diff --git a/app/build.gradle b/app/build.gradle index 78fca85d20..29611feff2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -51,8 +51,7 @@ android { ndk { // 如果不添加 `arm64` 调用系统的 PackageManager 的方法读取安装包信息的时候会出现 native 层闪退,草 - // 微博 SDK 没有 64位的 SO,添加了 arm64 又会无法使用微博登录,下个版本更新微博 SDK 刻不容缓了! - abiFilters "armeabi-v7a", "x86" + abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86" } renderscriptTargetApi 18 @@ -348,6 +347,10 @@ dependencies { implementation "com.aliyun.openservices:aliyun-log-android-sdk:${aliyunLog}" implementation "com.github.princekin-f:EasyFloat:${easyFloat}" + implementation "io.github.florent37:shapeofview:$shapeOfView" + + implementation 'io.github.sinaweibosdk:core:11.6.0@aar' + implementation project(':libraries:LGLibrary') // implementation project(':libraries:MTA') implementation project(':libraries:QQShare') diff --git a/app/libs/sina-weibo-2.0.3.aar b/app/libs/sina-weibo-2.0.3.aar deleted file mode 100644 index 3b5d737637..0000000000 Binary files a/app/libs/sina-weibo-2.0.3.aar and /dev/null differ diff --git a/app/proguard-rules.txt b/app/proguard-rules.txt index 02a39fdf44..5dbda15ef8 100644 --- a/app/proguard-rules.txt +++ b/app/proguard-rules.txt @@ -51,7 +51,7 @@ } ### weiboSdk --keep class com.sina.weibo.sdk.* { *; } +-keep class com.sina.weibo.sdk.** { *; } -dontwarn android.webkit.WebView -dontwarn android.webkit.WebViewClient diff --git a/app/src/main/java/com/gh/base/BaseRichEditorViewModel.kt b/app/src/main/java/com/gh/base/BaseRichEditorViewModel.kt index 7a1b1c9e7d..6ffbf5d545 100644 --- a/app/src/main/java/com/gh/base/BaseRichEditorViewModel.kt +++ b/app/src/main/java/com/gh/base/BaseRichEditorViewModel.kt @@ -75,7 +75,10 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo if (File(picturePath).length() > ImageUtils.getUploadFileMaxSize()) { val count = ImageUtils.getUploadFileMaxSize() / 1024 / 1024 val application: Application = getApplication() - Utils.toast(getApplication(), application.getString(R.string.pic_max_hint, count)) + Utils.toast( + getApplication(), + application.getString(R.string.pic_max_hint, count) + ) continue } Utils.log("picturePath = $picturePath") @@ -85,88 +88,110 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo } } if (pictureList.size == 0) return + val imageType = when (getRichType()) { + RichType.ARTICLE -> UploadImageUtils.UploadType.community_article + RichType.QUESTION -> UploadImageUtils.UploadType.question + else -> UploadImageUtils.UploadType.poster + } + uploadImageSubscription = UploadImageUtils.compressAndUploadImageList( + imageType, + pictureList, + false, + object : UploadImageUtils.OnUploadImageListListener { + override fun onProgress(total: Long, progress: Long) {} - uploadImageSubscription = UploadImageUtils.compressAndUploadImageList(UploadImageUtils.UploadType.answer, pictureList - , false, object : UploadImageUtils.OnUploadImageListListener { - override fun onProgress(total: Long, progress: Long) {} - - override fun onCompressSuccess(imageUrls: List) { - val chooseImageMd5Map = LinkedHashMap() - imageUrls.forEach { - chooseImageMd5Map[MD5Utils.getUrlMD5(it)] = "" - } - uploadingImage.add(chooseImageMd5Map) - chooseImagesUpload.postValue(chooseImageMd5Map) - } - - override fun onSingleSuccess(imageUrl: Map) { - val map = LinkedHashMap() - for (key in imageUrl.keys) { - map[MD5Utils.getUrlMD5(key)] = FILE_HOST + key.decodeURI() - mapImages[TextUtils.htmlEncode(key).decodeURI()] = imageUrl[key] ?: "" - } - chooseImagesUploadSuccess.postValue(map) - } - - override fun onSuccess(imageUrl: LinkedHashMap, errorMap: Map) { - val uploadMap = uploadingImage.find { it.containsKey(MD5Utils.getUrlMD5(imageUrl.entries.iterator().next().key)) } - uploadMap?.let { - uploadingImage.remove(uploadMap) - } - - val errorSize = pictureList.size - imageUrl.size - if (errorSize > 0) { - val map = LinkedHashMap() - for (key in errorMap.keys) { - map[MD5Utils.getUrlMD5(key)] = "" + override fun onCompressSuccess(imageUrls: List) { + val chooseImageMd5Map = LinkedHashMap() + imageUrls.forEach { + chooseImageMd5Map[MD5Utils.getUrlMD5(it)] = "" + } + uploadingImage.add(chooseImageMd5Map) + chooseImagesUpload.postValue(chooseImageMd5Map) + } + + override fun onSingleSuccess(imageUrl: Map) { + val map = LinkedHashMap() + for (key in imageUrl.keys) { + map[MD5Utils.getUrlMD5(key)] = FILE_HOST + key.decodeURI() + mapImages[TextUtils.htmlEncode(key).decodeURI()] = imageUrl[key] ?: "" } - //value为空会删除PlaceholderImage chooseImagesUploadSuccess.postValue(map) + } + + override fun onSuccess( + imageUrl: LinkedHashMap, + errorMap: Map + ) { + val uploadMap = uploadingImage.find { + it.containsKey( + MD5Utils.getUrlMD5( + imageUrl.entries.iterator().next().key + ) + ) + } + uploadMap?.let { + uploadingImage.remove(uploadMap) + } + + val errorSize = pictureList.size - imageUrl.size + if (errorSize > 0) { + val map = LinkedHashMap() + for (key in errorMap.keys) { + map[MD5Utils.getUrlMD5(key)] = "" + } + //value为空会删除PlaceholderImage + chooseImagesUploadSuccess.postValue(map) + + for (error in errorMap.values) { + if (error is HttpException && error.code() == 403) { + Utils.toast(getApplication(), errorSize.toString() + "张违规图片上传失败") + return + } + } + Utils.toast(getApplication(), errorSize.toString() + "张图片上传失败") + } + } + + override fun onError(errorMap: Map) { + val errorSize = pictureList.size + if (errorSize > 0) { + val map = LinkedHashMap() + for (key in errorMap.keys) { + map[MD5Utils.getUrlMD5(key)] = "" + } + //value为空会删除PlaceholderImage + chooseImagesUploadSuccess.postValue(map) + } for (error in errorMap.values) { if (error is HttpException && error.code() == 403) { - Utils.toast(getApplication(), errorSize.toString() + "张违规图片上传失败") + val e = error.response()?.errorBody()?.string()?.toObject() + if (e != null && e.code == 403017) { + Utils.toast( + getApplication(), + errorSize.toString() + "张图片的宽或高超过限制,请裁剪后上传" + ) + } else { + Utils.toast(getApplication(), errorSize.toString() + "张违规图片上传失败") + } return } } - Utils.toast(getApplication(), errorSize.toString() + "张图片上传失败") - } - } - - override fun onError(errorMap: Map) { - val errorSize = pictureList.size - if (errorSize > 0) { - val map = LinkedHashMap() - for (key in errorMap.keys) { - map[MD5Utils.getUrlMD5(key)] = "" - } - //value为空会删除PlaceholderImage - chooseImagesUploadSuccess.postValue(map) - } - - for (error in errorMap.values) { - if (error is HttpException && error.code() == 403) { - val e = error.response()?.errorBody()?.string()?.toObject() - if (e != null && e.code == 403017) { - Utils.toast(getApplication(), errorSize.toString() + "张图片的宽或高超过限制,请裁剪后上传") - } else { - Utils.toast(getApplication(), errorSize.toString() + "张违规图片上传失败") - } - return + if (errorSize == 1) { + Utils.toast(getApplication(), "图片上传失败") + } else { + Utils.toast(getApplication(), errorSize.toString() + "张图片上传失败") } } - if (errorSize == 1) { - Utils.toast(getApplication(), "图片上传失败") - } else { - Utils.toast(getApplication(), errorSize.toString() + "张图片上传失败") - } - } - }) + }) } fun uploadPoster(picturePath: String) { processDialog.postValue(WaitingDialogFragment.WaitingDialogData("封面上传中...", true)) - uploadImageSubscription = UploadImageUtils.compressAndUploadImage(UploadImageUtils.UploadType.poster, picturePath, false, + uploadImageSubscription = + UploadImageUtils.compressAndUploadImage(UploadImageUtils.UploadType.poster, + picturePath, + false, object : UploadImageUtils.OnUploadImageListener { override fun onSuccess(imageUrl: String) { patchVideoPoster(imageUrl) @@ -186,19 +211,19 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo if (id.isEmpty() || videoId.isEmpty()) return val map = hashMapOf("poster" to poster, "type" to getVideoType()) mApi.patchInsertVideo(videoId, map.toRequestBody()) - .compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - mUploadVideoListener?.changePoster(id, poster) - handleUploadPosterResult(false) - } + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + mUploadVideoListener?.changePoster(id, poster) + handleUploadPosterResult(false) + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - handleUploadPosterResult(true) - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + handleUploadPosterResult(true) + } + }) } private fun handleUploadPosterResult(isFailure: Boolean = false) { @@ -237,8 +262,13 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo if (localVideoList.isEmpty()) return currentUploadingVideo = localVideoList[0] UploadManager.createUploadTask(currentUploadingVideo?.filePath - ?: "", object : OnUploadListener { - override fun onProgressChanged(uploadFilePath: String, currentSize: Long, totalSize: Long, speed: Long) { + ?: "", object : OnUploadListener { + override fun onProgressChanged( + uploadFilePath: String, + currentSize: Long, + totalSize: Long, + speed: Long + ) { runOnUiThread { val percent = (currentSize * 100 / totalSize.toFloat()).roundTo(1) currentUploadingVideo?.id?.let { @@ -260,9 +290,13 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo } private fun postVideoPosterAndInfo(uploadFilePath: String, url: String) { - val localVideoPoster = getApplication().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".jpg" + val localVideoPoster = + getApplication().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".jpg" try { - val bmp = ThumbnailUtils.createVideoThumbnail(uploadFilePath, MediaStore.Images.Thumbnails.MINI_KIND) + val bmp = ThumbnailUtils.createVideoThumbnail( + uploadFilePath, + MediaStore.Images.Thumbnails.MINI_KIND + ) // bmp 可能为空 FileOutputStream(localVideoPoster).use { out -> bmp?.compress(Bitmap.CompressFormat.PNG, 100, out) @@ -273,7 +307,10 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo uploadVideoFailure() return } - uploadImageSubscription = UploadImageUtils.compressAndUploadImage(UploadImageUtils.UploadType.poster, localVideoPoster, false, + uploadImageSubscription = + UploadImageUtils.compressAndUploadImage(UploadImageUtils.UploadType.poster, + localVideoPoster, + false, object : UploadImageUtils.OnUploadImageListener { override fun onSuccess(imageUrl: String) { postVideoInfo(url, imageUrl) @@ -300,20 +337,20 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo } val requestBody = map.toRequestBody() mApi.insertVideo(requestBody) - .compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: JsonObject?) { - super.onResponse(response) - if (response != null) { - uploadVideoSuccess(poster, url, response) - } + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: JsonObject?) { + super.onResponse(response) + if (response != null) { + uploadVideoSuccess(poster, url, response) } + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - uploadVideoFailure() - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + uploadVideoFailure() + } + }) } private fun uploadVideoSuccess(poster: String, url: String, data: JsonObject) { diff --git a/app/src/main/java/com/gh/base/BaseSimpleDao.kt b/app/src/main/java/com/gh/base/BaseSimpleDao.kt new file mode 100644 index 0000000000..147c777753 --- /dev/null +++ b/app/src/main/java/com/gh/base/BaseSimpleDao.kt @@ -0,0 +1,93 @@ +package com.gh.base + +import android.content.Context +import android.content.SharedPreferences +import com.gh.common.util.SPUtils +import com.halo.assistant.HaloApp + +/** + * 用 SP 实现的简单列表持久化结构 + */ +abstract class BaseSimpleDao { + + // 使用独有的 SP 文件 + private val mSp: SharedPreferences by lazy { + HaloApp.getInstance().application.getSharedPreferences("SimpleDao", Context.MODE_PRIVATE) + } + + fun add(key: String) { + val originString = SPUtils.getString(mSp, getSPKey()) + + if (originString.isEmpty()) { + // Insert keyword only for the very first time. + SPUtils.setString(mSp, getSPKey(), key) + } else { + getAll()?.let { + if (getMaxSize() != -1 && it.size > getMaxSize()) { + it.removeAt(it.size - 1) + } + + // Move keyword to the very front if it exists. + if (it.contains(key)) { + it.remove(key) + } + it.add(0, key) + val builder = StringBuilder() + for ((index, k) in it.withIndex()) { + builder.append(k) + if (index != it.size - 1) { + builder.append(DIVIDER_KEY) + } + } + SPUtils.setString(mSp, getSPKey(), builder.toString()) + } + } + } + + fun delete(key: String) { + val originString = SPUtils.getString(mSp, getSPKey()) + + if (originString.isEmpty()) { + // do nothing + } else { + getAll()?.let { + if (it.contains(key)) { + it.remove(key) + } + val builder = StringBuilder() + for ((index, k) in it.withIndex()) { + builder.append(k) + if (index != it.size - 1) { + builder.append(DIVIDER_KEY) + } + } + SPUtils.setString(mSp, getSPKey(), builder.toString()) + } + } + } + + fun getAll(): ArrayList? { + val list = SPUtils.getString(mSp, getSPKey()).split(DIVIDER_KEY) + + return if (list.size == 1 && list[0].isEmpty()) null else ArrayList(list) + } + + fun getRawString(): String = SPUtils.getString(mSp, getSPKey()) + + fun contains(key: String): Boolean { + return getAll()?.contains(key) == true + } + + fun deleteAll() { + SPUtils.setString(mSp, getSPKey(), "") + } + + open fun getMaxSize(): Int = -1 + + abstract fun getSPKey(): String + + companion object { + private const val DIVIDER_KEY = "<-||->" + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/base/GlobalActivityLifecycleObserver.kt b/app/src/main/java/com/gh/base/GlobalActivityLifecycleObserver.kt index 35821516ea..e8b64d845f 100644 --- a/app/src/main/java/com/gh/base/GlobalActivityLifecycleObserver.kt +++ b/app/src/main/java/com/gh/base/GlobalActivityLifecycleObserver.kt @@ -7,9 +7,14 @@ import com.gh.common.notifier.Notifier import com.gh.common.util.DataUtils import com.gh.common.util.FloatingBackViewManager import com.gh.download.DownloadManager -import com.gh.gamecenter.SingletonWebActivity +import com.gh.gamecenter.MainActivity import com.gh.gamecenter.SplashScreenActivity import com.gh.gamecenter.energy.EnergyCenterActivity +import com.gh.gamecenter.forum.detail.ForumDetailActivity +import com.gh.gamecenter.forum.list.ForumListActivity +import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity +import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity +import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity import com.halo.assistant.HaloApp import com.lightgame.utils.AppManager @@ -29,12 +34,12 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks { // 判断是否需要显示或隐藏返回小浮窗 if (FloatingBackViewManager.getType().isNotEmpty()) { if (activity is EnergyCenterActivity - && FloatingBackViewManager.getType() == FloatingBackViewManager.TYPE_TASK) { + && FloatingBackViewManager.getType() == FloatingBackViewManager.TYPE_TASK + ) { FloatingBackViewManager.disableBackView() - } else if (activity is SingletonWebActivity - && FloatingBackViewManager.getType() == FloatingBackViewManager.TYPE_ACTIVITY - // TODO 再加上一个内容匹配? - ) { + } else if (!shouldShowActivityBackView(activity) + && FloatingBackViewManager.getType() == FloatingBackViewManager.TYPE_ACTIVITY + ) { FloatingBackViewManager.disableBackView() } else { FloatingBackViewManager.showBackView(activity) @@ -55,6 +60,15 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks { } } + private fun shouldShowActivityBackView(activity: Activity): Boolean { + return (activity is MainActivity + || activity is ArticleDetailActivity + || activity is ForumVideoDetailActivity + || activity is ForumDetailActivity + || activity is ForumListActivity + || activity is NewQuestionDetailActivity) + } + override fun onActivityPaused(activity: Activity) { CurrentActivityHolder.activitySet.remove(activity) FloatingBackViewManager.dismissBackView(activity) @@ -78,5 +92,4 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks { } } - } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/DefaultJsApi.kt b/app/src/main/java/com/gh/common/DefaultJsApi.kt index 071486612a..fde3ca10d4 100644 --- a/app/src/main/java/com/gh/common/DefaultJsApi.kt +++ b/app/src/main/java/com/gh/common/DefaultJsApi.kt @@ -45,6 +45,8 @@ import kotlin.collections.ArrayList class DefaultJsApi(var context: Context) { + private var mLoginHandler: CompletionHandler? = null + @JavascriptInterface fun isGhzs(msg: Any): String { return "true" @@ -106,7 +108,7 @@ class DefaultJsApi(var context: Context) { @JavascriptInterface fun getAppVersionCode(msg: Any): Int { - return PackageUtils.getVersionCode() + return PackageUtils.getGhVersionCode() } @JavascriptInterface @@ -374,6 +376,22 @@ class DefaultJsApi(var context: Context) { } } + @JavascriptInterface + fun loginWithCallback(msg: Any, handler: CompletionHandler) { + mLoginHandler = handler + login(msg) + } + + fun onLogin() { + mLoginHandler?.complete(true) + mLoginHandler = null + } + + @JavascriptInterface + fun openInNewFullWebview(url: Any) { + runOnUiThread { DirectUtils.directToFullScreenWebPage(context, url.toString(), true) } + } + @Keep internal data class ImageEvent(var imageList: ArrayList = arrayListOf(), var position: Int = 0) diff --git a/app/src/main/java/com/gh/common/DefaultUrlHandler.kt b/app/src/main/java/com/gh/common/DefaultUrlHandler.kt index f18cac805d..f2e3d8741b 100644 --- a/app/src/main/java/com/gh/common/DefaultUrlHandler.kt +++ b/app/src/main/java/com/gh/common/DefaultUrlHandler.kt @@ -14,7 +14,6 @@ import com.gh.common.util.DirectUtils.directToGameVideo import com.gh.common.util.DirectUtils.directToLegacyVideoDetail import com.gh.common.util.DirectUtils.directToLinkPage import com.gh.common.util.DirectUtils.directToQa -import com.gh.common.util.DirectUtils.directToVideoDetail import com.gh.common.util.GsonUtils.gson import com.gh.gamecenter.* import com.gh.gamecenter.entity.* @@ -161,9 +160,12 @@ object DefaultUrlHandler { } directToLegacyVideoDetail(context, id, location, false, gameId, entrance, "", referer, type, act, paginationType, fieldId, sectionName) } + EntranceUtils.HOST_VIDEO_DETAIL -> { + DirectUtils.directToVideoDetail(context, id, entrance, path) + } EntranceUtils.HOST_VIDEO_SINGLE -> { val referer = uri.getQueryParameter("referer") ?: "" - directToVideoDetail(context, id, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.value, + DirectUtils.directToVideoDetail(context, id, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.value, false, "", entrance, "", if (TextUtils.isEmpty(referer)) "" else referer) } EntranceUtils.HOST_VIDEO_STREAMING_HOME -> { @@ -294,6 +296,7 @@ object DefaultUrlHandler { val forumName = uri.getQueryParameter("forum_name") ?: "" val forumId = uri.getQueryParameter("forum_id") ?: "" val forumIcon = uri.getQueryParameter("forum_icon") ?: "" + val forumType = uri.getQueryParameter("forum_type") ?: BbsType.OFFICIAL_BBS.value val activityLabelEntity = ActivityLabelEntity(id = activityId, name = activityName) val communityEntity = CommunityEntity(id = forumId, name = forumName, icon = forumIcon) @@ -302,7 +305,7 @@ object DefaultUrlHandler { context, communityEntity, activityLabelEntity, - BbsType.GAME_BBS.value, + forumType, false, entrance, "" @@ -463,10 +466,11 @@ object DefaultUrlHandler { val name = uri.getQueryParameter("communityName") ?: "" DirectUtils.directToCommunityColumn(context, CommunityEntity(id, name), columnsId, entrance, "") } - contains("zone") -> { + contains("zone") && split("/").size > 2 -> { val gameId = split("/")[2] DirectUtils.directGameZone(context, gameId, url, entrance) } + else -> return false } } return true diff --git a/app/src/main/java/com/gh/common/constant/Config.java b/app/src/main/java/com/gh/common/constant/Config.java index 39b990b3f5..8069568eb7 100644 --- a/app/src/main/java/com/gh/common/constant/Config.java +++ b/app/src/main/java/com/gh/common/constant/Config.java @@ -1,5 +1,6 @@ package com.gh.common.constant; +import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.os.Build; @@ -12,6 +13,7 @@ import com.gh.common.util.PackageUtils; import com.gh.common.util.SPUtils; import com.gh.gamecenter.BuildConfig; import com.gh.gamecenter.SuggestionActivity; +import com.gh.gamecenter.entity.GameGuidePopupEntity; import com.gh.gamecenter.entity.NewSettingsEntity; import com.gh.gamecenter.entity.NewsEntity; import com.gh.gamecenter.entity.SettingsEntity; @@ -27,6 +29,7 @@ import org.greenrobot.eventbus.EventBus; import java.util.List; import androidx.annotation.Nullable; + import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; @@ -68,6 +71,7 @@ public class Config { private static SettingsEntity mSettingsEntity; private static NewSettingsEntity mNewSettingsEntity; + private static GameGuidePopupEntity mGameGuidePopupEntity; public static final String FIX_DOWNLOAD_KEY = "isFixDownload"; public static final String FIX_PLUGIN_KEY = "isFixPlugin"; @@ -225,6 +229,11 @@ public class Config { return mNewSettingsEntity; } + @Nullable + public static GameGuidePopupEntity getGameGuidePopupEntity() { + return mGameGuidePopupEntity; + } + private static boolean isExistDownloadFilter() { if (getSettings() == null || getSettings().getDownload() == null || getSettings().getDownload().size() == 0) { return false; @@ -277,10 +286,11 @@ public class Config { editor.apply(); } + @SuppressLint("CheckResult") public static void getGhzsSettings() { String channel = HaloApp.getInstance().getChannel(); RetrofitManager.getInstance(HaloApp.getInstance().getApplication()) - .getSensitiveApi().getSettings(PackageUtils.getVersionName(), channel) + .getSensitiveApi().getSettings(PackageUtils.getGhVersionName(), channel) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Response() { @@ -312,5 +322,16 @@ public class Config { SPUtils.setString(Constants.SP_NEW_SETTINGS, GsonUtils.toJson(data)); } }); + + RetrofitManager.getInstance(HaloApp.getInstance().getApplication()) + .getApi().getGameGuidePopup(Build.MANUFACTURER, Build.VERSION.RELEASE, Build.MODEL, channel, BuildConfig.VERSION_NAME) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new BiResponse() { + @Override + public void onSuccess(GameGuidePopupEntity data) { + mGameGuidePopupEntity = data; + } + }); } } diff --git a/app/src/main/java/com/gh/common/constant/Constants.java b/app/src/main/java/com/gh/common/constant/Constants.java index 51e028c783..18ca0d4dae 100644 --- a/app/src/main/java/com/gh/common/constant/Constants.java +++ b/app/src/main/java/com/gh/common/constant/Constants.java @@ -93,11 +93,11 @@ public class Constants { // 今天是否已经触发了 “通知管理” 引导弹窗 public static final String SP_IS_SHOWED_NOTIFICATION_TODAY = "show_is_notification_today"; // v4.0.0已废弃,标记安装的游戏为已玩过弹窗,最多取消2次 (https://gitlab.ghzs.com/pm/halo-app-issues/issues/722 调整为版本相关) (不是常量了也放这里好像有点奇怪) - public static final String SP_MARK_INSTALLED_GAME = "mark_installed_game" + PackageUtils.getVersionName(); + public static final String SP_MARK_INSTALLED_GAME = "mark_installed_game" + PackageUtils.getGhVersionName(); // 标记安装的游戏为已玩过弹窗(个人主页最多弹一次) - public static final String SP_MARK_INSTALLED_GAME_USER_HOME = "mark_installed_game_user_home" + PackageUtils.getVersionName(); + public static final String SP_MARK_INSTALLED_GAME_USER_HOME = "mark_installed_game_user_home" + PackageUtils.getGhVersionName(); // 标记安装的游戏为已玩过弹窗(我的游戏最多弹一次) - public static final String SP_MARK_INSTALLED_GAME_MY_GAME = "mark_installed_game_my_game" + PackageUtils.getVersionName(); + public static final String SP_MARK_INSTALLED_GAME_MY_GAME = "mark_installed_game_my_game" + PackageUtils.getGhVersionName(); //视频详情滑动引导 public static final String SP_SHOW_SLIDE_GUIDE = "show_slide_guide"; //视频详情点击引导 @@ -161,6 +161,8 @@ public class Constants { public static final String SP_SHOULD_SHOW_GAMEDETAIL_USE_BROWSER_TO_INSTALL_HINT = "should_show_gamedetail_use_browser_to_install_hint"; // 第一次普通安装推荐使用浏览器安装提示 public static final String SP_SHOULD_SHOW_USE_BROWSER_TO_INSTALL_HINT = "should_show_use_browser_to_install_hint"; + // 游戏详情切换安装方式显示开关 + public static final String SP_SWITCH_INSTALL_VISIBLE = "sp_switch_install_visible"; //模拟器管理引导 public static final String SP_SIMULATOR_GUIDE = "simulator_guide"; @@ -217,6 +219,9 @@ public class Constants { public static final String SP_COMMUNITY_HOME_VIDEO_GUIDE = "community_home_video_guide"; // 论坛详情申请版主引导 public static final String SP_FORUM_DETAIL_MODERATOR_GUIDE = "forum_detail_moderator_guide"; + // 游戏详情安装引导 + public static final String SP_GAME_DETAIL_INSTALL_GUIDE = "game_detail_install_guide"; + public static final String SP_SHOULD_SHOW_GAME_DETAIL_INSTALL_GUIDE = "should_show_game_detail_install_guide"; //手机号码匹配规则 public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$"; @@ -347,7 +352,7 @@ public class Constants { //已收录包名更新 cd间隔 public static final int PACKAGES_CD = 60 * 1000; - public static final String[] REPORT_LIST = new String[]{"垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息", "违法有害信息", "其它"}; + public static final String[] REPORT_LIST = new String[]{"垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息", "违法有害信息", "其他原因"}; public static final String ENTRANCE_UNKNOWN = "(unknown)"; diff --git a/app/src/main/java/com/gh/common/databind/BindingAdapters.java b/app/src/main/java/com/gh/common/databind/BindingAdapters.java index 72d4fc7b10..d7fa0f91dc 100644 --- a/app/src/main/java/com/gh/common/databind/BindingAdapters.java +++ b/app/src/main/java/com/gh/common/databind/BindingAdapters.java @@ -760,17 +760,29 @@ public class BindingAdapters { if (test != null // 这个判断用于开测表列表 && !"type_tag".equals(test.getGameTag())) { - TagStyleEntity typeTag = new TagStyleEntity(); - typeTag.setName(test.getType() != null ? test.getType() : ""); - typeTag.setBackground("FFF3E0"); - typeTag.setColor("FA8500"); - tagStyle.add(typeTag); + if ("custom".equals(test.getGameTag())) { + TagStyleEntity typeTag = new TagStyleEntity(); + if (!TextUtils.isEmpty(test.getText())) { + typeTag.setName(test.getText() != null ? test.getText() : ""); + } else { + typeTag.setName(test.getType() != null ? test.getType() : ""); + } + typeTag.setBackground("E8F3FF"); + typeTag.setColor("1383EB"); + tagStyle.add(typeTag); + } else { + 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); + TagStyleEntity timeTag = new TagStyleEntity(); + timeTag.setName(GameViewUtils.getGameTestDate(test.getStart())); + timeTag.setBackground("E0FFF9"); + timeTag.setColor("00A887"); + tagStyle.add(timeTag); + } } else { tagStyle = gameEntity.getTagStyle(); } diff --git a/app/src/main/java/com/gh/common/dialog/ApplyModeratorDialogFragment.kt b/app/src/main/java/com/gh/common/dialog/ApplyModeratorDialogFragment.kt index 7d617e9454..2a21aff188 100644 --- a/app/src/main/java/com/gh/common/dialog/ApplyModeratorDialogFragment.kt +++ b/app/src/main/java/com/gh/common/dialog/ApplyModeratorDialogFragment.kt @@ -1,6 +1,5 @@ package com.gh.common.dialog -import android.graphics.Paint import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -9,12 +8,17 @@ import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.FragmentTransaction import com.gh.base.fragment.BaseDialogFragment import com.gh.common.util.DirectUtils +import com.gh.common.util.SpanBuilder import com.gh.common.util.dip2px +import com.gh.common.view.CustomLinkMovementMethod +import com.gh.gamecenter.R import com.gh.gamecenter.databinding.DialogApplyModeratorBinding + class ApplyModeratorDialogFragment : BaseDialogFragment() { private lateinit var binding: DialogApplyModeratorBinding private var groupNumber = "" + private var groupKey = "" private var mCallBack: (() -> Unit)? = null override fun onCreateView( @@ -28,14 +32,17 @@ class ApplyModeratorDialogFragment : BaseDialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.groupTv.text = groupNumber - binding.groupTv.paint.flags = Paint.UNDERLINE_TEXT_FLAG - binding.groupTv.setOnClickListener { - DirectUtils.directToQqGroup( - requireContext(), - binding.groupTv.text.toString() - ) - } + val startText = "版主考核群:" + val text = "$startText$groupNumber\n感谢你对论坛建设的支持\n请加入版主考核群并联系群主进行版主资格考核" + binding.desTv.text = SpanBuilder(text) + .click(startText.length, startText.length + groupNumber.length, R.color.theme_font,true) { + DirectUtils.directToQqGroup( + requireContext(), + groupKey + ) + } + .build() + binding.desTv.movementMethod = CustomLinkMovementMethod.getInstance() binding.confirmTv.setOnClickListener { dismissAllowingStateLoss() mCallBack?.invoke() @@ -51,11 +58,17 @@ class ApplyModeratorDialogFragment : BaseDialogFragment() { companion object { @JvmStatic - fun show(activity: AppCompatActivity, number: String, callBack: (() -> Unit)?) { + fun show( + activity: AppCompatActivity, + number: String, + key: String, + callBack: (() -> Unit)? + ) { var dialogFragment = activity.supportFragmentManager.findFragmentByTag(ApplyModeratorDialogFragment::class.java.simpleName) as? ApplyModeratorDialogFragment if (dialogFragment != null) { dialogFragment.groupNumber = number + dialogFragment.groupKey = key dialogFragment.mCallBack = callBack val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction() @@ -64,6 +77,7 @@ class ApplyModeratorDialogFragment : BaseDialogFragment() { } else { dialogFragment = ApplyModeratorDialogFragment().apply { groupNumber = number + groupKey = key mCallBack = callBack } dialogFragment.show( diff --git a/app/src/main/java/com/gh/common/exposure/ExposureUtils.kt b/app/src/main/java/com/gh/common/exposure/ExposureUtils.kt index 37042e04f6..c147810094 100644 --- a/app/src/main/java/com/gh/common/exposure/ExposureUtils.kt +++ b/app/src/main/java/com/gh/common/exposure/ExposureUtils.kt @@ -76,7 +76,7 @@ object ExposureUtils { if (PackageUtils.isCanUpdate(apkEntity, gameId)) { DownloadType.PLUGIN_UPDATE } else { - if (Version(apkEntity.version).isHigherThan(PackageUtils.getVersionByPackage(apkEntity.packageName))) { + if (Version(apkEntity.version).isHigherThan(PackageUtils.getVersionNameByPackageName(apkEntity.packageName))) { DownloadType.UPDATE } else { DownloadType.DOWNLOAD diff --git a/app/src/main/java/com/gh/common/filter/RegionSettingHelper.kt b/app/src/main/java/com/gh/common/filter/RegionSettingHelper.kt index 726c7945e3..3e85b88ace 100644 --- a/app/src/main/java/com/gh/common/filter/RegionSettingHelper.kt +++ b/app/src/main/java/com/gh/common/filter/RegionSettingHelper.kt @@ -11,7 +11,6 @@ import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.retrofit.BiResponse import com.gh.gamecenter.retrofit.RetrofitManager import com.halo.assistant.HaloApp -import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.functions.Function import io.reactivex.schedulers.Schedulers @@ -62,13 +61,12 @@ object RegionSettingHelper { @SuppressLint("CheckResult") @JvmStatic fun getRegionSetting() { - debounceActionWithInterval(R.string.app_name, 3000) { + debounceActionWithInterval(R.string.app_name, 5000) { // 使用默认的 Schdulers.io() 可能会触发 OOM RetrofitManager.getInstance(HaloApp.getInstance().application) .sensitiveApi .getRegionSetting(HaloApp.getInstance().channel) .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : BiResponse() { override fun onSuccess(data: RegionSetting) { updateSettingsInMemory(data) diff --git a/app/src/main/java/com/gh/common/loghub/LoghubHelper.kt b/app/src/main/java/com/gh/common/loghub/LoghubHelper.kt index 708965bdbd..bc3895ddd4 100644 --- a/app/src/main/java/com/gh/common/loghub/LoghubHelper.kt +++ b/app/src/main/java/com/gh/common/loghub/LoghubHelper.kt @@ -41,7 +41,7 @@ object LoghubHelper { // 每次发送前会把日志保存到本地的binlog文件,只有发送成功才会删除,保证日志上传At Least Once setPersistent(1) // 持久化的文件名,需要保证文件所在的文件夹已创建。配置多个客户端时,不应设置相同文件 - setPersistentFilePath(HaloApp.getInstance().application.filesDir.absolutePath + "/log.dat") + setPersistentFilePath(HaloApp.getInstance().application.filesDir.absolutePath + "/${logStore}.dat") // 是否每次AddLog强制刷新,高可靠性场景建议打开 setPersistentForceFlush(1) // 持久化文件滚动个数,建议设置成10。 diff --git a/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt b/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt index fd02bf3931..778826c6e9 100644 --- a/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt +++ b/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt @@ -112,7 +112,7 @@ class SimulatorDownloadManager private constructor() { return } val isInstalled = PackageUtils.isInstalledFromAllPackage(context, simulator?.apk?.packageName) - val versionFromInstalledApp = PackageUtils.getVersionByPackage(simulator?.apk?.packageName) + val versionFromInstalledApp = PackageUtils.getVersionNameByPackageName(simulator?.apk?.packageName) val shouldShowUpdate = Version(simulator?.apk?.version).isHigherThan(versionFromInstalledApp) val title = if (shouldShowUpdate && isInstalled) "更新模拟器" else "安装模拟器" val message = if (shouldShowUpdate && isInstalled) "检测到模拟器存在更高版本,是否前往更新" else "模拟器游戏需要先下载安装对应的模拟器,才可以运行" diff --git a/app/src/main/java/com/gh/common/simulator/SimulatorGameManager.kt b/app/src/main/java/com/gh/common/simulator/SimulatorGameManager.kt index 4212156931..0bd81702a8 100644 --- a/app/src/main/java/com/gh/common/simulator/SimulatorGameManager.kt +++ b/app/src/main/java/com/gh/common/simulator/SimulatorGameManager.kt @@ -15,6 +15,7 @@ import com.gh.gamecenter.entity.SimulatorGameRecordEntity import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.retrofit.BiResponse import com.gh.gamecenter.retrofit.EmptyResponse +import com.gh.gamecenter.retrofit.Response import com.gh.gamecenter.retrofit.RetrofitManager import com.gh.gamecenter.room.AppDatabase import com.halo.assistant.HaloApp @@ -84,8 +85,10 @@ object SimulatorGameManager { @JvmStatic fun launchSimulatorGame(downloadEntity: DownloadEntity, gameEntity: GameEntity) { - val versionFromInstalledApp = PackageUtils.getVersionByPackage(gameEntity.simulator?.apk?.packageName) + val versionFromInstalledApp = PackageUtils.getVersionNameByPackageName(gameEntity.simulator?.apk?.packageName) val shouldShowUpdate = Version(gameEntity.simulator?.apk?.version).isHigherThan(versionFromInstalledApp) + + updateSimulatorConfigFile(gameId = gameEntity.id) if (shouldShowUpdate) { SimulatorDownloadManager.getInstance().showDownloadDialog(AppManager.getInstance().recentActiveActivity, gameEntity.simulator, SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.id, gameEntity.name @@ -305,4 +308,22 @@ object SimulatorGameManager { .observeOn(AndroidSchedulers.mainThread()) .subscribe(EmptyResponse()) } + + private fun updateSimulatorConfigFile(gameId: String) { + RetrofitManager.getInstance(HaloApp.getInstance().application) + .api + .getGameDigest(gameId) + .map(ApkActiveUtils.filterMapper) + .subscribeOn(Schedulers.io()) + .subscribe(object : Response() { + override fun onResponse(game: GameEntity?) { + game?.let { + if (!TextUtils.isEmpty(game.simulatorGameConfig)) { + val configFilePath = getPathByType(game.simulatorType + "/cheat/" + game.getApk().firstOrNull()?.packageName + ".ini") + FileUtils.downloadAndUpdateFile(game.simulatorGameConfig, configFilePath) + } + } + } + }) + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/tracker/TrackerLogger.kt b/app/src/main/java/com/gh/common/tracker/TrackerLogger.kt index 2930f8dfb2..dcd82cb877 100644 --- a/app/src/main/java/com/gh/common/tracker/TrackerLogger.kt +++ b/app/src/main/java/com/gh/common/tracker/TrackerLogger.kt @@ -120,6 +120,7 @@ object TrackerLogger { val jsonObject = JSONObject() val payloadObject = JSONObject() val signatureHash = PackageUtils.getApkSignatureByPackageName(context, context.packageName) + val sideLoadInfo = PackageUtils.getSideLoadedInfo() tryCatchInRelease { payloadObject.put("launch_id", Tracker.launchId) @@ -128,6 +129,13 @@ object TrackerLogger { payloadObject.put("package_name", context.packageName) payloadObject.put("app_name", context.getString(R.string.app_name)) + sideLoadInfo?.let { + payloadObject.put("is_side_loaded", sideLoadInfo["is_side_loaded"]) + sideLoadInfo["installer_store"]?.let { + payloadObject.put("installer_store", it) + } + } + jsonObject.put("event", "app_launch") jsonObject.put("payload", payloadObject) jsonObject.put("meta", getMeta()) diff --git a/app/src/main/java/com/gh/common/util/AccessTokenKeeper.java b/app/src/main/java/com/gh/common/util/AccessTokenKeeper.java index 5a81cfbebf..e296f72462 100644 --- a/app/src/main/java/com/gh/common/util/AccessTokenKeeper.java +++ b/app/src/main/java/com/gh/common/util/AccessTokenKeeper.java @@ -2,6 +2,7 @@ package com.gh.common.util; import android.content.Context; import android.content.SharedPreferences; +import android.os.Bundle; import com.sina.weibo.sdk.auth.Oauth2AccessToken; @@ -13,6 +14,7 @@ public class AccessTokenKeeper { private static final String PREFERENCES_NAME = "com_weibo_sdk_android"; private static final String KEY_UID = "uid"; + private static final String KEY_USERNAME = "userName"; private static final String KEY_ACCESS_TOKEN = "access_token"; private static final String KEY_EXPIRES_IN = "expires_in"; private static final String KEY_REFRESH_TOKEN = "refresh_token"; @@ -28,13 +30,14 @@ public class AccessTokenKeeper { return; } - SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); + SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = pref.edit(); editor.putString(KEY_UID, token.getUid()); - editor.putString(KEY_ACCESS_TOKEN, token.getToken()); + editor.putString(KEY_USERNAME, token.getScreenName()); + editor.putString(KEY_ACCESS_TOKEN, token.getAccessToken()); editor.putString(KEY_REFRESH_TOKEN, token.getRefreshToken()); editor.putLong(KEY_EXPIRES_IN, token.getExpiresTime()); - editor.commit(); + editor.apply(); } /** @@ -48,14 +51,14 @@ public class AccessTokenKeeper { return null; } - Oauth2AccessToken token = new Oauth2AccessToken(); - SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); - token.setUid(pref.getString(KEY_UID, "")); - token.setToken(pref.getString(KEY_ACCESS_TOKEN, "")); - token.setRefreshToken(pref.getString(KEY_REFRESH_TOKEN, "")); - token.setExpiresTime(pref.getLong(KEY_EXPIRES_IN, 0)); - - return token; + SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE); + Bundle args = new Bundle(); + args.putString(KEY_UID, pref.getString(KEY_UID, "")); + args.putString(KEY_USERNAME, pref.getString(KEY_USERNAME, "")); + args.putString(KEY_ACCESS_TOKEN, pref.getString(KEY_ACCESS_TOKEN, "")); + args.putString(KEY_REFRESH_TOKEN, pref.getString(KEY_REFRESH_TOKEN, "")); + args.putLong(KEY_EXPIRES_IN, pref.getLong(KEY_EXPIRES_IN, 0)); + return Oauth2AccessToken.parseAccessToken(args); } /** @@ -68,9 +71,9 @@ public class AccessTokenKeeper { return; } - SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); + SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = pref.edit(); editor.clear(); - editor.commit(); + editor.apply(); } } diff --git a/app/src/main/java/com/gh/common/util/BbsReportHelper.kt b/app/src/main/java/com/gh/common/util/BbsReportHelper.kt index 7e03c524a4..633d258e7e 100644 --- a/app/src/main/java/com/gh/common/util/BbsReportHelper.kt +++ b/app/src/main/java/com/gh/common/util/BbsReportHelper.kt @@ -2,133 +2,124 @@ package com.gh.common.util import android.annotation.SuppressLint import android.app.Dialog -import android.content.Context -import android.graphics.Color -import android.graphics.drawable.ColorDrawable import android.preference.PreferenceManager +import android.text.TextUtils import android.view.LayoutInflater import android.view.View import android.view.Window -import android.widget.EditText -import android.widget.LinearLayout -import android.widget.TextView -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.content.ContextCompat +import androidx.core.widget.doOnTextChanged +import androidx.recyclerview.widget.LinearLayoutManager import com.gh.base.CurrentActivityHolder import com.gh.common.json.json -import com.gh.common.util.ToastUtils.showToast +import com.gh.common.view.VerticalItemDecoration import com.gh.gamecenter.R import com.gh.gamecenter.SuggestionActivity +import com.gh.gamecenter.adapter.ReportReasonAdapter +import com.gh.gamecenter.databinding.DialogReportReasonBinding import com.gh.gamecenter.entity.SettingsEntity import com.gh.gamecenter.retrofit.BiResponse import com.gh.gamecenter.retrofit.RetrofitManager import com.halo.assistant.HaloApp -import com.lightgame.utils.Util_System_Keyboard -import com.lightgame.utils.Utils import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.json.JSONObject +import retrofit2.HttpException object BbsReportHelper { fun showReportDialog(contentId: String) { val sp = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance()) - val suggestion: SettingsEntity.Suggestion? = sp.getString(SuggestionActivity.SUGGESTION_HINT_TYPE, null)?.toObject() + val suggestion: SettingsEntity.Suggestion? = + sp.getString(SuggestionActivity.SUGGESTION_HINT_TYPE, null)?.toObject() val reportList = suggestion?.report ?: return CurrentActivityHolder.getCurrentActivity()?.apply { if (this.isFinishing) return@apply - val dialog = Dialog(this) + val dialog = Dialog(this, R.style.DialogWindowTransparent) + val binding: DialogReportReasonBinding = + DialogReportReasonBinding.inflate(LayoutInflater.from(this)) + val reportReasonAdapter = ReportReasonAdapter( + this, reportList as ArrayList + ) { reason -> + if (reason == "其他原因") { + binding.reasonTitle.setText(R.string.report_reason_other_title) + binding.normalReasonContainer.visibility = View.GONE + binding.otherReasonContainer.visibility = View.VISIBLE + } else { + postReport(contentId, json { + "reason" to reason + }) + dialog.cancel() + } + } + binding.reasonRv.layoutManager = LinearLayoutManager(this) + binding.reasonRv.addItemDecoration( + VerticalItemDecoration( + this, + 1f, + false, + R.color.text_f5f5f5 + ) + ) + binding.reasonRv.adapter = reportReasonAdapter - val view = LayoutInflater.from(this).inflate(R.layout.dialog_video_complaint, null, false) - val complaintContainer = view.findViewById(R.id.complaintContainer) - val otherComplaintContainer: ConstraintLayout = view.findViewById(R.id.otherComplaintContainer) - val complaintCommentEt = view.findViewById(R.id.complaintCommentEt) - val backTv = view.findViewById(R.id.backTv) - val commitTv = view.findViewById(R.id.commitTv) - val finalContext: Context = this - //添加透明阴影,实现类似 clipPadding=false 效果 - complaintCommentEt.setShadowLayer(complaintCommentEt.extendedPaddingBottom.toFloat(), 0f, 0f, Color.TRANSPARENT) - - complaintCommentEt.setTextChangedListener { s: CharSequence, _: Int?, _: Int?, _: Int? -> - commitTv.setTextColor(ContextCompat.getColor(finalContext, if (s.toString().trim { it <= ' ' }.isEmpty()) R.color.text_999999 else R.color.theme_font)) + binding.negativeBtn.setOnClickListener { v -> + binding.reasonTitle.setText(R.string.report_reason_title) + binding.normalReasonContainer.visibility = View.VISIBLE + binding.otherReasonContainer.visibility = View.GONE } - for (option in reportList) { - val reportTv = TextView(this) - reportTv.text = option - reportTv.textSize = 16F - reportTv.setTextColor(R.color.title.toColor()) - reportTv.setBackgroundResource(R.drawable.textview_white_style) - reportTv.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.WRAP_CONTENT) - reportTv.setPadding(20F.dip2px(), 17F.dip2px(), 20F.dip2px(), 17F.dip2px()) - if (option.contains("其它")) { - val drawable = R.drawable.ic_complaint_arrow_right.toDrawable() - drawable!!.setBounds(0, 0, 6F.dip2px(), 10F.dip2px()) - reportTv.setCompoundDrawables(null, null, drawable, null) - } - complaintContainer.addView(reportTv) - reportTv.setOnClickListener { - if (option.contains("其它")) { - complaintContainer.visibility = View.GONE - otherComplaintContainer.visibility = View.VISIBLE - complaintCommentEt.requestFocus() - Util_System_Keyboard.showSoftKeyboard(finalContext, complaintCommentEt) - } else { - postReport(contentId, json { - "reason" to reportTv.text.toString() - }) - dialog.cancel() - } + binding.positiveBtn.setOnClickListener { v -> + if (TextUtils.isEmpty( + binding.otherReasonEt.text.toString().trim() + ) + ) { + ToastUtils.showToast("请填写举报原因") + } else { + postReport(contentId, json { + "reason" to "其它" + "description" to binding.otherReasonEt.text.toString() + }) + + dialog.cancel() } } - backTv.setOnClickListener { - Util_System_Keyboard.hideSoftKeyboard(finalContext, complaintCommentEt) - complaintContainer.visibility = View.VISIBLE - otherComplaintContainer.visibility = View.GONE - } - commitTv.setOnClickListener { - if (complaintCommentEt.text.toString().isEmpty()) { - showToast("请先输入说明~") - return@setOnClickListener + binding.otherReasonEt.doOnTextChanged { text, start, before, count -> + val tvCount: Int = text.toString().length + if (tvCount >= 500) { + binding.tvCount.setTextColor(R.color.text_FF4147.toColor()) } - postReport(contentId, json { - "reason" to "其它" - "description" to complaintCommentEt.text.toString() - }) - - dialog.cancel() + binding.tvCount.text = "$tvCount/500" } dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) - dialog.setContentView(view) + dialog.setContentView(binding.root) dialog.show() - val window = dialog.window - if (window != null) { - window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) - val params = window.attributes - params.width = resources.displayMetrics.widthPixels - 40F.dip2px() - window.attributes = params - } } } @SuppressLint("CheckResult") private fun postReport(contentId: String, reportContent: JSONObject) { RetrofitManager.getInstance(HaloApp.getInstance()) - .api - .postBbsReport(contentId, reportContent.toRequestBody()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : BiResponse() { - override fun onSuccess(data: ResponseBody) { - Utils.toast(HaloApp.getInstance(), "举报成功") + .api + .postBbsReport(contentId, reportContent.toRequestBody()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: ResponseBody) { + ToastUtils.toast("举报成功") + } + + override fun onFailure(exception: Exception) { + super.onFailure(exception) + if (exception is HttpException) { + ErrorHelper.handleError(HaloApp.getInstance().application, exception.response().errorBody()?.string()) } - }) + } + }) } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/BbsStayTimeHelper.kt b/app/src/main/java/com/gh/common/util/BbsStayTimeHelper.kt index 859d263f49..22ce7deafb 100644 --- a/app/src/main/java/com/gh/common/util/BbsStayTimeHelper.kt +++ b/app/src/main/java/com/gh/common/util/BbsStayTimeHelper.kt @@ -6,7 +6,6 @@ import android.app.Application import android.os.Bundle import com.gh.base.CurrentActivityHolder import com.gh.base.GHThreadFactory -import com.gh.common.runOnUiThread import com.gh.gamecenter.MainActivity import com.gh.gamecenter.forum.detail.ForumDetailActivity import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity @@ -37,13 +36,11 @@ object BbsStayTimeHelper { private val mActivityLifecycleCallbacks by lazy { object : Application.ActivityLifecycleCallbacks { - override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { - // do nothing - } - - override fun onActivityStarted(activity: Activity) { - // do nothing - } + override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {} + override fun onActivityStopped(activity: Activity) {} + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {} + override fun onActivityDestroyed(activity: Activity) {} + override fun onActivityStarted(activity: Activity) {} override fun onActivityResumed(activity: Activity) { if (isTopActivityBbsRelated(activity) && mIsStayTimeCountEnabled) { @@ -56,18 +53,6 @@ object BbsStayTimeHelper { pauseTimeCount() } } - - override fun onActivityStopped(activity: Activity) { - // do nothing - } - - override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { - // do nothing - } - - override fun onActivityDestroyed(activity: Activity) { - // do nothing - } } } @@ -101,19 +86,6 @@ object BbsStayTimeHelper { if (mStayTimeCount >= mStayTimeTimeout) { postExploreFinish() } - if (!isPublishEnv()) { - if (!isPublishEnv()) { - runOnUiThread { - ToastUtils.toast("论坛页面累计停留了 $mStayTimeCount 秒") - } - } - } - } - } else { - if (!isPublishEnv()) { - runOnUiThread { - ToastUtils.toast("当前页面不满足论坛任务条件(仅测试包有这个 toast 不要慌)") - } } } Thread.sleep(1000) @@ -146,7 +118,7 @@ object BbsStayTimeHelper { .subscribe(object : BiResponse() { override fun onSuccess(data: ResponseBody) { if (!isPublishEnv()) { - ToastUtils.toast("完成了论坛停留任务(仅测试包有这个 toast 不要慌)") + ToastUtils.toast("完成了论坛停留任务(仅测试环境有这个 toast 不要慌)") } disableStayTimeCount() } diff --git a/app/src/main/java/com/gh/common/util/CheckLoginUtils.java b/app/src/main/java/com/gh/common/util/CheckLoginUtils.java index 8c4f525fe2..92b9550043 100644 --- a/app/src/main/java/com/gh/common/util/CheckLoginUtils.java +++ b/app/src/main/java/com/gh/common/util/CheckLoginUtils.java @@ -1,9 +1,11 @@ package com.gh.common.util; +import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.text.TextUtils; +import com.gh.base.CurrentActivityHolder; import com.gh.common.constant.Constants; import com.gh.gamecenter.LoginActivity; import com.gh.gamecenter.manager.UserManager; @@ -16,14 +18,21 @@ import com.lightgame.utils.Utils; public class CheckLoginUtils { - public static void checkLogin(final Context context, String entrance, OnLoginListener listener) { + public static void checkLogin(Context context, String entrance, OnLoginListener listener) { if (!isLogin()) { if (listener != null) Utils.toast(context, "需要登录"); LogUtils.login("dialog", null, entrance); LogUtils.login("activity", null, entrance); if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) { - QuickLoginHelper.startLogin(context, entrance); + // 需要确保传入的 context 不为 application + if (!(context instanceof Activity)) { + context = CurrentActivityHolder.getCurrentActivity(); + } + + if (context != null) { + QuickLoginHelper.startLogin(context, entrance); + } } else { // 有可能App未启动 Bundle bundle = new Bundle(); diff --git a/app/src/main/java/com/gh/common/util/CommentHelper.kt b/app/src/main/java/com/gh/common/util/CommentHelper.kt index 317bbe7ed9..c8ea390bd2 100644 --- a/app/src/main/java/com/gh/common/util/CommentHelper.kt +++ b/app/src/main/java/com/gh/common/util/CommentHelper.kt @@ -5,6 +5,8 @@ import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout import android.widget.TextView +import com.gh.common.constant.Constants +import com.gh.common.json.json import com.gh.common.util.CommentUtils.copyText import com.gh.common.view.BugFixedPopupWindow import com.gh.gamecenter.CommentDetailActivity @@ -27,84 +29,110 @@ import retrofit2.HttpException object CommentHelper { @JvmStatic - fun showCommunityArticleCommentOptions(view: View, - commentEntity: CommentEntity, - showConversation: Boolean, - articleId: String, - communityId: String, - isShowTop: Boolean = false, - ignoreModerator: Boolean = false, - listener: OnCommentOptionClickListener?) { - showCommentOptions(view = view, - commentEntity = commentEntity, - showConversation = showConversation, - articleId = articleId, - communityId = communityId, - isShowTop = isShowTop, - ignoreModerator = ignoreModerator, - listener = listener) + fun showCommunityArticleCommentOptions( + view: View, + commentEntity: CommentEntity, + showConversation: Boolean, + articleId: String, + communityId: String, + isShowTop: Boolean = false, + ignoreModerator: Boolean = false, + listener: OnCommentOptionClickListener? + ) { + showCommentOptions( + view = view, + commentEntity = commentEntity, + showConversation = showConversation, + articleId = articleId, + communityId = communityId, + isShowTop = isShowTop, + ignoreModerator = ignoreModerator, + listener = listener + ) } @JvmStatic - fun showAnswerCommentOptions(view: View, - commentEntity: CommentEntity, - showConversation: Boolean, - answerId: String, - listener: OnCommentOptionClickListener?) { - showCommentOptions(view = view, - commentEntity = commentEntity, - showConversation = showConversation, - answerId = answerId, - listener = listener) + fun showAnswerCommentOptions( + view: View, + commentEntity: CommentEntity, + showConversation: Boolean, + answerId: String, + listener: OnCommentOptionClickListener? + ) { + showCommentOptions( + view = view, + commentEntity = commentEntity, + showConversation = showConversation, + answerId = answerId, + listener = listener + ) } @JvmStatic - fun showVideoCommentOptions(view: View, - commentEntity: CommentEntity, - showConversation: Boolean, - videoId: String, - isVideoAuthor: Boolean, - listener: OnCommentOptionClickListener?) { - showCommentOptions(view = view, - commentEntity = commentEntity, - showConversation = showConversation, - videoId = videoId, - isVideoAuthor = isVideoAuthor, - listener = listener) + fun showVideoCommentOptions( + view: View, + commentEntity: CommentEntity, + showConversation: Boolean, + videoId: String, + isVideoAuthor: Boolean, + isShowTop: Boolean = false, + listener: OnCommentOptionClickListener? + ) { + showCommentOptions( + view = view, + commentEntity = commentEntity, + showConversation = showConversation, + videoId = videoId, + isVideoAuthor = isVideoAuthor, + isShowTop = isShowTop, + listener = listener + ) } - fun showQuestionCommentOption(view: View, - commentEntity: CommentEntity, - questionId: String, - listener: OnCommentOptionClickListener?) { - showCommentOptions(view = view, - commentEntity = commentEntity, - showConversation = false, - questionId = questionId, - isShowTop = true, - ignoreModerator = true, - listener = listener) + fun showQuestionCommentOption( + view: View, + commentEntity: CommentEntity, + questionId: String, + isShowTop: Boolean = false, + listener: OnCommentOptionClickListener? + ) { + showCommentOptions( + view = view, + commentEntity = commentEntity, + showConversation = false, + questionId = questionId, + isShowTop = isShowTop, + ignoreModerator = true, + listener = listener + ) } - private fun showCommentOptions(view: View, - commentEntity: CommentEntity, - showConversation: Boolean, - articleId: String? = null, - communityId: String? = null, - answerId: String? = null, - questionId: String? = null, - videoId: String? = null, - isShowTop: Boolean = false, - ignoreModerator: Boolean = false, - isVideoAuthor: Boolean = false, - listener: OnCommentOptionClickListener? = null) { + private fun showCommentOptions( + view: View, + commentEntity: CommentEntity, + showConversation: Boolean, + articleId: String? = null, + communityId: String? = null, + answerId: String? = null, + questionId: String? = null, + videoId: String? = null, + isShowTop: Boolean = false, + ignoreModerator: Boolean = false, + isVideoAuthor: Boolean = false, + listener: OnCommentOptionClickListener? = null + ) { val context = view.context val dialogOptions = ArrayList() - if (isShowTop && (articleId != null || questionId != null) && commentEntity.me?.isArticleOrAnswerAuthor == true) { + + if (isShowTop && (articleId != null || questionId != null) && commentEntity.me?.isContentAuthor == true) { dialogOptions.add(if (commentEntity.isTop) "取消置顶" else "置顶") } - if (questionId != null && commentEntity.me?.isArticleOrAnswerAuthor == true && !commentEntity.accept) { - dialogOptions.add("采纳") + if (questionId != null && commentEntity.me?.isContentAuthor == true) { + if (commentEntity.accept) { + dialogOptions.add("取消采纳") + } else { + dialogOptions.add("采纳") + } } dialogOptions.add("复制") @@ -114,23 +142,21 @@ object CommentHelper { if (questionId != null && commentEntity.me?.isModerator == true && !commentEntity.choiceness) { dialogOptions.add("加精选") } - if (isVideoAuthor || (videoId != null && commentEntity.user.id == UserManager.getInstance().userId)) { - dialogOptions.add("删除评论") - } else if ((articleId != null || questionId != null) && (commentEntity.user.id == UserManager.getInstance().userId || - commentEntity.me?.isModerator == true || commentEntity.me?.isArticleOrAnswerAuthor == true)) { + if (commentEntity.user.id == UserManager.getInstance().userId || commentEntity.me?.isModerator == true || commentEntity.me?.isContentAuthor == true) { dialogOptions.add("删除评论") } - commentEntity.me?.let { + /*commentEntity.me?.let { if (ignoreModerator) return@let if (it.isModerator || (it.moderatorPermissions.hideAnswerComment > Permissions.GUEST - || it.moderatorPermissions.topAnswerComment > Permissions.GUEST - || it.moderatorPermissions.hideCommunityArticleComment > Permissions.GUEST - || it.moderatorPermissions.topCommunityArticleComment > Permissions.GUEST)) { + || it.moderatorPermissions.topAnswerComment > Permissions.GUEST + || it.moderatorPermissions.hideCommunityArticleComment > Permissions.GUEST + || it.moderatorPermissions.topCommunityArticleComment > Permissions.GUEST) + ) { dialogOptions.add("管理") } - } + }*/ if (commentEntity.parentUser != null && showConversation) { dialogOptions.add("查看对话") @@ -138,9 +164,11 @@ object CommentHelper { val inflater = LayoutInflater.from(context) val layout = inflater.inflate(R.layout.layout_popup_container, null) - val popupWindow = BugFixedPopupWindow(layout, - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT) + val popupWindow = BugFixedPopupWindow( + layout, + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ) val container = layout.findViewById(R.id.container) for (text in dialogOptions) { val item = inflater.inflate(R.layout.layout_popup_option_item, container, false) @@ -153,39 +181,77 @@ object CommentHelper { popupWindow.dismiss() listener?.onCommentOptionClick(commentEntity, text) when (text) { - "管理" -> showControlDialog(context, answerId, articleId, communityId, commentEntity, commentEntity.me!!) + "管理" -> showControlDialog( + context, + answerId, + articleId, + communityId, + commentEntity, + commentEntity.me!! + ) "复制" -> copyText(commentEntity.content, context) "投诉" -> { context.ifLogin("回答详情-评论-投诉") { showReportTypeDialog(context) { reportType -> - val commentListener = object : PostCommentUtils.PostCommentListener { - override fun postSuccess(response: JSONObject?) { - Utils.toast(context, "感谢您的投诉") - } + val commentListener = + object : PostCommentUtils.PostCommentListener { + override fun postSuccess(response: JSONObject?) { + Utils.toast(context, "感谢您的投诉") + } - override fun postFailed(error: Throwable?) { - if (error == null) { - Utils.toast(context, "投诉失败,请稍后重试") - } else { - Utils.toast(context, "投诉失败,${error.message}") + override fun postFailed(error: Throwable?) { + if (error == null) { + Utils.toast(context, "投诉失败,请稍后重试") + } else { + if (error is HttpException) { + ErrorHelper.handleError( + HaloApp.getInstance().application, + error.response().errorBody()?.string() + ) + } + } } } - } when { answerId != null -> { - PostCommentUtils.postAnswerReportData(context, commentEntity.id, answerId, reportType, commentListener) + PostCommentUtils.postAnswerReportData( + context, + commentEntity.id, + answerId, + reportType, + commentListener + ) } articleId != null -> { - PostCommentUtils.reportCommunityArticleComment(context, communityId, articleId, commentEntity.id, reportType, commentListener) + PostCommentUtils.reportCommunityArticleComment( + context, + communityId, + articleId, + commentEntity.id, + reportType, + commentListener + ) } questionId != null -> { - PostCommentUtils.reportQuestionComment(context, questionId, commentEntity.id, reportType, commentListener) + PostCommentUtils.reportQuestionComment( + context, + questionId, + commentEntity.id, + reportType, + commentListener + ) } else -> { - PostCommentUtils.reportVideoComment(context, videoId, commentEntity.id, reportType, commentListener) + PostCommentUtils.reportVideoComment( + context, + videoId, + commentEntity.id, + reportType, + commentListener + ) } } } @@ -194,14 +260,37 @@ object CommentHelper { "查看对话" -> { if (answerId != null) { - context.startActivity(CommentDetailActivity - .getAnswerCommentIntent(context, commentEntity.id, answerId, null)) + context.startActivity( + CommentDetailActivity + .getAnswerCommentIntent( + context, + commentEntity.id, + answerId, + null + ) + ) } else if (articleId != null) { - context.startActivity(CommentDetailActivity - .getCommunityArticleCommentIntent(context, articleId, commentEntity.id, communityId, null)) + context.startActivity( + CommentDetailActivity + .getCommunityArticleCommentIntent( + context, + articleId, + commentEntity.id, + communityId, + null + ) + ) } else { - context.startActivity(CommentDetailActivity - .getVideoCommentIntent(context, commentEntity.id, videoId, isVideoAuthor, null)) + context.startActivity( + CommentDetailActivity + .getVideoCommentIntent( + context, + commentEntity.id, + videoId, + isVideoAuthor, + null + ) + ) } } } @@ -213,12 +302,14 @@ object CommentHelper { popupWindow.showAutoOrientation(view) } - private fun showControlDialog(context: Context, - answerId: String? = null, - articleId: String? = null, - communityId: String? = null, - comment: CommentEntity, - me: MeEntity) { + private fun showControlDialog( + context: Context, + answerId: String? = null, + articleId: String? = null, + communityId: String? = null, + comment: CommentEntity, + me: MeEntity + ) { val dialogOptions = arrayListOf() val highlight = "置顶评论" val hide = "隐藏评论" @@ -227,19 +318,23 @@ object CommentHelper { var canHideCommentDirectly = false if (me.isModerator || me.moderatorPermissions.topAnswerComment > Permissions.GUEST - || me.moderatorPermissions.topCommunityArticleComment > Permissions.GUEST) { + || me.moderatorPermissions.topCommunityArticleComment > Permissions.GUEST + ) { dialogOptions.add(highlight) if (me.moderatorPermissions.topAnswerComment > Permissions.REPORTER - || me.moderatorPermissions.topCommunityArticleComment > Permissions.REPORTER) { + || me.moderatorPermissions.topCommunityArticleComment > Permissions.REPORTER + ) { canHighlightCommentDirectly = true } } if (me.isModerator || me.moderatorPermissions.hideAnswerComment > Permissions.GUEST - || me.moderatorPermissions.hideCommunityArticleComment > Permissions.GUEST) { + || me.moderatorPermissions.hideCommunityArticleComment > Permissions.GUEST + ) { dialogOptions.add(hide) if (me.moderatorPermissions.hideAnswerComment > Permissions.REPORTER - || me.moderatorPermissions.hideCommunityArticleComment > Permissions.REPORTER) { + || me.moderatorPermissions.hideCommunityArticleComment > Permissions.REPORTER + ) { canHideCommentDirectly = true } } @@ -300,7 +395,10 @@ object CommentHelper { val errorJson = JSONObject(string) val errorCode = errorJson.getInt("code") if (errorCode == 403059) { - Utils.toast(HaloApp.getInstance().application, "权限错误,请刷新后重试") + Utils.toast( + HaloApp.getInstance().application, + "权限错误,请刷新后重试" + ) return } else { Utils.toast(HaloApp.getInstance().application, e.message()) @@ -311,23 +409,31 @@ object CommentHelper { } if (answerId != null) { - DialogUtils.showAlertDialog(context, highlight, highlightDialogHintContent, - "确定", "取消", { - RetrofitManager.getInstance(context).api + DialogUtils.showAlertDialog( + context, highlight, highlightDialogHintContent, + "确定", "取消", { + RetrofitManager.getInstance(context).api .highlightAnswerComment(answerId, comment.id) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(highlightObserver) - }, null) + }, null + ) } else { - DialogUtils.showAlertDialog(context, highlight, highlightDialogHintContent, - "确定", "取消", { - RetrofitManager.getInstance(context).api - .highlightCommunityArticleComment(communityId, articleId, comment.id) + DialogUtils.showAlertDialog( + context, highlight, highlightDialogHintContent, + "确定", "取消", { + RetrofitManager.getInstance(context).api + .highlightCommunityArticleComment( + communityId, + articleId, + comment.id + ) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(highlightObserver) - }, null) + }, null + ) } } @@ -349,7 +455,10 @@ object CommentHelper { val errorJson = JSONObject(string) val errorCode = errorJson.getInt("code") if (errorCode == 403059) { - Utils.toast(HaloApp.getInstance().application, "权限错误,请刷新后重试") + Utils.toast( + HaloApp.getInstance().application, + "权限错误,请刷新后重试" + ) return } else { Utils.toast(HaloApp.getInstance().application, e.message()) @@ -360,33 +469,45 @@ object CommentHelper { } if (answerId != null) { - DialogUtils.showAlertDialog(context, hide, hideDialogHintContent, - "确定", "取消", { - RetrofitManager.getInstance(context).api + DialogUtils.showAlertDialog( + context, hide, hideDialogHintContent, + "确定", "取消", { + RetrofitManager.getInstance(context).api .hideAnswerComment(answerId, comment.id) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(hideObserver) - }, null) + }, null + ) } else { - DialogUtils.showAlertDialog(context, hide, hideDialogHintContent, - "确定", "取消", { - RetrofitManager.getInstance(context).api + DialogUtils.showAlertDialog( + context, hide, hideDialogHintContent, + "确定", "取消", { + RetrofitManager.getInstance(context).api .hideCommunityArticleComment(communityId, articleId, comment.id) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(hideObserver) - }, null) + }, null + ) } } } } } - private fun showReportTypeDialog(context: Context, reportCallback: (reportType: String) -> Unit) { - val reportTypes = arrayListOf("垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息", "违法有害信息", "其它") - DialogUtils.showVideoComplaintDialog(context, reportTypes, null) { text -> - reportCallback.invoke(text) + private fun showReportTypeDialog( + context: Context, + reportCallback: (reportType: String) -> Unit + ) { + DialogUtils.showReportReasonDialog( + context, + Constants.REPORT_LIST.toList() as ArrayList + ) { reason, desc -> + val json = json { + "reason" to if (reason != "其他原因") reason else desc + } + reportCallback.invoke(json.toString()) } } diff --git a/app/src/main/java/com/gh/common/util/DataLogUtils.java b/app/src/main/java/com/gh/common/util/DataLogUtils.java index df7f2de0fc..21440726c0 100644 --- a/app/src/main/java/com/gh/common/util/DataLogUtils.java +++ b/app/src/main/java/com/gh/common/util/DataLogUtils.java @@ -48,7 +48,7 @@ public class DataLogUtils { // 上传日志 public static void uploadLog(Context context, String topic, Map map) { - String version = PackageUtils.getVersionName(); + String version = PackageUtils.getGhVersionName(); String user = Installation.getUUID(context); String channel = HaloApp.getInstance().getChannel(); map.put("version", version); diff --git a/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java b/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java index 054c461e58..9b60dae37e 100644 --- a/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java +++ b/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java @@ -4,6 +4,7 @@ import android.text.TextUtils; import android.view.View; import com.gh.common.constant.Config; +import com.gh.common.constant.Constants; import com.gh.common.repository.ReservationRepository; import com.gh.common.simulator.SimulatorGameManager; import com.gh.common.view.DownloadProgressBar; @@ -133,7 +134,11 @@ public class DetailDownloadUtils { case downloading: case pause: case overflow: - viewHolder.mDownloadPb.setText(R.string.downloading); + if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) { + viewHolder.mDownloadPb.setText(R.string.browser_install_downloading); + } else { + viewHolder.mDownloadPb.setText(R.string.downloading); + } if (downloadEntity.isPluggable() && PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) { viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_PLUGIN); } else { @@ -152,17 +157,25 @@ public class DetailDownloadUtils { } break; case done: - if (SimulatorGameManager.isSimulatorGame(viewHolder.gameEntity)){ + if (SimulatorGameManager.isSimulatorGame(viewHolder.gameEntity)) { boolean isInstalled = PackageUtils.isInstalledFromAllPackage(viewHolder.context, viewHolder.gameEntity.getSimulator().getApk().getPackageName()); - if (isInstalled){ + if (isInstalled) { viewHolder.mDownloadPb.setText(R.string.launch); viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.LAUNCH_OR_OPEN); - }else{ - viewHolder.mDownloadPb.setText(R.string.install); + } else { + if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) { + viewHolder.mDownloadPb.setText(R.string.browser_install_install); + } else { + viewHolder.mDownloadPb.setText(R.string.install); + } viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL); } - }else{ - viewHolder.mDownloadPb.setText(R.string.install); + } else { + if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) { + viewHolder.mDownloadPb.setText(R.string.browser_install_install); + } else { + viewHolder.mDownloadPb.setText(R.string.install); + } if (downloadEntity.isPluggable() && PackagesManager.isInstalled(downloadEntity.getPackageName())) { viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_PLUGIN); diff --git a/app/src/main/java/com/gh/common/util/DialogHelper.kt b/app/src/main/java/com/gh/common/util/DialogHelper.kt index 68d5158cb6..08f31024fd 100644 --- a/app/src/main/java/com/gh/common/util/DialogHelper.kt +++ b/app/src/main/java/com/gh/common/util/DialogHelper.kt @@ -1,5 +1,6 @@ package com.gh.common.util +import android.app.Activity import android.app.Dialog import android.content.Context import android.graphics.Color @@ -35,9 +36,11 @@ object DialogHelper { uiModificationCallback: ((binding: DialogAlertDefaultBinding) -> Unit)? = null, trackMtaEvent: Boolean = false, mtaEvent: String = "", - mtaKey: String = ""): Dialog { + mtaKey: String = "") { val solidContext = checkDialogContext(context) + if (solidContext is Activity && solidContext.isFinishing) return + val dialog = if (trackMtaEvent) { TrackableDialog(solidContext, R.style.GhAlertDialog, mtaEvent, mtaKey) } else { @@ -65,6 +68,7 @@ object DialogHelper { if (it.showCloseIcon) { binding.closeContainer.visibility = View.VISIBLE + binding.closeContainer.enlargeTouchArea() binding.closeContainer.setOnClickListener { dialog.dismiss() } } } @@ -97,7 +101,6 @@ object DialogHelper { dialog.setContentView(contentView) dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) dialog.show() - return dialog } /** @@ -114,8 +117,8 @@ object DialogHelper { negativeClickCallback: EmptyCallback, trackMtaEvent: Boolean = false, mtaEvent: String = "", - mtaKey: String = ""): Dialog { - return showDialog( + mtaKey: String = "") { + showDialog( context = context, title = title, content = content, diff --git a/app/src/main/java/com/gh/common/util/DialogUtils.java b/app/src/main/java/com/gh/common/util/DialogUtils.java index 411572e341..e91661de2e 100644 --- a/app/src/main/java/com/gh/common/util/DialogUtils.java +++ b/app/src/main/java/com/gh/common/util/DialogUtils.java @@ -45,10 +45,12 @@ import androidx.appcompat.app.AlertDialog; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.content.ContextCompat; import androidx.databinding.DataBindingUtil; +import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import kotlin.Unit; import kotlin.jvm.functions.Function0; +import kotlin.jvm.functions.Function1; import com.facebook.drawee.generic.GenericDraweeHierarchy; import com.facebook.drawee.view.SimpleDraweeView; @@ -60,11 +62,14 @@ import com.gh.common.view.DrawableView; import com.gh.common.view.FixLinearLayoutManager; import com.gh.common.view.LimitHeightLinearLayout; import com.gh.common.view.MaxHeightNestedScrollView; +import com.gh.common.view.VerticalItemDecoration; import com.gh.gamecenter.AboutActivity; import com.gh.gamecenter.R; import com.gh.gamecenter.SuggestionActivity; +import com.gh.gamecenter.adapter.ReportReasonAdapter; import com.gh.gamecenter.adapter.viewholder.PrivacyPolicyItemViewHolder; import com.gh.gamecenter.databinding.DialogBindPhoneBinding; +import com.gh.gamecenter.databinding.DialogEnergySignBinding; import com.gh.gamecenter.databinding.DialogOverseaConfirmationBinding; import com.gh.gamecenter.databinding.DialogPackageParseErrorBinding; import com.gh.gamecenter.databinding.DialogQuickLoginPermissionBinding; @@ -1927,7 +1932,7 @@ public class DialogUtils { return dialog; } - public static void showEnergyDialog(Context context, String userName, int energy) { + public static void showEnergyDialog(Context context, String userName, long energy) { context = checkDialogContext(context); final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent); @@ -2012,37 +2017,26 @@ public class DialogUtils { } @SuppressLint("SetTextI18n") - public static void showReportReasonDialog(Context context, ReportReasonCallBack callBack) { + public static void showReportReasonDialog(Context context, ArrayList items, ReportReasonCallBack callBack) { context = checkDialogContext(context); final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent); DialogReportReasonBinding binding = DialogReportReasonBinding.inflate(LayoutInflater.from(context)); - binding.reasonOne.setOnClickListener(v -> { - dialog.dismiss(); - callBack.onResponse(binding.reasonOne.getText().toString(), ""); - }); - - binding.reasonTwo.setOnClickListener(v -> { - dialog.dismiss(); - callBack.onResponse(binding.reasonTwo.getText().toString(), ""); - }); - - binding.reasonThree.setOnClickListener(v -> { - dialog.dismiss(); - callBack.onResponse(binding.reasonThree.getText().toString(), ""); - }); - - binding.reasonFour.setOnClickListener(v -> { - dialog.dismiss(); - callBack.onResponse(binding.reasonFour.getText().toString(), ""); - }); - - binding.reasonOther.setOnClickListener(v -> { - binding.reasonTitle.setText(R.string.report_reason_other_title); - binding.normalReasonContainer.setVisibility(View.GONE); - binding.otherReasonContainer.setVisibility(View.VISIBLE); + ReportReasonAdapter reportReasonAdapter = new ReportReasonAdapter(context, items, reason -> { + if (reason.equals("其他原因")) { + binding.reasonTitle.setText(R.string.report_reason_other_title); + binding.normalReasonContainer.setVisibility(View.GONE); + binding.otherReasonContainer.setVisibility(View.VISIBLE); + } else { + dialog.dismiss(); + callBack.onResponse(reason, ""); + } + return null; }); + binding.reasonRv.setLayoutManager(new LinearLayoutManager(context)); + binding.reasonRv.addItemDecoration(new VerticalItemDecoration(context, 1F, false, R.color.text_f5f5f5)); + binding.reasonRv.setAdapter(reportReasonAdapter); binding.negativeBtn.setOnClickListener(v -> { binding.reasonTitle.setText(R.string.report_reason_title); @@ -2052,10 +2046,10 @@ public class DialogUtils { binding.positiveBtn.setOnClickListener(v -> { if (TextUtils.isEmpty(binding.otherReasonEt.getText().toString().trim())) { - ToastUtils.INSTANCE.showToast("请填写举报原因"); + ToastUtils.showToast("请填写举报原因"); } else { dialog.dismiss(); - callBack.onResponse("其它", binding.otherReasonEt.getText().toString()); + callBack.onResponse("其他原因", binding.otherReasonEt.getText().toString()); } }); @@ -2183,6 +2177,38 @@ public class DialogUtils { dialog.show(); } + public static void showEnergySignDialog(Context context, int sevenDaySerialSign) { + context = checkDialogContext(context); + + final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent); + DialogEnergySignBinding binding = DialogEnergySignBinding.inflate(LayoutInflater.from(context)); + + if (sevenDaySerialSign > 7) sevenDaySerialSign = 7; + + for (int i = 1; i <= sevenDaySerialSign; i++) { + int index = (i - 1) * 2; + LinearLayout dayContainer = (LinearLayout) binding.signDaysContainer.getChildAt(index); + ImageView dayIv = (ImageView) dayContainer.getChildAt(1); + dayIv.setImageResource(R.drawable.ic_energy_center_signed); + + if (i != 7) { + int rIndex = (i - 1) * 2 + 1; + LinearLayout lineContainer = (LinearLayout) binding.signDaysContainer.getChildAt(rIndex); + View straightLine = lineContainer.getChildAt(0); + View dottedLine = lineContainer.getChildAt(1); + if (i != sevenDaySerialSign) { + straightLine.setVisibility(View.VISIBLE); + } else { + dottedLine.setVisibility(View.VISIBLE); + } + } + } + + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + dialog.setContentView(binding.getRoot()); + dialog.show(); + } + /** * @param context may be is application context * @return activity context diff --git a/app/src/main/java/com/gh/common/util/DirectUtils.kt b/app/src/main/java/com/gh/common/util/DirectUtils.kt index 7139dad930..afcbbd412d 100644 --- a/app/src/main/java/com/gh/common/util/DirectUtils.kt +++ b/app/src/main/java/com/gh/common/util/DirectUtils.kt @@ -1516,14 +1516,14 @@ object DirectUtils { * 跳转至活动详情 */ @JvmStatic - fun directToActivityDetail(context: Context, activityId: String, entrance: String) { + fun directToActivityDetail(context: Context, activityId: String, categoryId: String, entrance: String) { var url: String = if (isPublishEnv()) { Constants.ACTIVITY_DETAIL_ADDRESS } else { Constants.ACTIVITY_DETAIL_ADDRESS_DEV } - url = String.format(Locale.CHINA, "%s&id=%s×tamp=%d", url, activityId, (Date().time / 1000 / 1000.toFloat()).roundToInt()) + url = String.format(Locale.CHINA, "%s&id=%s&category_id=%s×tamp=%d", url, activityId, categoryId, (Date().time / 1000 / 1000.toFloat()).roundToInt()) directToWebView(context, url, entrance) } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/DownloadDialogHelper.kt b/app/src/main/java/com/gh/common/util/DownloadDialogHelper.kt index 7e5814a9e3..314ebe9f38 100644 --- a/app/src/main/java/com/gh/common/util/DownloadDialogHelper.kt +++ b/app/src/main/java/com/gh/common/util/DownloadDialogHelper.kt @@ -29,7 +29,7 @@ object DownloadDialogHelper { if (downloadDialog.isNullOrEmpty()) return null for (dialog in downloadDialog) { - val versionName = PackageUtils.getVersionName() + val versionName = PackageUtils.getGhVersionName() val noticeVersions = dialog.rule.noticeVersions if (noticeVersions.isEmpty() || noticeVersions.contains(versionName)) { // 共有 8 种可能 diff --git a/app/src/main/java/com/gh/common/util/DownloadItemUtils.java b/app/src/main/java/com/gh/common/util/DownloadItemUtils.java index 18252c6689..e3c7dbd118 100644 --- a/app/src/main/java/com/gh/common/util/DownloadItemUtils.java +++ b/app/src/main/java/com/gh/common/util/DownloadItemUtils.java @@ -386,7 +386,9 @@ public class DownloadItemUtils { holder.gameDes.setVisibility(View.GONE); holder.gameProgressbar.setVisibility(View.VISIBLE); holder.gameInfo.setVisibility(View.VISIBLE); - holder.recommendContainer.setVisibility(View.GONE); + if (holder.recommendContainer != null) { + holder.recommendContainer.setVisibility(View.GONE); + } } else { holder.gameProgressbar.setVisibility(View.GONE); holder.gameInfo.setVisibility(View.GONE); @@ -395,21 +397,18 @@ public class DownloadItemUtils { if (briefStyle != null && recommendStyle != null && briefStyle.contains("recommend")) { - holder.recommendContainer.setVisibility(View.VISIBLE); + if (holder.recommendContainer != null) { + holder.recommendContainer.setVisibility(View.VISIBLE); + } if (holder.gameRating != null) holder.gameRating.setVisibility(View.GONE); holder.gameDes.setVisibility(View.GONE); holder.recommendTv.setText(recommendStyle.getText()); - if ("none".equals(recommendStyle.getType())) { + if (TextUtils.isEmpty(recommendStyle.getIcon())) { holder.recommendIv.setVisibility(View.GONE); } else { - Context context = holder.recommendContainer.getContext(); - int drawableId = context.getResources().getIdentifier( - "ic_recommend_" + recommendStyle.getType(), - "drawable", - context.getPackageName()); holder.recommendIv.setVisibility(View.VISIBLE); - holder.recommendIv.setImageResource(drawableId); + ImageUtils.display(holder.recommendIv, recommendStyle.getIcon()); } return; } else { diff --git a/app/src/main/java/com/gh/common/util/EnergyTaskHelper.kt b/app/src/main/java/com/gh/common/util/EnergyTaskHelper.kt index 19a9cdec47..5c63070475 100644 --- a/app/src/main/java/com/gh/common/util/EnergyTaskHelper.kt +++ b/app/src/main/java/com/gh/common/util/EnergyTaskHelper.kt @@ -130,27 +130,39 @@ object EnergyTaskHelper { // 完成弹窗 @JvmStatic fun showCompletePopup(entity: EnergyTaskCompleteEntity) { - val currentActivity = AppManager.getInstance().recentActiveActivity - currentActivity?.run { - val contentView = View.inflate(this, R.layout.popup_energy_task, null) - contentView.run { - findViewById(R.id.taskDesc).text = "恭喜你!完成任务:${entity.name}" - findViewById(R.id.taskEnergy).text = "+${entity.energy}光能" - isFocusable = true - isFocusableInTouchMode = true - setOnClickListener { - if (currentActivity::class.java.simpleName != EnergyCenterActivity::class.java.simpleName) { - currentActivity.startActivity(EnergyCenterActivity.getIntent(currentActivity)) + tryWithDefaultCatch { + val currentActivity = AppManager.getInstance().recentActiveActivity + val popWindow = PopupWindow(LinearLayout.LayoutParams.MATCH_PARENT, 88F.dip2px()) + + currentActivity?.run { + val contentView = View.inflate(this, R.layout.popup_energy_task, null) + contentView.run { + findViewById(R.id.taskDesc).text = "恭喜你!完成任务:${entity.name}" + findViewById(R.id.taskEnergy).text = "+${entity.energy}光能" + isFocusable = true + isFocusableInTouchMode = true + setOnClickListener { + if (popWindow != null && popWindow.isShowing) { + popWindow.dismiss() + } + if (currentActivity !is EnergyCenterActivity) { + currentActivity.startActivity(EnergyCenterActivity.getIntent(currentActivity)) + } } } - } - val popWindow = PopupWindow(contentView, LinearLayout.LayoutParams.MATCH_PARENT, 88F.dip2px()) - popWindow.showAtLocation(currentActivity.window.decorView, Gravity.TOP, 0, 0) - countDownTimer(3) { finish, _ -> - if (finish && popWindow != null && popWindow.isShowing) { - popWindow.dismiss() + popWindow.contentView = contentView + currentActivity.window.decorView.post { + popWindow.showAtLocation(currentActivity.window.decorView, Gravity.TOP, 0, 0) } + + contentView.postDelayed({ + tryCatchInRelease { + if (popWindow != null && popWindow.isShowing) { + popWindow.dismiss() + } + } + }, 3000) } } } diff --git a/app/src/main/java/com/gh/common/util/EntranceUtils.java b/app/src/main/java/com/gh/common/util/EntranceUtils.java index ceeb792161..32c7f446da 100644 --- a/app/src/main/java/com/gh/common/util/EntranceUtils.java +++ b/app/src/main/java/com/gh/common/util/EntranceUtils.java @@ -53,6 +53,7 @@ public class EntranceUtils { public static final String HOST_VIDEO_STREAMING_HOME = "video_streaming_home";//视频流-首页 public static final String HOST_VIDEO_STREAMING_DESC = "video_streaming_desc";//视频流-游戏介绍进入 public static final String HOST_VIDEO_COLLECTION = "video_collection";//视频合集 + public static final String HOST_VIDEO_DETAIL = "video_detail"; public static final String HOST_USERHOME = "userhome";//个人主页 public static final String HOST_VIDEO = "video"; public static final String HOST_FORUM = "forum"; diff --git a/app/src/main/java/com/gh/common/util/ErrorHelper.kt b/app/src/main/java/com/gh/common/util/ErrorHelper.kt index 8b9feb51e7..901b42cf57 100644 --- a/app/src/main/java/com/gh/common/util/ErrorHelper.kt +++ b/app/src/main/java/com/gh/common/util/ErrorHelper.kt @@ -19,10 +19,12 @@ object ErrorHelper { * [customizedHandler] 返回 true 为已处理该错误码,false 则交由 [handleError] 处理 */ @JvmStatic - fun handleErrorWithCustomizedHandler(context: Context, - errorString: String?, - showHighPriorityHint: Boolean = false, - customizedHandler: (code: Int) -> Boolean) { + fun handleErrorWithCustomizedHandler( + context: Context, + errorString: String?, + showHighPriorityHint: Boolean = false, + customizedHandler: (code: Int) -> Boolean + ) { val errorEntity = errorString?.toObject() if (customizedHandler(errorEntity?.code ?: 0)) { @@ -75,8 +77,15 @@ object ErrorHelper { *403057: 游戏评论 *403054: 更新社区文章 *403047: 回答点赞 + *403112: 发布视频贴 + *403113: 修改视频贴 + *403114: 点赞视频贴 */ - private fun handleError(context: Context, showHighPriorityHint: Boolean = false, errorEntity: ErrorEntity) { + private fun handleError( + context: Context, + showHighPriorityHint: Boolean = false, + errorEntity: ErrorEntity + ) { when (errorEntity.code) { 403050, 403051, @@ -89,7 +98,10 @@ object ErrorHelper { 403054, 403069, 403071, - 403047 -> handleErrorWithCommunityBannedDialog(context, errorEntity) + 403047, + 403112, + 403113, + 403114 -> handleErrorWithCommunityBannedDialog(context, errorEntity) 403057, 403068 -> handleErrorWithCommentBannedDialog(context, errorEntity) @@ -120,12 +132,17 @@ object ErrorHelper { 403082 -> Utils.toast(context, "作者已关闭评论") 403022 -> Utils.toast(context, "不能回复自己") 403056 -> Utils.toast(context, "发布失败,字数已达上限") + 403111 -> Utils.toast(context, "提交失败,评论违规") + 400001 -> Utils.toast(context, "字数超过500或者未填写原因") + 403102 -> Utils.toast(context, "你已经举报过该内容了哦") 403020 -> if (showHighPriorityHint) { - DialogUtils.showAlertDialog(context, - "提醒", - "提问过于频繁,请先休息一下哦", - "知道了", null, null, null) + DialogUtils.showAlertDialog( + context, + "提醒", + "提问过于频繁,请先休息一下哦", + "知道了", null, null, null + ) } else { Utils.toast(context, R.string.comment_failed_toofrequent) } @@ -148,12 +165,14 @@ object ErrorHelper { "(非永久)" } val dialogContext = DialogUtils.checkDialogContext(context) - DialogUtils.showAlertDialog(dialogContext, - "提示", - "你因违反《光环助手评论规则》,已被禁言$bannedType,如有疑问,请联系客服(QQ:${Config.getSettings()?.support?.qq})", - "去看看", "关闭", { - dialogContext.startActivity(WebActivity.getCommentRulesIntent(dialogContext)) - }, null) + DialogUtils.showAlertDialog( + dialogContext, + "提示", + "你因违反《光环助手评论规则》,已被禁言$bannedType,如有疑问,请联系客服(QQ:${Config.getSettings()?.support?.qq})", + "去看看", "关闭", { + dialogContext.startActivity(WebActivity.getCommentRulesIntent(dialogContext)) + }, null + ) } private fun handleErrorWithCommunityBannedDialog(context: Context, errorEntity: ErrorEntity) { @@ -163,18 +182,21 @@ object ErrorHelper { "(非永久)" } val dialogContext = DialogUtils.checkDialogContext(context) - DialogUtils.showAlertDialog(dialogContext, - "提示", - "你因违反《问答版块规则》,已被禁言$bannedType,如有疑问,请联系客服(QQ:1562479331)", - "去看看", "关闭", { - dialogContext.startActivity(WebActivity.getCommunityRuleIntent(dialogContext)) - }, null) + DialogUtils.showAlertDialog( + dialogContext, + "提示", + "你因违反《问答版块规则》,已被禁言$bannedType,如有疑问,请联系客服(QQ:1562479331)", + "去看看", "关闭", { + dialogContext.startActivity(WebActivity.getCommunityRuleIntent(dialogContext)) + }, null + ) } @JvmStatic fun handleLoginError(context: Context, httpException: HttpException?) { try { - val errorEntity: ErrorEntity? = httpException?.response()?.errorBody()?.string()?.toObject() + val errorEntity: ErrorEntity? = + httpException?.response()?.errorBody()?.string()?.toObject() when { errorEntity?.code == 403099 -> { Utils.toast(context, "当前账号正在注销,禁止登录") diff --git a/app/src/main/java/com/gh/common/util/Extensions.kt b/app/src/main/java/com/gh/common/util/Extensions.kt index e6f0495c50..db011d7e92 100644 --- a/app/src/main/java/com/gh/common/util/Extensions.kt +++ b/app/src/main/java/com/gh/common/util/Extensions.kt @@ -6,18 +6,19 @@ import android.content.ClipboardManager import android.content.Context import android.graphics.Bitmap import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Rect import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable import android.os.Build import android.text.* +import android.text.format.Formatter import android.text.style.ClickableSpan import android.text.style.ImageSpan import android.text.style.URLSpan +import android.util.Log import android.util.TypedValue -import android.view.Gravity -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup +import android.view.* import android.view.inputmethod.InputMethodManager import android.widget.EditText import android.widget.PopupWindow @@ -65,21 +66,22 @@ import java.util.concurrent.TimeUnit import java.util.regex.Pattern import kotlin.math.abs + /** * 创建以 activity 为观察者上下文的 viewModel */ inline fun FragmentActivity.viewModelProvider( - provider: ViewModelProvider.Factory? = null + provider: ViewModelProvider.Factory? = null ) = - ViewModelProviders.of(this, provider).get(VM::class.java) + ViewModelProviders.of(this, provider).get(VM::class.java) /** * 创建以 activity 为观察者上下文的 viewModel * 额外的 key: 用于区分单 activity 多 viewModel 的情况 (如首页tab) */ inline fun Fragment.viewModelProviderFromParent( - provider: ViewModelProvider.Factory? = null, - key: String = "" + provider: ViewModelProvider.Factory? = null, + key: String = "" ) = if (key.isEmpty()) { ViewModelProviders.of(requireActivity(), provider).get(VM::class.java) } else { @@ -90,28 +92,33 @@ inline fun Fragment.viewModelProviderFromParent( * 创建以 activity 为观察者上下文的 viewModel */ inline fun FragmentActivity.viewModelProviderFromParent( - provider: ViewModelProvider.Factory? = null + provider: ViewModelProvider.Factory? = null ) = - ViewModelProviders.of(this, provider).get(VM::class.java) + ViewModelProviders.of(this, provider).get(VM::class.java) /** * 创建以 fragment 为观察者上下文的 viewModel */ inline fun Fragment.viewModelProvider( - provider: ViewModelProvider.Factory? = null + provider: ViewModelProvider.Factory? = null ) = - ViewModelProviders.of(this, provider).get(VM::class.java) + ViewModelProviders.of(this, provider).get(VM::class.java) /** * * ViewPager Extensions * */ -fun ViewPager.doOnPageSelected(action: (position: Int) -> Unit) = addOnPageChangeListener(onSelected = action) +fun ViewPager.doOnPageSelected(action: (position: Int) -> Unit) = + addOnPageChangeListener(onSelected = action) fun ViewPager.addOnPageChangeListener(onSelected: ((position: Int) -> Unit)? = null) { val listener = object : ViewPager.OnPageChangeListener { - override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + override fun onPageScrolled( + position: Int, + positionOffset: Float, + positionOffsetPixels: Int + ) { // Do nothing. } @@ -126,11 +133,17 @@ fun ViewPager.addOnPageChangeListener(onSelected: ((position: Int) -> Unit)? = n addOnPageChangeListener(listener) } -fun ViewPager.doOnScroll(onStateChanged: ((state: Int) -> Unit)? = null, - onPageScrolled: ((position: Int, positionOffset: Float, positionOffsetPixels: Int) -> Unit)? = null, - onPageSelected: ((position: Int) -> Unit)? = null) { +fun ViewPager.doOnScroll( + onStateChanged: ((state: Int) -> Unit)? = null, + onPageScrolled: ((position: Int, positionOffset: Float, positionOffsetPixels: Int) -> Unit)? = null, + onPageSelected: ((position: Int) -> Unit)? = null +) { val listener = object : ViewPager.OnPageChangeListener { - override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + override fun onPageScrolled( + position: Int, + positionOffset: Float, + positionOffsetPixels: Int + ) { onPageScrolled?.invoke(position, positionOffset, positionOffsetPixels) } @@ -150,13 +163,19 @@ fun ViewPager.doOnScroll(onStateChanged: ((state: Int) -> Unit)? = null, * Fragment related */ inline fun Fragment.fragmentFromActivity() = - parentFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T - ?: parentFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T + parentFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T + ?: parentFragmentManager.fragmentFactory.instantiate( + requireContext().classLoader, + T::class.java.canonicalName + ) as T inline fun Fragment.fragmentFromParentFragment() = - childFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T - ?: childFragmentManager.fragmentFactory.instantiate(requireContext().classLoader, T::class.java.canonicalName) as T + childFragmentManager.findFragmentByTag(T::class.java.simpleName) as? T + ?: childFragmentManager.fragmentFactory.instantiate( + requireContext().classLoader, + T::class.java.canonicalName + ) as T /** @@ -164,7 +183,12 @@ inline fun Fragment.fragmentFromParentFragment() = */ // 监听滚动距离 -fun RecyclerView.doOnScrolledSpecificDistance(distanceX: Int = 0, distanceY: Int = 0, singleTimeEvent: Boolean = false, action: () -> Unit) { +fun RecyclerView.doOnScrolledSpecificDistance( + distanceX: Int = 0, + distanceY: Int = 0, + singleTimeEvent: Boolean = false, + action: () -> Unit +) { val listener = object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) @@ -186,10 +210,10 @@ fun RecyclerView.doOnScrolledSpecificDistance(distanceX: Int = 0, distanceY: Int */ inline fun ViewGroup.toBinding(): T { return T::class.java.getMethod( - "inflate", - LayoutInflater::class.java, - ViewGroup::class.java, - Boolean::class.java + "inflate", + LayoutInflater::class.java, + ViewGroup::class.java, + Boolean::class.java ).invoke(null, layoutInflater, this, false) as T } @@ -236,6 +260,43 @@ fun View.setDebouncedClickListener(action: () -> Unit) { val View.layoutInflater: LayoutInflater get() = LayoutInflater.from(this.context) +fun View.removeFromParent() { + postDelayed(object : Runnable { + override fun run() { + try { + if (parent == null) { + Utils.log(javaClass.simpleName, "getParent() returning Null") + } else { + try { + (parent as ViewGroup).removeView(this@removeFromParent) + } catch (ex: Exception) { + Utils.log(javaClass.simpleName, "Cannot remove from parent layout") + } + } + } catch (ex: Exception) { + Utils.log(javaClass.simpleName, Log.getStackTraceString(ex)) + } + } + }, 100) +} + +/** + * 扩大 View 的点击区域 + */ +fun View.enlargeTouchArea(enlargedSizeInPx: Int = 4F.dip2px()) { + val parent = parent as View + + parent.post { + val rect = Rect() + getHitRect(rect) + rect.top -= enlargedSizeInPx + rect.left -= enlargedSizeInPx + rect.bottom += enlargedSizeInPx + rect.right += enlargedSizeInPx + parent.touchDelegate = TouchDelegate(rect, this) + } +} + fun isPublishEnv(): Boolean { return BuildConfig.FLAVOR != "internal" } @@ -288,11 +349,11 @@ fun String.insert(index: Int, string: String): String { */ fun String.replaceUnsupportedHtmlTag(): String { return this.replace("", "") - .replace("", "") - .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") } fun String.containHtmlTag(): Boolean { @@ -307,8 +368,8 @@ fun String.containHtmlTag(): Boolean { fun Fragment.showRegulationTestDialogIfNeeded(action: (() -> Unit)) { if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) { DialogUtils.showRegulationTestDialog(requireContext(), - { DirectUtils.directToRegulationTestPage(requireContext()) }, - { action.invoke() }) + { DirectUtils.directToRegulationTestPage(requireContext()) }, + { action.invoke() }) } else { action() } @@ -317,8 +378,8 @@ fun Fragment.showRegulationTestDialogIfNeeded(action: (() -> Unit)) { fun Context.showRegulationTestDialogIfNeeded(action: (() -> Unit)) { if (UserManager.getInstance().userShouldTakeRegulationBaseOnLastRemind()) { DialogUtils.showRegulationTestDialog(this, - { DirectUtils.directToRegulationTestPage(this) }, - { action.invoke() }) + { DirectUtils.directToRegulationTestPage(this) }, + { action.invoke() }) } else { action() } @@ -417,14 +478,15 @@ fun String.removeInsertedContent(): String { // 去除视频相关文本 fun String.removeVideoContent(): String { - val videoRegex = "(?s)
" + val videoRegex = + "(?s)
" return this.replace(videoRegex.toRegex(), "") } // 完全地清除所有 Html 格式 fun String.clearHtmlFormatCompletely(): String { return Html.fromHtml(this).toString().replace('\n', 32.toChar()) - .replace(160.toChar(), 32.toChar()).replace(65532.toChar(), 32.toChar()).trim { it <= ' ' } + .replace(160.toChar(), 32.toChar()).replace(65532.toChar(), 32.toChar()).trim { it <= ' ' } } // 如果该字符串长度超过固定长度的话,从头开始截取固定长度并返回 @@ -554,19 +616,23 @@ fun PopupWindow.showAutoOrientation(anchorView: View, distanceY: Int = 0, distan * 权限相关 */ fun Fragment.checkReadPhoneStateAndStoragePermissionBeforeAction(action: (() -> Unit)) { - PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(requireContext(), object : EmptyCallback { - override fun onCallback() { - action.invoke() - } - }) + PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction( + requireContext(), + object : EmptyCallback { + override fun onCallback() { + action.invoke() + } + }) } fun Fragment.checkReadPhoneStatePermissionBeforeAction(action: (() -> Unit)) { - PermissionHelper.checkReadPhoneStatePermissionBeforeAction(requireContext(), object : EmptyCallback { - override fun onCallback() { - action.invoke() - } - }) + PermissionHelper.checkReadPhoneStatePermissionBeforeAction( + requireContext(), + object : EmptyCallback { + override fun onCallback() { + action.invoke() + } + }) } fun Fragment.checkStoragePermissionBeforeAction(action: (() -> Unit)) { @@ -578,11 +644,13 @@ fun Fragment.checkStoragePermissionBeforeAction(action: (() -> Unit)) { } fun FragmentActivity.checkReadPhoneStateAndStoragePermissionBeforeAction(action: (() -> Unit)) { - PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction(this, object : EmptyCallback { - override fun onCallback() { - action.invoke() - } - }) + PermissionHelper.checkReadPhoneStateAndStoragePermissionBeforeAction( + this, + object : EmptyCallback { + override fun onCallback() { + action.invoke() + } + }) } fun FragmentActivity.checkReadPhoneStatePermissionBeforeAction(action: (() -> Unit)) { @@ -613,20 +681,27 @@ fun List.secondOrNull(): T? { /** * TextView related. */ -fun TextView.setTextWithHighlightedTextWrappedInsideWrapper(text: CharSequence, - wrapper: String = Constants.DEFAULT_TEXT_WRAPPER, - @ColorRes - highlightColorId: Int = R.color.theme_font, - copyClickedText: Boolean = false, - highlightedTextClickListener: (() -> Unit)? = null) { - TextHelper.highlightTextThatIsWrappedInsideWrapper(this, text, wrapper, highlightColorId, object : SimpleCallback { - override fun onCallback(arg: String) { - if (copyClickedText) { - arg.copyTextAndToast("已复制:$arg") +fun TextView.setTextWithHighlightedTextWrappedInsideWrapper( + text: CharSequence, + wrapper: String = Constants.DEFAULT_TEXT_WRAPPER, + @ColorRes + highlightColorId: Int = R.color.theme_font, + copyClickedText: Boolean = false, + highlightedTextClickListener: (() -> Unit)? = null +) { + TextHelper.highlightTextThatIsWrappedInsideWrapper( + this, + text, + wrapper, + highlightColorId, + object : SimpleCallback { + override fun onCallback(arg: String) { + if (copyClickedText) { + arg.copyTextAndToast("已复制:$arg") + } + highlightedTextClickListener?.invoke() } - highlightedTextClickListener?.invoke() - } - }) + }) } fun TextView.setTextChangedListener(action: (s: CharSequence, start: Int, before: Int, count: Int) -> Unit) { @@ -667,7 +742,10 @@ fun List.safelyGetInRelease(index: Int): T? { * @param shrankText 未展开时的文字 * @param expandedText 展开后的文字 */ -fun ExpandTextView.setTextWithInterceptingInternalUrl(shrankText: CharSequence, expandedText: CharSequence) { +fun ExpandTextView.setTextWithInterceptingInternalUrl( + shrankText: CharSequence, + expandedText: CharSequence +) { var shrankSsb = shrankText.interceptUrlSpanAndRoundImageSpan() var expandedSsb = expandedText.interceptUrlSpanAndRoundImageSpan() @@ -675,56 +753,114 @@ fun ExpandTextView.setTextWithInterceptingInternalUrl(shrankText: CharSequence, if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { while (shrankSsb.contains("\n\n")) { val index = shrankSsb.indexOf("\n\n", 0, true) - shrankSsb = SpannableStringBuilder(shrankSsb.subSequence(0, index)).append(shrankSsb.subSequence(index + "\n".length, shrankSsb.length)) + shrankSsb = SpannableStringBuilder( + shrankSsb.subSequence( + 0, + index + ) + ).append(shrankSsb.subSequence(index + "\n".length, shrankSsb.length)) } while (expandedSsb.contains("\n\n")) { val index = expandedSsb.indexOf("\n\n", 0, true) - expandedSsb = SpannableStringBuilder(expandedSsb.subSequence(0, index)).append(expandedSsb.subSequence(index + "\n".length, expandedSsb.length)) + expandedSsb = SpannableStringBuilder( + expandedSsb.subSequence( + 0, + index + ) + ).append(expandedSsb.subSequence(index + "\n".length, expandedSsb.length)) } } // 去掉多余的 P 标签换行 if (expandedSsb.endsWith("\n", true)) { - expandedSsb = SpannableStringBuilder((expandedSsb.subSequence(0, expandedSsb.length - "\n".length))) + expandedSsb = + SpannableStringBuilder((expandedSsb.subSequence(0, expandedSsb.length - "\n".length))) } movementMethod = CustomLinkMovementMethod.getInstance() - shrankSsb = TextHelper.updateSpannableStringWithHighlightedSpan(context, shrankSsb, highlightedTextClickListener = null) - expandedSsb = TextHelper.updateSpannableStringWithHighlightedSpan(context, expandedSsb, highlightedTextClickListener = null) + shrankSsb = TextHelper.updateSpannableStringWithHighlightedSpan( + context, + shrankSsb, + highlightedTextClickListener = null + ) + expandedSsb = TextHelper.updateSpannableStringWithHighlightedSpan( + context, + expandedSsb, + highlightedTextClickListener = null + ) setShrankTextAndExpandedText(shrankSsb, expandedSsb) } +fun TextView.setTextWithInterceptingInternalUrl(text: CharSequence) { + var ssb = text.interceptUrlSpanAndRoundImageSpan() + // 去掉旧版本 Android 系统 [Html.FROM_HTML_MODE_LEGACY] 产生的两个换行符 (丑陋的代码) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + while (ssb.contains("\n\n")) { + val index = ssb.indexOf("\n\n", 0, true) + ssb = SpannableStringBuilder( + ssb.subSequence( + 0, + index + ) + ).append(ssb.subSequence(index + "\n".length, ssb.length)) + } + } + // 去掉多余的 P 标签换行 + if (ssb.endsWith("\n", true)) { + ssb = + SpannableStringBuilder((ssb.subSequence(0, ssb.length - "\n".length))) + } + + movementMethod = CustomLinkMovementMethod.getInstance() + + ssb = TextHelper.updateSpannableStringWithHighlightedSpan( + context, + ssb, + highlightedTextClickListener = null + ) + setText(ssb) +} + fun CharSequence.interceptUrlSpanAndRoundImageSpan(): SpannableStringBuilder { return SpannableStringBuilder.valueOf(this).apply { getSpans(0, length, URLSpan::class.java).forEach { setSpan( - object : ClickableSpan() { - override fun updateDrawState(ds: TextPaint) { - super.updateDrawState(ds) - ds.color = ContextCompat.getColor(HaloApp.getInstance().application, R.color.theme_font) - ds.isUnderlineText = false - } + object : ClickableSpan() { + override fun updateDrawState(ds: TextPaint) { + super.updateDrawState(ds) + ds.color = ContextCompat.getColor( + HaloApp.getInstance().application, + R.color.theme_font + ) + ds.isUnderlineText = false + } - override fun onClick(widget: View) { - if (!DefaultUrlHandler.interceptUrl(widget.context, it.url, "")) { - widget.context.startActivity(WebActivity.getIntent(widget.context, it.url, true)) - } + override fun onClick(widget: View) { + if (!DefaultUrlHandler.interceptUrl(widget.context, it.url, "")) { + widget.context.startActivity( + WebActivity.getIntent( + widget.context, + it.url, + true + ) + ) } - }, - getSpanStart(it), - getSpanEnd(it), - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + } + }, + getSpanStart(it), + getSpanEnd(it), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE ) removeSpan(it) } getSpans(0, length, ImageSpan::class.java).forEach { setSpan( - CenterImageSpan(it.drawable), - getSpanStart(it), - getSpanEnd(it), - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + CenterImageSpan(it.drawable), + getSpanStart(it), + getSpanEnd(it), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE ) removeSpan(it) } @@ -747,6 +883,13 @@ fun Int.toSimpleCount(): String { return NumberUtils.transSimpleCount(this) } +/** + * Long related + */ +fun Long.toProperReadableSize(): String { + return Formatter.formatFileSize(HaloApp.getInstance().application, this) +} + /** * Image related */ @@ -833,22 +976,22 @@ inline fun testChannelOnly(f: () -> Unit) { * 倒计时,单位s */ inline fun countDownTimer( - timeInSeconds: Long, - crossinline block: (finish: Boolean, remainingTime: 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 < timeInSeconds) { - block.invoke(false, timeInSeconds - it) - } else { - block.invoke(true, 0) - if (subscribe != null && !subscribe!!.isDisposed) { - subscribe?.dispose() - } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + if (it < timeInSeconds) { + block.invoke(false, timeInSeconds - it) + } else { + block.invoke(true, 0) + if (subscribe != null && !subscribe!!.isDisposed) { + subscribe?.dispose() } } + } return subscribe } @@ -857,17 +1000,17 @@ inline fun countDownTimer( * @start 起始时间 */ inline fun countUpTimer( - start: Long, - period: Long = 1000, - crossinline block: (millisUntilFinished: Long) -> Unit + start: Long, + period: Long = 1000, + crossinline block: (millisUntilFinished: Long) -> Unit ): Disposable { var startTime = start return Observable.interval(0, period, TimeUnit.MILLISECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - startTime += period - block.invoke(startTime) - } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + startTime += period + block.invoke(startTime) + } } /** @@ -875,10 +1018,10 @@ inline fun countUpTimer( */ inline fun rxTimer(interval: Long, crossinline block: (times: Long) -> Unit): Disposable { return Observable.interval(0, interval, TimeUnit.MILLISECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - block.invoke(it) - } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + block.invoke(it) + } } fun LottieAnimationView.doOnAnimationEnd(action: () -> Unit) { @@ -944,13 +1087,17 @@ fun List?.checkSameFromStringArray(check2: List?): Boolean { fun EditText.showKeyBoard() { this.postDelayed({ this.requestFocus() - val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + val inputMethodManager = + context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager inputMethodManager.showSoftInput(this, 0) }, 300) } -fun SeekBar.doOnSeekBarChangeListener(progressChange: ((progress: Int) -> Unit)? = null, onStopTrackingTouch: (() -> Unit)? = null) { +fun SeekBar.doOnSeekBarChangeListener( + progressChange: ((progress: Int) -> Unit)? = null, + onStopTrackingTouch: (() -> Unit)? = null +) { this.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { progressChange?.invoke(progress) @@ -969,14 +1116,22 @@ fun SeekBar.doOnSeekBarChangeListener(progressChange: ((progress: Int) -> Unit)? fun observableToMain(): ObservableTransformer { return ObservableTransformer { upstream -> upstream.subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(AndroidSchedulers.mainThread()) } } fun singleToMain(): SingleTransformer { return SingleTransformer { upstream -> upstream.subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(AndroidSchedulers.mainThread()) + } +} + +fun clickToastByStatus(status: String, action: () -> Unit) { + when (status) { + "pending" -> ToastUtils.showToast("内容审核中") + "fail" -> ToastUtils.showToast("内容审核不通过") + else -> action.invoke() } } @@ -985,4 +1140,13 @@ fun View.getBitmapFromView(): Bitmap? { val canvas = Canvas(bitmap) this.draw(canvas) return bitmap +} + +fun String.hexStringToIntColor(): Int { + val colorStr = if (this.length == 9) { + "#${this.substring(3)}" + } else this + return if (colorStr.length >= 7) { + Color.parseColor(colorStr) + } else Color.WHITE } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/FloatingBackViewManager.kt b/app/src/main/java/com/gh/common/util/FloatingBackViewManager.kt index 63267352ed..d3cd027587 100644 --- a/app/src/main/java/com/gh/common/util/FloatingBackViewManager.kt +++ b/app/src/main/java/com/gh/common/util/FloatingBackViewManager.kt @@ -90,6 +90,7 @@ object FloatingBackViewManager { /** * 隐藏返回小浮窗 */ + @JvmStatic fun dismissBackView(activity: Activity) { EasyFloat.dismiss(activity, FLOATING_BACK_VIEW) } @@ -113,9 +114,17 @@ object FloatingBackViewManager { * @param type 类型 * @param activityUrl 类型为活动的时候用的地址 */ + @JvmStatic fun disableBackView() { mType = "" mActivityUrl = "" } + /** + * 返回小浮窗类型是否为活动 + */ + fun isTypeActivity() : Boolean { + return mType == TYPE_ACTIVITY + } + } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/GameSubstituteRepositoryHelper.kt b/app/src/main/java/com/gh/common/util/GameSubstituteRepositoryHelper.kt index 0e73d3dfe2..c8c6a22bc7 100644 --- a/app/src/main/java/com/gh/common/util/GameSubstituteRepositoryHelper.kt +++ b/app/src/main/java/com/gh/common/util/GameSubstituteRepositoryHelper.kt @@ -93,6 +93,13 @@ object GameSubstituteRepositoryHelper { val game = collection.data?.find { game -> isThisGameUnique(game, gameIdList) } game?.let { collection.data?.remove(game) + + collection.data?.size?.let { remainingSize -> + // 记录被替换游戏的数量,10个以上的时候触发 + if (remainingSize % 10 == 0) { + SentryHelper.onEvent("game_substitute", "substituted_size", "${50 - remainingSize}") + } + } // 产品说要记录补充专题的曝光数,所以这个游戏附带了所在专题的名字 game.subjectName = collection.name return game diff --git a/app/src/main/java/com/gh/common/util/GameUtils.java b/app/src/main/java/com/gh/common/util/GameUtils.java index 90e368995e..dfeeade1e3 100644 --- a/app/src/main/java/com/gh/common/util/GameUtils.java +++ b/app/src/main/java/com/gh/common/util/GameUtils.java @@ -19,6 +19,7 @@ import com.gh.gamecenter.entity.SettingsEntity; import com.gh.gamecenter.manager.PackagesManager; import com.lightgame.download.DownloadEntity; import com.lightgame.download.DownloadStatus; +import com.lightgame.utils.Utils; import java.util.ArrayList; import java.util.List; @@ -225,6 +226,8 @@ public class GameUtils { gameUpdateEntity.setIndexPlugin(gameEntity.getIndexPlugin()); gameUpdateEntity.setPluginDesc(gameEntity.getPluginDesc()); gameUpdateEntity.setFormat(apkEntity.getFormat()); + gameUpdateEntity.setCurrentVersion(PackageUtils.getVersionNameByPackageName(apkEntity.getPackageName())); + gameUpdateEntity.setCategory(gameEntity.getCategory()); GameCollectionEntity pluggableCollection = getPluggableCollectionFromGameEntity(gameEntity, apkEntity.getPackageName()); if (pluggableCollection != null) { @@ -269,5 +272,4 @@ public class GameUtils { } return null; } - } diff --git a/app/src/main/java/com/gh/common/util/HomePluggableHelper.kt b/app/src/main/java/com/gh/common/util/HomePluggableHelper.kt index 1e87908ee1..6d3ccef881 100644 --- a/app/src/main/java/com/gh/common/util/HomePluggableHelper.kt +++ b/app/src/main/java/com/gh/common/util/HomePluggableHelper.kt @@ -5,6 +5,9 @@ import com.gh.gamecenter.entity.HomePluggableFilterEntity import com.gh.gamecenter.room.AppDatabase import com.halo.assistant.HaloApp +/** + * 首页插件化区域辅助类 + */ object HomePluggableHelper { private val mHomePluggableFilterDao = AppDatabase.getInstance(HaloApp.getInstance().application).homePluggableFilterDao() @@ -56,7 +59,7 @@ object HomePluggableHelper { } } catch (e: Exception) { e.printStackTrace() - toastInInternalRelease("数据库/磁盘已满,插件筛选失败") + toastInInternalRelease("插件化筛选出现异常") } } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/ImageUtils.kt b/app/src/main/java/com/gh/common/util/ImageUtils.kt index e467e58530..8b04fbad33 100644 --- a/app/src/main/java/com/gh/common/util/ImageUtils.kt +++ b/app/src/main/java/com/gh/common/util/ImageUtils.kt @@ -312,7 +312,7 @@ object ImageUtils { if (url == null) return // 部分自适应宽高图片需要一个 TARGET_WIDTH 来避免加载过小图片 - val width = (view?.getTag(TARGET_WIDTH) as? Int) ?: view?.layoutParams?.width + val width = (view?.getTag(TARGET_WIDTH) as? Int) ?: view?.width?.coerceAtLeast(view.layoutParams?.width ?: 0) val height = view?.layoutParams?.height var lowResUrl = "" diff --git a/app/src/main/java/com/gh/common/util/InstallUtils.java b/app/src/main/java/com/gh/common/util/InstallUtils.java index 4e8fb3fd42..0a438acd58 100644 --- a/app/src/main/java/com/gh/common/util/InstallUtils.java +++ b/app/src/main/java/com/gh/common/util/InstallUtils.java @@ -64,7 +64,7 @@ public class InstallUtils { keys.add(packageName); DownloadEntity downloadEntity = DownloadManager.getInstance(context).getDownloadEntityByPackageName(packageName); - String installVersion = PackageUtils.getVersionByPackage(packageName); + String installVersion = PackageUtils.getVersionNameByPackageName(packageName); if (!TextUtils.isEmpty(installVersion) && downloadEntity != null && installVersion.equals(downloadEntity.getVersionName())) { if (!downloadEntity.isPluggable() || PackageUtils.isSignedByGh(context, packageName)) { diff --git a/app/src/main/java/com/gh/common/util/LibaoUtils.java b/app/src/main/java/com/gh/common/util/LibaoUtils.java index d59efd571e..49d808a5ec 100644 --- a/app/src/main/java/com/gh/common/util/LibaoUtils.java +++ b/app/src/main/java/com/gh/common/util/LibaoUtils.java @@ -257,17 +257,19 @@ public class LibaoUtils { ("ling".equals(beforeStatus) || "tao".equals(beforeStatus))) { //检查是否到了重复领取时间 if (isCanLing(libaoEntity)) { if ("ling".equals(beforeStatus)) { - return "repeatLinged"; // 可以重复领取 + status = "repeatLinged"; // 可以重复领取 } else { - return "repeatTaoed"; // 可以重复领取 + status = "repeatTaoed"; // 可以重复领取 } } else { if ("ling".equals(beforeStatus)) { - return "repeatLing"; // 预备重复领取 + status = "repeatLing"; // 预备重复领取 } else { - return "repeatTao"; // 预备重复领取 + status = "repeatTao"; // 预备重复领取 } } + libaoEntity.setStatus(status); + return status; } } return status; @@ -289,9 +291,10 @@ public class LibaoUtils { } public static void initLibaoBtn(final Context context, final TextView libaoBtn, final LibaoEntity libaoEntity, - final boolean isInstallRequired, final LibaoDetailAdapter adapter, boolean shouldUpdateStatus, final String entrance) { - String status = libaoEntity.getStatus(); + final boolean isInstallRequired, final LibaoDetailAdapter adapter, boolean shouldUpdateStatus, + final String entrance, final OnLibaoStatusChangeListener listener) { setLiBaoBtnStatusRound(libaoBtn, libaoEntity, shouldUpdateStatus, context); + String status = libaoEntity.getStatus(); if (adapter != null) { if (libaoBtn.getText().toString().equals("再领")) { @@ -307,7 +310,7 @@ public class LibaoUtils { // 领取限制 CheckLoginUtils.checkLogin(context, "礼包详情-[" + btnStatus + "]", () -> { if ("领取".equals(btnStatus) || "淘号".equals(btnStatus)) { - if (isInstallRequired && !isAppInstalled(context, libaoEntity.getPackageName())) { + if (isInstallRequired && !isAppInstalled(context, libaoEntity.getPackageName()) && adapter != null) { String platform; if (TextUtils.isEmpty(libaoEntity.getPlatform())) { platform = ""; @@ -353,24 +356,23 @@ public class LibaoUtils { case "再领一个": case "领取": if ("repeatLing".equals(status)) { - DialogUtils.showWarningDialog(context, "礼包刷新提醒" - , "礼包每天0点刷新,换新区或者换新角色需要继续领取礼包的童鞋,请于明天0点之后回来即可[再领一个]" - , null, "知道了", null, null); + ToastUtils.showToast("礼包每天0点刷新,明日0点后可再领一个"); } else { - libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance); + libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, null, entrance, listener); } break; case "再淘": case "再淘一个": case "淘号": - libaoTao(context, libaoBtn, libaoEntity, isInstallRequired, adapter, status, entrance); + libaoTao(context, libaoBtn, libaoEntity, isInstallRequired, adapter, status, entrance, listener); break; } }); }); } - private static void libaoTao(Context context, TextView libaoBtn, LibaoEntity libaoEntity, boolean isInstallRequired, LibaoDetailAdapter adapter, String status, String entrance) { + private static void libaoTao(Context context, TextView libaoBtn, LibaoEntity libaoEntity, boolean isInstallRequired, LibaoDetailAdapter adapter, + String status, String entrance, final OnLibaoStatusChangeListener listener) { if ("repeatTao".equals(status)) { Utils.toast(context, "没到重复淘号时间, 礼包每天0点刷新"); return; @@ -411,30 +413,21 @@ public class LibaoUtils { } return; } - Utils.toast(context, "淘号成功"); libaoEntity.setStatus("taoed"); + initLibaoCode(libaoEntity, new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context))); + if (adapter != null) { + adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context))); + } EventBus.getDefault().post(new EBReuse("libaoChanged")); - adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "tao", Utils.getTime(context))); + if (listener != null) listener.onLibaoStatusChange(); uploadEvent(libaoEntity, true, entrance); - final String finalLibaoCode = libaoCode; String des; if (!hasSame) { - des = "淘到的礼包码不保证可以兑换,请尽快前往游戏兑换"; + des = "淘号成功,请进入礼包详情查看兑换方法"; } else { - des = "您已领取过相同的礼包,可能无法成功兑换,请自行尝试"; + des = "您已领取过相同的礼包,可能无法成功兑换"; } - DialogUtils.showReceiveLibaoSuccessDialog(context, "淘号成功", des, finalLibaoCode, () -> { - copyLink(finalLibaoCode, context); - if (isInstallRequired) { - libaoBtn.postDelayed(() -> { - Spanned msg = Html.fromHtml( - context.getString(R.string.taoed_copy_dialog - , finalLibaoCode)); - lunningAppDialog(context - , msg, libaoEntity); - }, 300); - } - }); + ToastUtils.showToast(des); } @Override @@ -495,7 +488,7 @@ public class LibaoUtils { } private static void libaoLing(final Context context, final TextView libaoBtn, final LibaoEntity libaoEntity, final LibaoDetailAdapter adapter, - final boolean isInstallRequired, String captchaCode, final String entrance) { + final boolean isInstallRequired, String captchaCode, final String entrance, final OnLibaoStatusChangeListener listener) { if (BuildConfig.DEBUG) { Log.e("LIBAO", "context? " + context + libaoBtn.getContext()); @@ -525,37 +518,26 @@ public class LibaoUtils { } libaoEntity.setAvailable(libaoEntity.getAvailable() - 1); libaoEntity.setStatus("linged"); + initLibaoCode(libaoEntity, new UserDataLibaoEntity(libaoCode, "ling", Utils.getTime(context))); + if (listener != null) listener.onLibaoStatusChange(); EventBus.getDefault().post(new EBReuse("libaoChanged")); uploadEvent(libaoEntity, false, entrance); - adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "ling", Utils.getTime(context))); - adapter.notifyDataSetChanged(); - final String finalLibaoCode = libaoCode; + if (adapter != null) { + adapter.initLibaoCode(new UserDataLibaoEntity(libaoCode, "ling", Utils.getTime(context))); + adapter.notifyDataSetChanged(); + } boolean finalHasSame = hasSame; - int finalGameApkSize = gameApkSize; NotificationHelper.showNotificationHintDialog(NotificationUgc.GIFT, isShow -> { if (!isShow) { String des; if (!finalHasSame) { - if (finalGameApkSize > 1) { - des = "礼包码将于60分钟后进入淘号池,部分礼包兑换有平台限制,请根据使用说明兑换"; - } else { - des = "礼包码将于60分钟后进入淘号池,请尽快前往游戏兑换"; - } + des = "领取成功,请进入礼包详情查看兑换方法"; } else { - des = "您已领取过相同的礼包,可能无法成功兑换,请自行尝试"; + des = "您已领取过相同的礼包,可能无法成功兑换"; } - DialogUtils.showReceiveLibaoSuccessDialog(context, "领取成功", des, finalLibaoCode, () -> { - copyLink(finalLibaoCode, context); - if (isInstallRequired) { - libaoBtn.postDelayed(() -> { - Spanned msg = Html.fromHtml(context.getString(R.string.linged_copy_dialog, finalLibaoCode)); - lunningAppDialog(context - , msg, libaoEntity); - }, 300); - } - }); + ToastUtils.showToast(des); } return null; }); @@ -601,7 +583,7 @@ public class LibaoUtils { DialogUtils.showHintDialog(context, "礼包已领光" , "手速不够快,礼包已经被抢光了,十分抱歉", "知道了"); libaoEntity.setStatus("used_up"); - initLibaoBtn(context, libaoBtn, libaoEntity, isInstallRequired, adapter, false, entrance); + initLibaoBtn(context, libaoBtn, libaoEntity, isInstallRequired, adapter, false, entrance, listener); break; case "maintaining": Utils.toast(context, "网络状态异常,请稍后再试"); @@ -618,7 +600,7 @@ public class LibaoUtils { } else if (exception.code() == 412) { // 需要验证 GeetestUtils.getInstance().showDialog(context, captcha -> - libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, captcha, entrance)); + libaoLing(context, libaoBtn, libaoEntity, adapter, isInstallRequired, captcha, entrance, listener)); return; } else if (exception.code() == 401) { return; @@ -629,6 +611,22 @@ public class LibaoUtils { }, captchaCode); } + public static void initLibaoCode(LibaoEntity libaoEntity, UserDataLibaoEntity userDataLibaoEntity) { + MeEntity userData = libaoEntity.getMe(); + if (userData == null) { + userData = new MeEntity(); + libaoEntity.setMe(userData); + } + + List userDataLibaoList = userData.getUserDataLibaoList(); + if (userDataLibaoList == null) { + userDataLibaoList = new ArrayList<>(); + userData.setUserDataLibaoList(userDataLibaoList); + } + userDataLibaoList.add(userDataLibaoEntity); + + } + private static void uploadEvent(LibaoEntity libaoEntity, boolean isTao, String entrance) { String location = ""; if (!libaoEntity.getClickReceiveBtnIn()) { @@ -738,4 +736,8 @@ public class LibaoUtils { void postFailed(Throwable error); } + + public interface OnLibaoStatusChangeListener { + void onLibaoStatusChange(); + } } diff --git a/app/src/main/java/com/gh/common/util/LogUtils.java b/app/src/main/java/com/gh/common/util/LogUtils.java index 7710b9e81f..259493edfd 100644 --- a/app/src/main/java/com/gh/common/util/LogUtils.java +++ b/app/src/main/java/com/gh/common/util/LogUtils.java @@ -262,7 +262,7 @@ public class LogUtils { Context context = HaloApp.getInstance().getApplication(); try { - object.put("version", PackageUtils.getVersionName()); + object.put("version", PackageUtils.getGhVersionName()); object.put("channel", HaloApp.getInstance().getChannel()); object.put("dia", MetaUtil.getBase64EncodedAndroidId()); object.put("time", Utils.getTime(context)); @@ -287,7 +287,7 @@ public class LogUtils { private static void uploadToReservation(JSONObject object) { Context context = HaloApp.getInstance().getApplication(); try { - object.put("version", PackageUtils.getVersionName()); + object.put("version", PackageUtils.getGhVersionName()); object.put("channel", HaloApp.getInstance().getChannel()); object.put("dia", MetaUtil.getBase64EncodedAndroidId()); object.put("time", Utils.getTime(context)); diff --git a/app/src/main/java/com/gh/common/util/LoginHelper.kt b/app/src/main/java/com/gh/common/util/LoginHelper.kt index 69cd9e5dd8..a189bf3aed 100644 --- a/app/src/main/java/com/gh/common/util/LoginHelper.kt +++ b/app/src/main/java/com/gh/common/util/LoginHelper.kt @@ -8,12 +8,11 @@ import com.gh.gamecenter.user.LoginTag import com.halo.assistant.HaloApp import com.lightgame.utils.RuntimeUtils import com.lightgame.utils.Utils -import com.sina.weibo.sdk.WbSdk import com.sina.weibo.sdk.auth.AuthInfo import com.sina.weibo.sdk.auth.Oauth2AccessToken import com.sina.weibo.sdk.auth.WbAuthListener -import com.sina.weibo.sdk.auth.WbConnectErrorMessage -import com.sina.weibo.sdk.auth.sso.SsoHandler +import com.sina.weibo.sdk.openapi.IWBAPI +import com.sina.weibo.sdk.openapi.WBAPIFactory import com.tencent.mm.opensdk.modelmsg.SendAuth import com.tencent.mm.opensdk.openapi.IWXAPI import com.tencent.mm.opensdk.openapi.WXAPIFactory @@ -24,6 +23,7 @@ import org.json.JSONException import org.json.JSONObject import java.lang.ref.WeakReference + /** * 第三方登录辅助类 */ @@ -36,7 +36,7 @@ object LoginHelper { private var mTencent: Tencent // QQ private var mIWXAPI: IWXAPI // 微信 - private var mSsoHandler: WeakReference? = null // 微博 + private lateinit var mWBAPI: IWBAPI // 微博 private var mQqLoginListener: IUiListener @@ -56,11 +56,17 @@ object LoginHelper { Utils.log("QQLoginComplete::$s") try { mTencent.openId = o.getString("openid") - mTencent.setAccessToken(o.getString("access_token"), o.getString("expires_in")) + mTencent.setAccessToken( + o.getString("access_token"), + o.getString("expires_in") + ) val content = JSONObject() content.put("openid", o.getString("openid")) - content.put("access_token_expire", Utils.getTime(context) + o.getLong("expires_in")) + content.put( + "access_token_expire", + Utils.getTime(context) + o.getLong("expires_in") + ) content.put("access_token", o.getString("access_token")) mLoginCallback?.get()?.onLoginSuccess(LoginTag.qq, content) // 回调QQ登录成功 @@ -87,7 +93,6 @@ object LoginHelper { } - // DouYinOpenApiFactory.init(DouYinOpenConfig(Config.DOUYIN_CLIENTKEY)) Utils.log("LoginHelper initialization") @@ -120,7 +125,7 @@ object LoginHelper { @JvmStatic fun onWeiboLoginCallback(requestCode: Int, resultCode: Int, data: Intent?) { - mSsoHandler?.get()?.authorizeCallBack(requestCode, resultCode, data) + mWBAPI.authorizeCallback(requestCode, resultCode, data) } // QQ登录 @@ -160,12 +165,14 @@ object LoginHelper { // 微博登录 @JvmStatic fun loginWithWeibo(loginCallback: LoginCallback, context: Activity) { - WbSdk.install(context, AuthInfo(context, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE)) - + mWBAPI = WBAPIFactory.createWBAPI(context) //初始化微博分享 mLoginCallback = WeakReference(loginCallback) - mSsoHandler = WeakReference(SsoHandler(context)) - mSsoHandler?.get()?.authorizeClientSso(object : WbAuthListener { - override fun onSuccess(token: Oauth2AccessToken?) { + mWBAPI.registerApp( + context, + AuthInfo(context, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE) + ) + mWBAPI.authorizeClient(object : WbAuthListener { + override fun onComplete(token: Oauth2AccessToken?) { token?.let { RuntimeUtils.getInstance().runOnUiThread { mAccessToken = token @@ -179,8 +186,12 @@ object LoginHelper { val content = JSONObject() tryWithDefaultCatch { content.put("uid", token.uid) - content.put("access_token", token.token) - content.put("access_token_expire", Utils.getTime(context) + token.expiresTime) + content.put("userName", token.screenName) + content.put("access_token", token.accessToken) + content.put( + "access_token_expire", + Utils.getTime(context) + token.expiresTime + ) content.put("refresh_token", token.refreshToken) // content.put("refresh_token_expire", Utils.getTime(mContext) + 86400 * 30); // refresh_token 有效期30天 mLoginCallback?.get()?.onLoginSuccess(LoginTag.weibo, content)// 微博 登录回调 @@ -188,14 +199,16 @@ object LoginHelper { } } - override fun onFailure(p0: WbConnectErrorMessage?) { + override fun onError(error: com.sina.weibo.sdk.common.UiError?) { mLoginCallback?.get()?.onLoginFailure(LoginTag.weibo, "微博登录需要客户端支持,请先安装微博") } - override fun cancel() { + override fun onCancel() { mLoginCallback?.get()?.onLoginFailure(LoginTag.weibo, "取消授权") } + }) + // 第一次启动本应用,AccessToken 不可用 mAccessToken = AccessTokenKeeper.readAccessToken(context) } diff --git a/app/src/main/java/com/gh/common/util/MessageShareUtils.java b/app/src/main/java/com/gh/common/util/MessageShareUtils.java index 62722a16d1..26e52e1ea8 100644 --- a/app/src/main/java/com/gh/common/util/MessageShareUtils.java +++ b/app/src/main/java/com/gh/common/util/MessageShareUtils.java @@ -11,11 +11,6 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; - -import androidx.core.content.ContextCompat; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - import android.util.Base64; import android.view.Gravity; import android.view.KeyEvent; @@ -27,13 +22,15 @@ import android.widget.PopupWindow; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import com.gh.common.Base64ImageHolder; import com.gh.common.constant.Config; import com.gh.gamecenter.R; import com.gh.gamecenter.WeiBoShareActivity; import com.lightgame.utils.Utils; -import com.sina.weibo.sdk.WbSdk; -import com.sina.weibo.sdk.auth.AuthInfo; import com.tencent.connect.auth.QQToken; import com.tencent.connect.share.QQShare; import com.tencent.mm.opensdk.modelmsg.SendMessageToWX; @@ -53,8 +50,6 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.util.Date; -import static com.gh.common.util.LoginHelper.WEIBO_SCOPE; - /** * Created by khy on 2016/11/8. */ @@ -284,23 +279,23 @@ public class MessageShareUtils { // 分享 switch (type) { - case "qq" : + case "qq": shareWay = ShareWay.qq; qqShare(); break; - case "qq_zone" : + case "qq_zone": shareWay = ShareWay.qqZone; qZoneShare(); break; - case "wechat" : + case "wechat": shareWay = ShareWay.wechat; wechatShare(); break; - case "wechat_moments" : + case "wechat_moments": shareWay = ShareWay.wechatMoments; wechatMomentsShare(); break; - case "save" : + case "save": String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/ghzhushou/"; writeBitmap(savePath, "gh-" + new Date().getTime() + ".jpg", shareBm, true); break; @@ -414,8 +409,6 @@ public class MessageShareUtils { //新浪微博分享 public void weiboShare() { - WbSdk.install(mContext, new AuthInfo(mContext, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE)); - Activity activity = mActivity.get(); if (activity != null) { Intent intent = WeiBoShareActivity.getWeiboImageShareIntent(activity); diff --git a/app/src/main/java/com/gh/common/util/NewLogUtils.kt b/app/src/main/java/com/gh/common/util/NewLogUtils.kt index ed034e2167..ab9f17d00b 100644 --- a/app/src/main/java/com/gh/common/util/NewLogUtils.kt +++ b/app/src/main/java/com/gh/common/util/NewLogUtils.kt @@ -41,15 +41,15 @@ object NewLogUtils { @SuppressLint("CheckResult") fun logForumContentBrowser(contentId: String, contentType: String) { val requestBody = hashMapOf( - Pair("content_id", contentId), - Pair("content_type", contentType) + Pair("content_id", contentId), + Pair("content_type", contentType) ).createRequestBody() RetrofitManager.getInstance(HaloApp.getInstance()) - .api - .postBrowses(requestBody) - .subscribeOn(Schedulers.io()) - .subscribe(EmptyResponse()) + .api + .postBrowses(requestBody) + .subscribeOn(Schedulers.io()) + .subscribe(EmptyResponse()) } // 游戏详情点击顶部标签 @@ -465,7 +465,7 @@ object NewLogUtils { fun logShareTypeClick(shareType: String) { val json = json { "location" to "分享面板" - "event" to "view_detail_share_panel" + "event" to "share_type" "meta" to LogUtils.getMetaObject() "share_type" to shareType "launch_id" to Tracker.launchId @@ -475,6 +475,21 @@ object NewLogUtils { log(json, "bbs_community", false) } + //分享结果 + @JvmStatic + fun logShareResult(shareResult: Boolean){ + val json = json { + "location" to "分享面板" + "event" to "share_result" + "meta" to LogUtils.getMetaObject() + "share_success" to shareResult + "launch_id" to Tracker.launchId + "session_id" to Tracker.sessionId + "timestamp" to System.currentTimeMillis() / 1000 + } + log(json, "bbs_community", false) + } + //分享面板点击 fun logSharePanelClick(event: String, userId: String, contentType: String, contentId: String, bbsId: String, bbsType: String) { val json = json { @@ -1113,4 +1128,45 @@ object NewLogUtils { } log(json, "bbs_community", false) } + + //出现引导浮窗 + fun logGuidePopShow(guideId: String){ + val json = json { + "event" to "guide_pop_show" + "payload" to json { + "guide_pop_id" to guideId + } + "meta" to LogUtils.getMetaObject() + "timestamp" to System.currentTimeMillis() / 1000 + } + log(json,"event",false) + } + + //关闭引导浮窗 + fun logGuidePopClose(guideId: String){ + val json = json { + "event" to "guide_pop_close" + "payload" to json { + "guide_pop_id" to guideId + } + "meta" to LogUtils.getMetaObject() + "timestamp" to System.currentTimeMillis() / 1000 + } + log(json,"event",false) + } + + //点击引导浮窗链接 + fun logGuidePopLinkClick(guideId: String, linkType: String? = "", linkTitle: String? = ""){ + val json = json { + "event" to "guide_pop_link_click" + "payload" to json { + "guide_pop_id" to guideId + "link_type" to linkType + "link_title" to linkTitle + } + "meta" to LogUtils.getMetaObject() + "timestamp" to System.currentTimeMillis() / 1000 + } + log(json,"event",false) + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/util/NotificationHelper.kt b/app/src/main/java/com/gh/common/util/NotificationHelper.kt index 22a34e3717..9d89443464 100644 --- a/app/src/main/java/com/gh/common/util/NotificationHelper.kt +++ b/app/src/main/java/com/gh/common/util/NotificationHelper.kt @@ -15,7 +15,7 @@ object NotificationHelper { @JvmStatic fun showNotificationHintDialog(ugc: NotificationUgc, callBack: ((isShow: Boolean) -> Unit)? = null) { val showedNewVersion = SPUtils.getInt(Constants.SP_SHOWED_NOTIFICATION_NEW_VERSION, 0) - val currentVersion = PackageUtils.getVersionCode() + val currentVersion = PackageUtils.getGhVersionCode() // 版本升级后重置数据 if (currentVersion > showedNewVersion) { SPUtils.setBoolean(Constants.SP_SHOWED_NOTIFICATION_LOGIN, false) diff --git a/app/src/main/java/com/gh/common/util/PackageInstaller.kt b/app/src/main/java/com/gh/common/util/PackageInstaller.kt index a59453478e..3a23b350d1 100644 --- a/app/src/main/java/com/gh/common/util/PackageInstaller.kt +++ b/app/src/main/java/com/gh/common/util/PackageInstaller.kt @@ -1,7 +1,6 @@ package com.gh.common.util import android.app.Activity -import android.app.Application import android.content.Context import android.content.Intent import android.net.Uri @@ -46,7 +45,7 @@ object PackageInstaller { // TODO 此处可能遇到 activity 是 WXEntryActivity // TODO 当 activity 全部出栈,但是应用还在下载游戏,下载完会唤不起安装! - if (currentActivity is AppCompatActivity) { + if (currentActivity is AppCompatActivity && !currentActivity.isFinishing) { InstallPermissionDialogFragment.show(currentActivity, downloadEntity) { // 取消状态栏下载完成的通知,若存在 downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES" @@ -125,7 +124,7 @@ object PackageInstaller { // 应用内更新不加 FLAG_ACTIVITY_NEW_TASK 在模拟器上会出现安装完成后安装界面也一并消失的类似闪退的表现 // Application 上下文就更不用说了 val pkgName = PackageUtils.getPackageNameByPath(context, path) - if (pkgName == context.packageName || context is Application) { + if (pkgName == context.packageName || context !is Activity) { installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } installIntent.setDataAndType(uri, "application/vnd.android.package-archive") diff --git a/app/src/main/java/com/gh/common/util/PackageUtils.java b/app/src/main/java/com/gh/common/util/PackageUtils.java index b9153f6fac..fd1187abdd 100644 --- a/app/src/main/java/com/gh/common/util/PackageUtils.java +++ b/app/src/main/java/com/gh/common/util/PackageUtils.java @@ -45,7 +45,9 @@ import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -83,6 +85,9 @@ public class PackageUtils { updateEntity.setIndexPlugin(gameEntity.getIndexPlugin()); updateEntity.setPluginDesc(gameEntity.getPluginDesc()); updateEntity.setFormat(apkEntity.getFormat()); + updateEntity.setSignature(apkEntity.getSignature()); + updateEntity.setCategory(gameEntity.getCategory()); + updateEntity.setCurrentVersion(PackageUtils.getVersionNameByPackageName(apkEntity.getPackageName())); updateList.add(updateEntity); } } @@ -92,8 +97,10 @@ public class PackageUtils { // ghVersion 不存在即是非插件游戏 if (TextUtils.isEmpty(apkEntity.getGhVersion())) { + int versionCodeFromRequest = apkEntity.getVersionCode(); + int versionCodeFromInstalledApp = getVersionCodeByPackageName(apkEntity.getPackageName()); String versionFromRequest = apkEntity.getVersion(); - String versionFromInstalledApp = getVersionByPackage(apkEntity.getPackageName()); + String versionFromInstalledApp = getVersionNameByPackageName(apkEntity.getPackageName()); // 是否需要显示更新 boolean shouldShowUpdate = apkEntity.getForce(); @@ -103,6 +110,11 @@ public class PackageUtils { // 根据版本判断是否需要更新 shouldShowUpdate = new Version(versionFromRequest).isHigherThan(versionFromInstalledApp); + // versionName 没法判定的时候尝试使用 versionCode 去判断 + if (!shouldShowUpdate && versionCodeFromRequest != 0) { + shouldShowUpdate = versionCodeFromRequest > versionCodeFromInstalledApp; + } + if (shouldShowUpdate) { GameUpdateEntity updateEntity = new GameUpdateEntity(); updateEntity.setId(gameEntity.getId()); @@ -121,6 +133,9 @@ public class PackageUtils { updateEntity.setIndexPlugin(gameEntity.getIndexPlugin()); updateEntity.setPluginDesc(gameEntity.getPluginDesc()); updateEntity.setFormat(apkEntity.getFormat()); + updateEntity.setSignature(apkEntity.getSignature()); + updateEntity.setCategory(gameEntity.getCategory()); + updateEntity.setCurrentVersion(PackageUtils.getVersionNameByPackageName(apkEntity.getPackageName())); updateList.add(updateEntity); } } @@ -158,6 +173,42 @@ public class PackageUtils { return getMetaData(HaloApp.getInstance().getApplication(), packageName, "gh_id"); } + @Nullable + public static Map getSideLoadedInfo() { + Context context = HaloApp.getInstance().getApplicationContext(); + + String packageName = null; + try { + final PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); + final PackageManager packageManager = context.getPackageManager(); + + if (packageInfo != null && packageManager != null) { + packageName = packageInfo.packageName; + + // getInstallSourceInfo requires INSTALL_PACKAGES permission which is only given to system + // apps. + final String installerPackageName = packageManager.getInstallerPackageName(packageName); + + final Map sideLoadedInfo = new HashMap<>(); + + if (installerPackageName != null) { + sideLoadedInfo.put("is_side_loaded", "false"); + // could be amazon, google play etc + sideLoadedInfo.put("installer_store", installerPackageName); + } else { + // if it's installed via adb, system apps or untrusted sources + sideLoadedInfo.put("is_side_loaded", "true"); + } + + return sideLoadedInfo; + } + } catch (Exception e) { + Utils.log(e.getLocalizedMessage()); + } + + return null; + } + /* * 判断是否是插件包 @@ -391,21 +442,21 @@ public class PackageUtils { /* * 返回光环助手的版本信息 */ - public static String getVersionName() { + public static String getGhVersionName() { return BuildConfig.VERSION_NAME; } /* * 返回光环助手的版本code */ - public static int getVersionCode() { + public static int getGhVersionCode() { return BuildConfig.VERSION_CODE; } /* - * 获取apk的版本 + * 获取apk的 versionName */ - public static String getVersionByPackage(String packageName) { + public static String getVersionNameByPackageName(String packageName) { try { return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionName; @@ -415,11 +466,24 @@ public class PackageUtils { return null; } + /* + * 获取apk的版本 versionCode + */ + public static int getVersionCodeByPackageName(String packageName) { + try { + return HaloApp.getInstance().getApplication().getPackageManager().getPackageInfo(packageName, + PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionCode; + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + return 0; + } + /* - * 获取apk的版本 + * 获取应用的 icon */ - public static Drawable getIconByPackage(Context context, String packageName) { + public static Drawable getIconByPackageName(Context context, String packageName) { try { PackageManager packageManager = context.getApplicationContext().getPackageManager(); return packageManager.getApplicationIcon(packageName); @@ -583,7 +647,7 @@ public class PackageUtils { // ghVersion 不存在即是非插件游戏 if (TextUtils.isEmpty(apkEntity.getGhVersion())) { String versionFromRequest = apkEntity.getVersion(); - String versionFromInstalledApp = getVersionByPackage(apkEntity.getPackageName()); + String versionFromInstalledApp = getVersionNameByPackageName(apkEntity.getPackageName()); // 是否需要显示更新 boolean shouldShowUpdate = apkEntity.getForce(); diff --git a/app/src/main/java/com/gh/common/util/ShareUtils.java b/app/src/main/java/com/gh/common/util/ShareUtils.java index 667eb403e4..bb5ea33dc5 100644 --- a/app/src/main/java/com/gh/common/util/ShareUtils.java +++ b/app/src/main/java/com/gh/common/util/ShareUtils.java @@ -31,8 +31,6 @@ import com.gh.gamecenter.WeiBoShareActivity; import com.gh.gamecenter.entity.ShareEntity; import com.gh.gamecenter.eventbus.EBShare; import com.lightgame.utils.Utils; -import com.sina.weibo.sdk.WbSdk; -import com.sina.weibo.sdk.auth.AuthInfo; import com.tencent.connect.share.QQShare; import com.tencent.connect.share.QzoneShare; import com.tencent.mm.opensdk.modelmsg.SendMessageToWX; @@ -51,8 +49,6 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; -import static com.gh.common.util.LoginHelper.WEIBO_SCOPE; - /** * Created by khy on 2016/9/4. */ @@ -148,6 +144,11 @@ public class ShareUtils { if (ShareUtils.shareEntrance == ShareEntrance.inviteFriends) { IntegralLogHelper.INSTANCE.logInviteResult("成功", mShareType.getName()); } + if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal || + ShareUtils.shareEntrance == ShareEntrance.communityArticle || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) { + NewLogUtils.logShareResult(true); + } } @Override @@ -158,6 +159,11 @@ public class ShareUtils { if (ShareUtils.shareEntrance == ShareEntrance.inviteFriends) { IntegralLogHelper.INSTANCE.logInviteResult("失败", mShareType.getName()); } + if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal || + ShareUtils.shareEntrance == ShareEntrance.communityArticle || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) { + NewLogUtils.logShareResult(false); + } } @Override @@ -168,6 +174,11 @@ public class ShareUtils { if (ShareUtils.shareEntrance == ShareEntrance.inviteFriends) { IntegralLogHelper.INSTANCE.logInviteResult("取消", mShareType.getName()); } + if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal || + ShareUtils.shareEntrance == ShareEntrance.communityArticle || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) { + NewLogUtils.logShareResult(false); + } } }; @@ -175,7 +186,6 @@ public class ShareUtils { mContext = context.getApplicationContext(); mTencent = Tencent.createInstance(Config.TENCENT_APPID, mContext); //初始化QQ分享 mIWXAPI = WXAPIFactory.createWXAPI(mContext, Config.WECHAT_APPID); //初始化微信分享 - } public static ShareUtils getInstance(Context context) { @@ -215,23 +225,23 @@ public class ShareUtils { // 分享 switch (way) { - case "qq" : + case "qq": mShareType = ShareType.qq; qqShare(); break; - case "qq_zone" : + case "qq_zone": mShareType = ShareType.qqZone; qZoneShare(); break; - case "wechat" : + case "wechat": mShareType = ShareType.wechat; wechatShare(); break; - case "wechat_moments" : + case "wechat_moments": mShareType = ShareType.wechatMoments; wechatMomentsShare(); break; - case "weibo" : + case "weibo": mShareType = ShareType.weibo; sinaWeiboShare(); break; @@ -665,8 +675,6 @@ public class ShareUtils { shareType = "sina_weibo"; LogUtils.uploadShareType(shareType, shareEntrance.getName(), shareUrl, mTitle, mSummary, resourceId); - WbSdk.install(mContext, new AuthInfo(mContext, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE)); - if (mShareEntrance == ShareEntrance.qaDetail) { mTitle = "向你推荐:" + mTitle + " @光环助手 " + shareUrl; mSummary = ""; diff --git a/app/src/main/java/com/gh/common/util/SimpleRequestHelper.kt b/app/src/main/java/com/gh/common/util/SimpleRequestHelper.kt index af6ab3a6cf..bf9f29fc20 100644 --- a/app/src/main/java/com/gh/common/util/SimpleRequestHelper.kt +++ b/app/src/main/java/com/gh/common/util/SimpleRequestHelper.kt @@ -7,6 +7,7 @@ import com.lightgame.utils.Utils import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody +import org.json.JSONObject import retrofit2.HttpException /** @@ -23,11 +24,11 @@ object SimpleRequestHelper { .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Response() { override fun onResponse(response: ResponseBody?) { - Utils.toast(HaloApp.getInstance().application, "感谢您的投诉") + Utils.toast(HaloApp.getInstance().application, "举报成功") } override fun onFailure(e: HttpException?) { - ErrorHelper.handleError(HaloApp.getInstance().application, e?.response()?.errorBody()?.string()) + ErrorHelper.handleError(HaloApp.getInstance().application,e?.response()?.errorBody()?.string()) } }) @@ -41,11 +42,11 @@ object SimpleRequestHelper { .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Response() { override fun onResponse(response: ResponseBody?) { - Utils.toast(HaloApp.getInstance().application, "感谢您的投诉") + Utils.toast(HaloApp.getInstance().application, "举报成功") } override fun onFailure(e: HttpException?) { - ErrorHelper.handleError(HaloApp.getInstance().application, e?.response()?.errorBody()?.string()) + ErrorHelper.handleError(HaloApp.getInstance().application,e?.response()?.errorBody()?.string()) } }) diff --git a/app/src/main/java/com/gh/common/util/SpUtils.kt b/app/src/main/java/com/gh/common/util/SpUtils.kt index 0b7551873b..db004f46f2 100644 --- a/app/src/main/java/com/gh/common/util/SpUtils.kt +++ b/app/src/main/java/com/gh/common/util/SpUtils.kt @@ -23,7 +23,7 @@ object SPUtils { @JvmStatic fun getString(key: String): String { - return sp.getString(key, "")?:"" + return sp.getString(key, "") ?: "" } @JvmStatic @@ -81,19 +81,30 @@ object SPUtils { return context.getSharedPreferences("Halo", Context.MODE_PRIVATE).getBoolean(key, defaultValue) } + /** + * 使用传入的 SP 来存储 KV + */ @JvmStatic - fun setString(sp: SharedPreferences, key: String, value: String? = null) { + fun setString(sharedPreferences: SharedPreferences, key: String, value: String? = null) { try { - val commitStatus = sp.edit().putString(key, value).commit() + val commitStatus = sharedPreferences.edit().putString(key, value).commit() if (!commitStatus) { - sp.edit().putString(key, value).apply() + sharedPreferences.edit().putString(key, value).apply() } } catch (e: Exception) { e.printStackTrace() - sp.edit().putString(key, value).apply() + sharedPreferences.edit().putString(key, value).apply() } } + /** + * 使用传入的 SP 来读取 KV + */ + @JvmStatic + fun getString(sharedPreferences: SharedPreferences, key: String, value: String? = null): String { + return sharedPreferences.getString(key, "") ?: "" + } + @JvmStatic fun setStringSet(key: String, values: Set) { sp.edit().putStringSet(key, values).apply() diff --git a/app/src/main/java/com/gh/common/util/SpanBuilder.kt b/app/src/main/java/com/gh/common/util/SpanBuilder.kt index dec35a5c5f..b8200f2271 100644 --- a/app/src/main/java/com/gh/common/util/SpanBuilder.kt +++ b/app/src/main/java/com/gh/common/util/SpanBuilder.kt @@ -3,6 +3,7 @@ package com.gh.common.util import android.content.Context import android.graphics.Color import android.graphics.Typeface +import android.graphics.drawable.Drawable import android.text.SpannableStringBuilder import android.text.Spanned import android.text.TextPaint @@ -70,6 +71,13 @@ class SpanBuilder(content: CharSequence) { return this } + //添加图标 + fun image(start: Int, end: Int, drawable: Drawable): SpanBuilder { + val imageSpan = CenterImageSpan(drawable) + spannableString.setSpan(imageSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + return this + } + fun click(start: Int, end: Int, colorRes: Int, isUnderlineText: Boolean = false, onClick: () -> Unit): SpanBuilder { val clickSpan = object : ClickableSpan() { override fun updateDrawState(ds: TextPaint) { diff --git a/app/src/main/java/com/gh/common/util/UploadImageUtils.kt b/app/src/main/java/com/gh/common/util/UploadImageUtils.kt index f95ab6885a..fac65dd176 100644 --- a/app/src/main/java/com/gh/common/util/UploadImageUtils.kt +++ b/app/src/main/java/com/gh/common/util/UploadImageUtils.kt @@ -27,6 +27,7 @@ import java.lang.Exception object UploadImageUtils { enum class UploadType { + community_article, question, answer, suggestion, diff --git a/app/src/main/java/com/gh/common/view/DrawableView.kt b/app/src/main/java/com/gh/common/view/DrawableView.kt index 4811b1f93c..e1a7f49674 100644 --- a/app/src/main/java/com/gh/common/view/DrawableView.kt +++ b/app/src/main/java/com/gh/common/view/DrawableView.kt @@ -112,6 +112,13 @@ object DrawableView { return drawable } + @JvmStatic + fun getGradientDrawable(startColor: Int, endColor: Int, orientation: GradientDrawable.Orientation = GradientDrawable.Orientation.LEFT_RIGHT, radius: Float = 999F): Drawable { + val drawable = GradientDrawable(orientation, intArrayOf(startColor, endColor)) + drawable.cornerRadius = DisplayUtils.dip2px(radius).toFloat() + return drawable + } + fun convertAlphaKey(percent: Int): String { val hexString = Integer.toHexString(Math.round((255 * percent / 100).toFloat())) return (if (hexString.length < 2) "0" else "") + hexString diff --git a/app/src/main/java/com/gh/common/view/OffsetLinearLayoutManager.kt b/app/src/main/java/com/gh/common/view/OffsetLinearLayoutManager.kt new file mode 100644 index 0000000000..cfc9a71f99 --- /dev/null +++ b/app/src/main/java/com/gh/common/view/OffsetLinearLayoutManager.kt @@ -0,0 +1,39 @@ +package com.gh.common.view + +import android.content.Context +import androidx.core.view.marginTop +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.util.dip2px +import java.util.* + +/** + * 重写computeVerticalScrollOffset,精确计算RecyclerView滑动距离 + */ +class OffsetLinearLayoutManager(context: Context?) : FixLinearLayoutManager(context) { + val heightMap = linkedMapOf() + override fun onLayoutCompleted(state: RecyclerView.State) { + super.onLayoutCompleted(state) + val count = childCount + for (i in 0 until count) { + val view = getChildAt(i) + heightMap[i] = view?.height ?: 0 + } + } + + override fun computeVerticalScrollOffset(state: RecyclerView.State): Int { + return if (childCount != 0) { + try { + val firstVisiablePosition = findFirstVisibleItemPosition() + val firstVisiableView = findViewByPosition(firstVisiablePosition) + var offsetY = -(firstVisiableView?.y ?: 0).toInt() + for (i in 0 until firstVisiablePosition) { + offsetY += (if (heightMap[i] == null) 0 else heightMap[i] ?: 0) + } + offsetY + } catch (e: Exception) { + 0 + } + } else 0 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/view/RichEditor.java b/app/src/main/java/com/gh/common/view/RichEditor.java index 0a80e4b6c7..fda2f83a94 100644 --- a/app/src/main/java/com/gh/common/view/RichEditor.java +++ b/app/src/main/java/com/gh/common/view/RichEditor.java @@ -11,7 +11,6 @@ import android.util.AttributeSet; import android.view.Gravity; import android.webkit.JavascriptInterface; import android.webkit.WebChromeClient; -import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; @@ -728,7 +727,7 @@ public class RichEditor extends WebView { @JavascriptInterface public int getAppVersionCode() { - return PackageUtils.getVersionCode(); + return PackageUtils.getGhVersionCode(); } /** diff --git a/app/src/main/java/com/gh/common/view/ScrollEventListener.kt b/app/src/main/java/com/gh/common/view/ScrollEventListener.kt new file mode 100644 index 0000000000..d1098bff63 --- /dev/null +++ b/app/src/main/java/com/gh/common/view/ScrollEventListener.kt @@ -0,0 +1,369 @@ +package com.gh.common.view + +import android.view.View +import android.view.ViewGroup +import android.view.ViewGroup.MarginLayoutParams +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.viewpager2.widget.ViewPager2 +import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback +import androidx.viewpager2.widget.ViewPager2.ScrollState + +/** + * 从 ViewPager2 源码摘抄的,更多细节可见 ScrollEventAdapter.java + */ +class ScrollEventListener(private val mRecyclerView: RecyclerView) : + RecyclerView.OnScrollListener() { + private annotation class AdapterState() + + private var mCallback: ViewPager2.OnPageChangeCallback? = null + private val mLayoutManager = (mRecyclerView.layoutManager as LinearLayoutManager) + + // state related fields + @AdapterState + private var mAdapterState: Int = 0 + + @ScrollState + var scrollState: Int = 0 + + private val mScrollValues: ScrollEventValues = ScrollEventValues() + private var mDragStartPosition: Int = 0 + private var mTarget: Int = 0 + private var mDispatchSelected: Boolean = false + private var mScrollHappened: Boolean = false + private var mDataSetChangeHappened: Boolean = false + + init { + resetState() + } + + /** + * @return `true` if a fake drag is ongoing. Returns `false` from the moment the + * [ViewPager2.endFakeDrag] is called. + */ + var isFakeDragging: Boolean = false + private set + + private fun resetState() { + mAdapterState = STATE_IDLE + scrollState = ViewPager2.SCROLL_STATE_IDLE + mScrollValues.reset() + mDragStartPosition = NO_POSITION + mTarget = NO_POSITION + mDispatchSelected = false + mScrollHappened = false + isFakeDragging = false + mDataSetChangeHappened = false + } + + fun setOnPageChangeCallback(callback: OnPageChangeCallback) { + mCallback = callback + } + + /** + * This method only deals with some cases of [AdapterState] transitions. The rest of + * the state transition implementation is in the [.onScrolled] method. + */ + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + // User started a drag (not dragging -> dragging) + if (((mAdapterState != STATE_IN_PROGRESS_MANUAL_DRAG + || scrollState != ViewPager2.SCROLL_STATE_DRAGGING) + && newState == RecyclerView.SCROLL_STATE_DRAGGING) + ) { + startDrag(false) + return + } + + // Drag is released, RecyclerView is snapping to page (dragging -> settling) + // Note that mAdapterState is not updated, to remember we were dragging when settling + if (isInAnyDraggingState && newState == RecyclerView.SCROLL_STATE_SETTLING) { + // Only go through the settling phase if the drag actually moved the page + if (mScrollHappened) { + dispatchStateChanged(ViewPager2.SCROLL_STATE_SETTLING) + // Determine target page and dispatch onPageSelected on next scroll event + mDispatchSelected = true + } + return + } + + // Drag is finished (dragging || settling -> idle) + if (isInAnyDraggingState && newState == RecyclerView.SCROLL_STATE_IDLE) { + var dispatchIdle: Boolean = false + updateScrollEventValues() + if (!mScrollHappened) { + // Pages didn't move during drag, so either we're at the start or end of the list, + // or there are no pages at all. + // In the first case, ViewPager's contract requires at least one scroll event. + // In the second case, don't send that scroll event + if (mScrollValues.mPosition != RecyclerView.NO_POSITION) { + dispatchScrolled(mScrollValues.mPosition, 0f, 0) + } + dispatchIdle = true + } else if (mScrollValues.mOffsetPx == 0) { + // Normally we dispatch the selected page and go to idle in onScrolled when + // mOffsetPx == 0, but in this case the drag was still ongoing when onScrolled was + // called, so that didn't happen. And since mOffsetPx == 0, there will be no further + // scroll events, so fire the onPageSelected event and go to idle now. + // Note that if we _did_ go to idle in that last onScrolled event, this code will + // not be executed because mAdapterState has been reset to STATE_IDLE. + dispatchIdle = true + if (mDragStartPosition != mScrollValues.mPosition) { + dispatchSelected(mScrollValues.mPosition) + } + } + if (dispatchIdle) { + // Normally idle is fired in last onScrolled call, but either onScrolled was never + // called, or we were still dragging when the last onScrolled was called + dispatchStateChanged(ViewPager2.SCROLL_STATE_IDLE) + resetState() + } + } + if ((mAdapterState == STATE_IN_PROGRESS_SMOOTH_SCROLL + ) && (newState == RecyclerView.SCROLL_STATE_IDLE) && mDataSetChangeHappened + ) { + updateScrollEventValues() + if (mScrollValues.mOffsetPx == 0) { + if (mTarget != mScrollValues.mPosition) { + dispatchSelected( + if (mScrollValues.mPosition == NO_POSITION) 0 else mScrollValues.mPosition + ) + } + dispatchStateChanged(ViewPager2.SCROLL_STATE_IDLE) + resetState() + } + } + } + + /** + * This method only deals with some cases of [AdapterState] transitions. The rest of + * the state transition implementation is in the [.onScrollStateChanged] method. + */ + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + mScrollHappened = true + updateScrollEventValues() + if (mDispatchSelected) { + // Drag started settling, need to calculate target page and dispatch onPageSelected now + mDispatchSelected = false + val scrollingForward: Boolean = dy > 0 + + // "&& values.mOffsetPx != 0": filters special case where we're scrolling forward and + // the first scroll event after settling already got us at the target + mTarget = + if (scrollingForward && mScrollValues.mOffsetPx != 0) mScrollValues.mPosition + 1 else mScrollValues.mPosition + if (mDragStartPosition != mTarget) { + dispatchSelected(mTarget) + } + } else if (mAdapterState == STATE_IDLE) { + // onScrolled while IDLE means RV has just been populated after an adapter has been set. + // Contract requires us to fire onPageSelected as well. + val position: Int = mScrollValues.mPosition + // Contract forbids us to send position = -1 though + dispatchSelected(if (position == NO_POSITION) 0 else position) + } + + // If position = -1, there are no items. Contract says to send position = 0 instead. + dispatchScrolled( + if (mScrollValues.mPosition == NO_POSITION) 0 else mScrollValues.mPosition, + mScrollValues.mOffset, mScrollValues.mOffsetPx + ) + + // Dispatch idle in onScrolled instead of in onScrollStateChanged because RecyclerView + // doesn't send IDLE event when using setCurrentItem(x, false) + if (((mScrollValues.mPosition == mTarget || mTarget == NO_POSITION) + && (mScrollValues.mOffsetPx == 0) && !(scrollState == ViewPager2.SCROLL_STATE_DRAGGING)) + ) { + // When the target page is reached and the user is not dragging anymore, we're settled, + // so go to idle. + // Special case and a bit of a hack when mTarget == NO_POSITION: RecyclerView is being + // initialized and fires a single scroll event. This flags mScrollHappened, so we need + // to reset our state. However, we don't want to dispatch idle. But that won't happen; + // because we were already idle. + dispatchStateChanged(ViewPager2.SCROLL_STATE_IDLE) + resetState() + } + } + + /** + * Calculates the current position and the offset (as a percentage and in pixels) of that + * position from the center. + */ + private fun updateScrollEventValues() { + val values: ScrollEventValues = mScrollValues + values.mPosition = mLayoutManager.findFirstVisibleItemPosition() + if (values.mPosition == RecyclerView.NO_POSITION) { + values.reset() + return + } + val firstVisibleView: View? = mLayoutManager.findViewByPosition(values.mPosition) + if (firstVisibleView == null) { + values.reset() + return + } + var leftDecorations: Int = mLayoutManager.getLeftDecorationWidth(firstVisibleView) + var rightDecorations: Int = mLayoutManager.getRightDecorationWidth(firstVisibleView) + var topDecorations: Int = mLayoutManager.getTopDecorationHeight(firstVisibleView) + var bottomDecorations: Int = mLayoutManager.getBottomDecorationHeight(firstVisibleView) + val params: ViewGroup.LayoutParams = firstVisibleView.layoutParams + if (params is MarginLayoutParams) { + val margin: MarginLayoutParams = params + leftDecorations += margin.leftMargin + rightDecorations += margin.rightMargin + topDecorations += margin.topMargin + bottomDecorations += margin.bottomMargin + } + val decoratedHeight: Int = firstVisibleView.height + topDecorations + bottomDecorations + val decoratedWidth: Int = firstVisibleView.width + leftDecorations + rightDecorations + val isHorizontal: Boolean = mLayoutManager.orientation == ViewPager2.ORIENTATION_HORIZONTAL + val start: Int + val sizePx: Int + if (isHorizontal) { + sizePx = decoratedWidth + start = firstVisibleView.left - leftDecorations - mRecyclerView.paddingLeft + } else { + sizePx = decoratedHeight + start = firstVisibleView.top - topDecorations - mRecyclerView.paddingTop + } + values.mOffsetPx = -start + values.mOffset = if (sizePx == 0) 0F else values.mOffsetPx.toFloat() / sizePx + } + + private fun startDrag(isFakeDrag: Boolean) { + isFakeDragging = isFakeDrag + mAdapterState = + if (isFakeDrag) STATE_IN_PROGRESS_FAKE_DRAG else STATE_IN_PROGRESS_MANUAL_DRAG + if (mTarget != NO_POSITION) { + // Target was set means we were settling to that target + // Update "drag start page" to reflect the page that ViewPager2 thinks it is at + mDragStartPosition = mTarget + // Reset target because drags have no target until released + mTarget = NO_POSITION + } else if (mDragStartPosition == NO_POSITION) { + // ViewPager2 was at rest, set "drag start page" to current page + mDragStartPosition = position + } + dispatchStateChanged(ViewPager2.SCROLL_STATE_DRAGGING) + } + + fun notifyDataSetChangeHappened() { + mDataSetChangeHappened = true + } + + /** + * Let the adapter know a programmatic scroll was initiated. + */ + fun notifyProgrammaticScroll(target: Int, smooth: Boolean) { + mAdapterState = + if (smooth) STATE_IN_PROGRESS_SMOOTH_SCROLL else STATE_IN_PROGRESS_IMMEDIATE_SCROLL + // mFakeDragging is true when a fake drag is interrupted by an a11y command + // set it to false so endFakeDrag won't fling the RecyclerView + isFakeDragging = false + val hasNewTarget: Boolean = mTarget != target + mTarget = target + dispatchStateChanged(ViewPager2.SCROLL_STATE_SETTLING) + if (hasNewTarget) { + dispatchSelected(target) + } + } + + /** + * Let the adapter know that a fake drag has started. + */ + fun notifyBeginFakeDrag() { + mAdapterState = STATE_IN_PROGRESS_FAKE_DRAG + startDrag(true) + } + + /** + * @return `true` if there is no known scroll in progress + */ + val isIdle: Boolean + get() = scrollState == ViewPager2.SCROLL_STATE_IDLE + + /** + * @return `true` if the ViewPager2 is being dragged. Returns `false` from the + * moment the ViewPager2 starts settling or goes idle. + */ + val isDragging: Boolean + get() = scrollState == ViewPager2.SCROLL_STATE_DRAGGING + + /** + * Checks if the adapter state (not the scroll state) is in the manual or fake dragging state. + * @return `true` if [.mAdapterState] is either [ ][.STATE_IN_PROGRESS_MANUAL_DRAG] or [.STATE_IN_PROGRESS_FAKE_DRAG] + */ + private val isInAnyDraggingState: Boolean + get() = (mAdapterState == STATE_IN_PROGRESS_MANUAL_DRAG + || mAdapterState == STATE_IN_PROGRESS_FAKE_DRAG) + + /** + * Calculates the scroll position of the currently visible item of the ViewPager relative to its + * width. Calculated by adding the fraction by which the first visible item is off screen to its + * adapter position. E.g., if the ViewPager is currently scrolling from the second to the third + * page, the returned value will be between 1 and 2. Thus, non-integral values mean that the + * the ViewPager is settling towards its [current item][ViewPager2.getCurrentItem], or + * the user may be dragging it. + * + * @return The current scroll position of the ViewPager, relative to its width + */ + val relativeScrollPosition: Double + get() { + updateScrollEventValues() + return mScrollValues.mPosition + mScrollValues.mOffset.toDouble() + } + + private fun dispatchStateChanged(@ScrollState state: Int) { + // Callback contract for immediate-scroll requires not having state change notifications, + // but only when there was no smooth scroll in progress. + // By putting a suppress statement in here (rather than next to dispatch calls) we are + // simplifying the code of the class and enforcing the contract in one place. + if ((mAdapterState == STATE_IN_PROGRESS_IMMEDIATE_SCROLL + && scrollState == ViewPager2.SCROLL_STATE_IDLE) + ) { + return + } + if (scrollState == state) { + return + } + scrollState = state + if (mCallback != null) { + mCallback!!.onPageScrollStateChanged(state) + } + } + + private fun dispatchSelected(target: Int) { + if (mCallback != null) { + mCallback!!.onPageSelected(target) + } + } + + private fun dispatchScrolled(position: Int, offset: Float, offsetPx: Int) { + if (mCallback != null) { + mCallback!!.onPageScrolled(position, offset, offsetPx) + } + } + + private val position: Int + get() { + return mLayoutManager.findFirstVisibleItemPosition() + } + + private class ScrollEventValues { + var mPosition: Int = 0 + var mOffset: Float = 0f + var mOffsetPx: Int = 0 + fun reset() { + mPosition = RecyclerView.NO_POSITION + mOffset = 0f + mOffsetPx = 0 + } + } + + companion object { + private const val STATE_IDLE: Int = 0 + private const val STATE_IN_PROGRESS_MANUAL_DRAG: Int = 1 + private const val STATE_IN_PROGRESS_SMOOTH_SCROLL: Int = 2 + private const val STATE_IN_PROGRESS_IMMEDIATE_SCROLL: Int = 3 + private const val STATE_IN_PROGRESS_FAKE_DRAG: Int = 4 + private const val NO_POSITION: Int = -1 + } + +} diff --git a/app/src/main/java/com/gh/common/view/TabIndicatorView.java b/app/src/main/java/com/gh/common/view/TabIndicatorView.java index 60345ad447..363705ab6e 100644 --- a/app/src/main/java/com/gh/common/view/TabIndicatorView.java +++ b/app/src/main/java/com/gh/common/view/TabIndicatorView.java @@ -112,10 +112,10 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList this.mIndicatorSpace = DisplayUtils.dip2px(getContext(), space); } - private int getIndicatorSpace() { + private int getIndicatorSpace(int position) { if (mIndicatorSpace != 0) return mIndicatorSpace; if (mIndicatorWidth != 0) { - View tag = getTabViewByPosition(0); + View tag = getTabViewByPosition(position); if (tag != null) return (tag.getWidth() - mIndicatorWidth) / 2; } return 0; @@ -174,15 +174,15 @@ public class TabIndicatorView extends View implements ViewPager.OnPageChangeList right += (int) (nextTabView.getRight() * positionOffset + tabView.getRight() * (1.f - positionOffset)); } - left += getIndicatorSpace(); - right -= getIndicatorSpace(); + left += getIndicatorSpace(position); + right -= getIndicatorSpace(position); top = tabView.getTop() + getPaddingTop(); bottom = tabView.getBottom() - getPaddingBottom(); range.set(left, top, right, bottom); } else { - left = tabView.getLeft() + getIndicatorSpace(); - right = tabView.getRight() - getIndicatorSpace(); + left = tabView.getLeft() + getIndicatorSpace(position); + right = tabView.getRight() - getIndicatorSpace(position); top = tabView.getTop() + getPaddingTop(); bottom = tabView.getBottom() - getPaddingBottom(); range.set(left, top, right, bottom); diff --git a/app/src/main/java/com/gh/common/xapk/XapkUnzipThread.kt b/app/src/main/java/com/gh/common/xapk/XapkUnzipThread.kt index 067ea0f210..f5379c7333 100644 --- a/app/src/main/java/com/gh/common/xapk/XapkUnzipThread.kt +++ b/app/src/main/java/com/gh/common/xapk/XapkUnzipThread.kt @@ -46,7 +46,7 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity, val absolutePath = Environment.getExternalStorageDirectory().absolutePath val xapkFile = File(path) - ZipFile(xapkFile).use { zip -> + val unzipClosure: (zip: ZipFile) -> Unit = { zip -> for (zipEntry in zip.entries().asSequence()) { val outputFile = if (zipEntry.name.getExtension() == XapkInstaller.XAPK_DATA_EXTENSION_NAME) { File(absolutePath + File.separator + zipEntry.name) @@ -91,7 +91,7 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity, bytes = input.read(buffer) if (canceled) { mUnzipListener.onCancel(mDownloadEntity) - return + return@use } else { // 防止多次短时间内多次触发onProgress方法导致阻塞主线程(低端机会出现十分明显的卡顿) debounceActionWithInterval(-1, 500) { @@ -104,6 +104,16 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity, mUnzipListener.onNext(mDownloadEntity, outputFile.path) } } + + // Kotlin 1.4.X 在安卓 4.4 以下使用 use 默认关闭 ZipFile 的流时会触发 + // java.lang.IncompatibleClassChangeError: interface not implemented 的 Error (Throwable) + // 但实测是不影响解压的,所以这里换用 let 不关闭流,确保不闪退,并且不影响解压结果 + // 帮用户解压了,但游戏能不能安装就看天吧 (毕竟支持4.X的游戏也不多了) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + ZipFile(File(path)).use { unzipClosure.invoke(it) } + } else { + ZipFile(File(path)).let { unzipClosure.invoke(it) } + } mUnzipListener.onSuccess(mDownloadEntity) } catch (e: Exception) { if (BuildConfig.DEBUG) throw e @@ -208,18 +218,21 @@ class XapkUnzipThread(private var mDownloadEntity: DownloadEntity, private fun getUnzipSize(path: String): Long { var totalSize = 0L - // 这里安卓5.0以下使用use会报错闪退 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - ZipFile(File(path)).use { - for (entry in it.entries()) { - totalSize += entry.size - } - } - } else { - for (entry in ZipFile(File(path)).entries()) { + + val calculateSizeClosure: (zip: ZipFile) -> Unit = { zip -> + for (entry in zip.entries()) { totalSize += entry.size } } + + // Kotlin 1.4.X 在安卓 4.4 以下使用 use 默认ZipFile 的流时会触发 + // java.lang.IncompatibleClassChangeError: interface not implemented 的 Error (Throwable) + // 实测是不影响解压,所以这里换用 let 不关闭流,确保不闪退 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + ZipFile(File(path)).use { calculateSizeClosure.invoke(it) } + } else { + ZipFile(File(path)).let { calculateSizeClosure.invoke(it) } + } return totalSize } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/download/DownloadManager.java b/app/src/main/java/com/gh/download/DownloadManager.java index 88a4181ac0..a6ad40c445 100644 --- a/app/src/main/java/com/gh/download/DownloadManager.java +++ b/app/src/main/java/com/gh/download/DownloadManager.java @@ -32,6 +32,7 @@ import com.gh.common.util.PackageUtils; import com.gh.common.util.PageSwitchDataHelper; import com.gh.common.util.SPUtils; import com.gh.gamecenter.BuildConfig; +import com.gh.gamecenter.download.DownloadedGameIdAndPackageNameDao; import com.gh.gamecenter.entity.ApkEntity; import com.gh.gamecenter.entity.GameEntity; import com.gh.gamecenter.entity.GameUpdateEntity; @@ -88,6 +89,7 @@ public class DownloadManager implements DownloadStatusListener { private ArrayMap downloadingMap; private DownloadDao mDownloadDao; + private DownloadedGameIdAndPackageNameDao mDownloadedGameIdAndPackageNameDao; private Set mUpdateMarks; @@ -132,6 +134,8 @@ public class DownloadManager implements DownloadStatusListener { public void onTaskDone(DownloadEntity entity) { downloadingMap.remove(entity.getUrl()); + mDownloadedGameIdAndPackageNameDao.add(entity.getGameId() + entity.getPackageName()); + if (downloadingMap.isEmpty()) { DownloadWorkManager.cancelWorker(); } @@ -145,6 +149,7 @@ public class DownloadManager implements DownloadStatusListener { private DownloadManager(Context context) { mContext = context.getApplicationContext(); mDownloadDao = DownloadDao.getInstance(mContext); + mDownloadedGameIdAndPackageNameDao = new DownloadedGameIdAndPackageNameDao(); mUpdateMarks = SPUtils.getStringSet(UPDATE_IS_READ_MARK); @@ -257,7 +262,7 @@ public class DownloadManager implements DownloadStatusListener { // 下载模拟器游戏配置文件,地址是 "模拟器游戏类型根目录/cheat/" if (!TextUtils.isEmpty(gameEntity.getSimulatorGameConfig())) { - String configFilePath = SimulatorGameManager.getPathByType(gameEntity.getSimulatorType()) + "/cheat/" + gameEntity.getName() + ".ini"; + String configFilePath = SimulatorGameManager.getPathByType(gameEntity.getSimulatorType()) + "/cheat/" + apkEntity.getPackageName()+ ".ini"; AppExecutor.getIoExecutor().execute(() -> { FileUtils.downloadFile(gameEntity.getSimulatorGameConfig(), configFilePath); }); diff --git a/app/src/main/java/com/gh/download/server/BrowserInstallHelper.kt b/app/src/main/java/com/gh/download/server/BrowserInstallHelper.kt index 661df11f89..ffddb4963d 100644 --- a/app/src/main/java/com/gh/download/server/BrowserInstallHelper.kt +++ b/app/src/main/java/com/gh/download/server/BrowserInstallHelper.kt @@ -29,7 +29,9 @@ object BrowserInstallHelper { private val mContext by lazy { HaloApp.getInstance().application } private val mAllInstalledPackageList: ArrayList by lazy { - PackageUtils.getAllPackageNameIncludeSystemApps(HaloApp.getInstance().applicationContext) + PackageUtils.getAllPackageNameIncludeSystemApps(HaloApp.getInstance().applicationContext).apply { + add(HaloApp.getInstance().applicationContext.packageName) + } } private fun getServer(): DownloadServer { diff --git a/app/src/main/java/com/gh/gamecenter/LibaoDetailActivity.java b/app/src/main/java/com/gh/gamecenter/LibaoDetailActivity.java index d3d123dfcb..2c2624e924 100644 --- a/app/src/main/java/com/gh/gamecenter/LibaoDetailActivity.java +++ b/app/src/main/java/com/gh/gamecenter/LibaoDetailActivity.java @@ -436,7 +436,7 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA mIsScroll = isScroll; } - @Override + /*@Override public boolean handleBackPressed() { // 重置领取状态 if (mLibaoEntity == null) { @@ -447,7 +447,7 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA mLibaoEntity.setStatus(mListStatus); } return false; - } + }*/ @Override public void loadDone() { diff --git a/app/src/main/java/com/gh/gamecenter/MainActivity.java b/app/src/main/java/com/gh/gamecenter/MainActivity.java index ad1acc99ce..3a4b18aa7c 100644 --- a/app/src/main/java/com/gh/gamecenter/MainActivity.java +++ b/app/src/main/java/com/gh/gamecenter/MainActivity.java @@ -61,6 +61,7 @@ import com.gh.common.util.PackageUtils; import com.gh.common.util.PlatformUtils; import com.gh.common.util.QuickLoginHelper; import com.gh.common.util.SPUtils; +import com.gh.common.util.SentryHelper; import com.gh.common.util.ShareUtils; import com.gh.common.util.ToastUtils; import com.gh.common.util.UrlFilterUtils; @@ -93,6 +94,7 @@ import com.github.piasy.biv.BigImageViewer; import com.github.piasy.biv.loader.fresco.FrescoImageLoader; import com.google.android.exoplayer2.upstream.cache.Cache; import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; import com.halo.assistant.HaloApp; import com.lightgame.download.DownloadEntity; @@ -100,6 +102,9 @@ import com.lightgame.download.DownloadStatus; import com.lightgame.download.FileUtils; import com.lightgame.utils.AppManager; import com.lightgame.utils.Utils; +import com.sina.weibo.sdk.auth.AuthInfo; +import com.sina.weibo.sdk.openapi.IWBAPI; +import com.sina.weibo.sdk.openapi.WBAPIFactory; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -144,6 +149,7 @@ import static com.gh.common.util.EntranceUtils.KEY_NEXT_TO; import static com.gh.common.util.EntranceUtils.KEY_TO; import static com.gh.common.util.EntranceUtils.KEY_TYPE; import static com.gh.common.util.ExtensionsKt.observableToMain; +import static com.gh.common.util.LoginHelper.WEIBO_SCOPE; import static com.gh.gamecenter.fragment.MainWrapperFragment.INDEX_PERSONAL; import static com.gh.gamecenter.personal.PersonalFragment.LOGIN_TAG; import static com.gh.gamecenter.personal.PersonalFragment.LOGOUT_TAG; @@ -197,7 +203,7 @@ public class MainActivity extends BaseActivity { mSp = PreferenceManager.getDefaultSharedPreferences(this); - isNewFirstLaunch = mSp.getBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), true); + isNewFirstLaunch = mSp.getBoolean("isNewFirstLaunchV" + PackageUtils.getGhVersionName(), true); if (isNewFirstLaunch) { final LunchType lunchType = DeviceTokenUtils.getLaunchType(); // 延时两秒提交,避免提交时还没获取到 GID/OAID @@ -208,12 +214,11 @@ public class MainActivity extends BaseActivity { // 第一次打开App删除模拟器游戏记录(不包括更新版本) if (HaloApp.getInstance().isBrandNewInstall) { SimulatorGameManager.deleteAllSimulatorGame(); - } } }, 2000L); getPluginUpdate(); - mSp.edit().putBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), false).apply(); + mSp.edit().putBoolean("isNewFirstLaunchV" + PackageUtils.getGhVersionName(), false).apply(); checkDevice(); // 根据设备信息判断用户是否是新用户 } @@ -317,6 +322,7 @@ public class MainActivity extends BaseActivity { deleteSimulatorGame(); QuickLoginHelper.getPhoneInfo(this); + initWBSDK(); } //上传关注视频浏览记录 @@ -451,6 +457,7 @@ public class MainActivity extends BaseActivity { if (view != null) { view.setVisibility(View.GONE); + ExtensionsKt.removeFromParent(view); } checkDialog(); @@ -553,17 +560,27 @@ public class MainActivity extends BaseActivity { break; case HOST_LAUNCH_SIMULATOR_GAME: String json = getIntent().getStringExtra(EntranceUtils.KEY_GAME); - GameEntity gameEntity = GsonUtils.getGson().fromJson(json, new TypeToken() { - }.getType()); - DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl()); - if (downloadEntity != null) { - File file = new File(downloadEntity.getPath()); - if (!file.exists()) { - ToastUtils.INSTANCE.showToast("文件已被删除,无法启动"); - return; - } + try { + GameEntity gameEntity = GsonUtils.getGson().fromJson(json, new TypeToken() { + }.getType()); + DownloadEntity downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk().get(0).getUrl()); + if (downloadEntity != null) { + File file = new File(downloadEntity.getPath()); + if (!file.exists()) { + ToastUtils.INSTANCE.showToast("文件已被删除,无法启动"); + return; + } - SimulatorGameManager.launchSimulatorGame(downloadEntity, gameEntity); + SimulatorGameManager.launchSimulatorGame(downloadEntity, gameEntity); + } + } catch (JsonSyntaxException exception) { + exception.printStackTrace(); + toast("模拟器游戏启动失败,请联系客服反馈相关信息"); + SentryHelper.INSTANCE.onEvent( + "SIMULATOR_SHORTCUT_LAUNCH_ERROR", + "raw_json", + json + ); } break; case KEY_MARKET_DETAILS: @@ -966,4 +983,10 @@ public class MainActivity extends BaseActivity { context.startActivity(intent); } + //需要提前初始化微博sdk,否则第一次分享或授权登录会失败 + private void initWBSDK() { + IWBAPI mWBAPI = WBAPIFactory.createWBAPI(this); + mWBAPI.registerApp(this, new AuthInfo(this, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE)); + } + } diff --git a/app/src/main/java/com/gh/gamecenter/SkipActivity.java b/app/src/main/java/com/gh/gamecenter/SkipActivity.java index bcc9f5415a..9ecd2e6dda 100644 --- a/app/src/main/java/com/gh/gamecenter/SkipActivity.java +++ b/app/src/main/java/com/gh/gamecenter/SkipActivity.java @@ -273,6 +273,9 @@ public class SkipActivity extends BaseActivity { bundle.putString(KEY_TYPE, type); EntranceUtils.jumpActivity(this, bundle); break; + case EntranceUtils.HOST_VIDEO_DETAIL: + DirectUtils.directToVideoDetail(this, path, ENTRANCE_BROWSER, ""); + break; case HOST_LIBAO: DirectUtils.directToGiftDetail(this, path, ENTRANCE_BROWSER); break; diff --git a/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.java b/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.java index 713450767c..3ba7d515d5 100644 --- a/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.java +++ b/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.java @@ -98,7 +98,7 @@ public class SplashScreenActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); - mIsNewForThisVersion = mSharedPreferences.getBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), true); + mIsNewForThisVersion = mSharedPreferences.getBoolean("isNewFirstLaunchV" + PackageUtils.getGhVersionName(), true); HaloApp.getInstance().isNewForThisVersion = mIsNewForThisVersion; super.onCreate(savedInstanceState); @@ -441,7 +441,7 @@ public class SplashScreenActivity extends BaseActivity { int index = name.indexOf("_"); if (index != -1) { String versionString = name.substring(name.indexOf("V") + 1, index); - Version currentVersion = new Version(PackageUtils.getVersionName()); + Version currentVersion = new Version(PackageUtils.getGhVersionName()); if (currentVersion.isHigherThan(versionString) || currentVersion.isEqual(versionString)) { file.delete(); } diff --git a/app/src/main/java/com/gh/gamecenter/SuggestionActivity.java b/app/src/main/java/com/gh/gamecenter/SuggestionActivity.java index e8589fb2e0..604f2fce15 100644 --- a/app/src/main/java/com/gh/gamecenter/SuggestionActivity.java +++ b/app/src/main/java/com/gh/gamecenter/SuggestionActivity.java @@ -1121,7 +1121,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall Map params = new HashMap<>(); params.put("from", mContactMethodEt.getText().toString()); - params.put("ghversion", PackageUtils.getVersionName()); + params.put("ghversion", PackageUtils.getGhVersionName()); params.put("channel", HaloApp.getInstance().getChannel()); params.put("type", android.os.Build.MODEL); params.put("sdk", String.valueOf(android.os.Build.VERSION.SDK_INT)); @@ -1151,7 +1151,7 @@ public class SuggestionActivity extends ToolBarActivity implements OnRequestCall Map params = new HashMap<>(); params.put("from", email); - params.put("ghversion", PackageUtils.getVersionName()); + params.put("ghversion", PackageUtils.getGhVersionName()); params.put("channel", HaloApp.getInstance().getChannel()); params.put("type", android.os.Build.MODEL); params.put("sdk", String.valueOf(android.os.Build.VERSION.SDK_INT)); diff --git a/app/src/main/java/com/gh/gamecenter/WeiBoShareActivity.java b/app/src/main/java/com/gh/gamecenter/WeiBoShareActivity.java index 30e3af9026..1a16ab29a7 100644 --- a/app/src/main/java/com/gh/gamecenter/WeiBoShareActivity.java +++ b/app/src/main/java/com/gh/gamecenter/WeiBoShareActivity.java @@ -13,11 +13,13 @@ import android.util.Base64; import androidx.annotation.NonNull; import com.gh.common.Base64ImageHolder; +import com.gh.common.constant.Config; import com.gh.common.util.BiCallback; import com.gh.common.util.EnergyTaskHelper; import com.gh.common.util.ImageUtils; import com.gh.common.util.IntegralLogHelper; import com.gh.common.util.LogUtils; +import com.gh.common.util.NewLogUtils; import com.gh.common.util.ShareUtils; import com.gh.gamecenter.eventbus.EBShare; import com.lightgame.utils.Utils; @@ -25,13 +27,17 @@ import com.sina.weibo.sdk.api.ImageObject; import com.sina.weibo.sdk.api.TextObject; import com.sina.weibo.sdk.api.WebpageObject; import com.sina.weibo.sdk.api.WeiboMultiMessage; +import com.sina.weibo.sdk.auth.AuthInfo; +import com.sina.weibo.sdk.common.UiError; +import com.sina.weibo.sdk.openapi.IWBAPI; +import com.sina.weibo.sdk.openapi.WBAPIFactory; import com.sina.weibo.sdk.share.WbShareCallback; -import com.sina.weibo.sdk.share.WbShareHandler; -import com.sina.weibo.sdk.utils.Utility; import org.greenrobot.eventbus.EventBus; import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.UUID; /** * Created by khy on 2016/11/23. @@ -48,6 +54,11 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback { private static final String KET_TYPE = "KET_TYPE"; private static final String KET_SUMMARY = "KET_SUMMARY"; + private static final String WEIBO_SCOPE = ( + "email,direct_messages_read,direct_messages_write," + + "friendships_groups_read,friendships_groups_write,statuses_to_me_read," + + "follow_app_official_microblog," + "invitation_write"); + private String shareUrl; private String mShareStyle; @@ -55,7 +66,7 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback { private String mSummary; private String mShareType; - private WbShareHandler mWeiboShareAPI; + private IWBAPI mWBAPI; @NonNull public static Intent getWeiboShareIntent(Context context, String shareUrl, String shareIcon, @@ -103,24 +114,26 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback { Utils.toast(this, R.string.share_skip); - mWeiboShareAPI = new WbShareHandler(this); - mWeiboShareAPI.registerApp(); + mWBAPI = WBAPIFactory.createWBAPI(this); + mWBAPI.registerApp(this, new AuthInfo(this, Config.WEIBO_APPKEY, "http://www.sina.com", WEIBO_SCOPE)); if ("NORMAL".equals(mShareStyle)) { if (shareIcon != null) { loadIconAndShare(shareIcon); } else { - onWbShareFail(); + onError(new UiError(0, "", "")); } } else if ("IMAGE".equals(mShareStyle)) { shareImage(); } } - - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - mWeiboShareAPI.doResultIntent(intent, this); //当前应用唤起微博分享后,返回当前应用 + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (mWBAPI != null) { + mWBAPI.doResultIntent(data, this); + } } private void loadIconAndShare(String iconUrl) { @@ -158,22 +171,37 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback { } ImageObject imageObject = new ImageObject(); - imageObject.setImageObject(bgBitmap);//设置缩略图。 注意:最终压缩过的缩略图大小不得超过 32kb。 + imageObject.setImageData(bgBitmap);//设置缩略图。 注意:最终压缩过的缩略图大小不得超过 32kb。 WebpageObject webObject = new WebpageObject(); - webObject.identify = Utility.generateGUID(); + webObject.identify = UUID.randomUUID().toString(); webObject.title = ""; webObject.description = getString(R.string.app_name); webObject.defaultText = getString(R.string.app_name); webObject.actionUrl = shareUrl; - webObject.setThumbImage(bgBitmap); + ByteArrayOutputStream os = null; + try { + os = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 85, os); + webObject.thumbData = os.toByteArray(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (os != null) { + os.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } WeiboMultiMessage weiboMessage = new WeiboMultiMessage();//初始化微博的分享消息 weiboMessage.textObject = textObject; weiboMessage.imageObject = imageObject; weiboMessage.mediaObject = webObject; - mWeiboShareAPI.shareMessage(weiboMessage, false); + mWBAPI.shareMessage(weiboMessage, false); } @Override @@ -189,14 +217,14 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback { // 转完后重新置位 Base64ImageHolder.INSTANCE.setImage(""); - Bitmap compressBitmap = compressBitmap(bitmap) ; + Bitmap compressBitmap = compressBitmap(bitmap); ImageObject imageObject = new ImageObject(); - imageObject.setImageObject(compressBitmap); + imageObject.setImageData(compressBitmap); WeiboMultiMessage weiboMessage = new WeiboMultiMessage();//初始化微博的分享消息 weiboMessage.imageObject = imageObject; - mWeiboShareAPI.shareMessage(weiboMessage, false); + mWBAPI.shareMessage(weiboMessage, false); } public Bitmap compressBitmap(Bitmap bitmap) { @@ -223,7 +251,7 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback { } @Override - public void onWbShareSuccess() { + public void onComplete() { Utils.toast(this, R.string.share_success_hint); if ("NORMAL".equals(mShareStyle)) { LogUtils.uploadShareResult(ShareUtils.shareType, ShareUtils.shareEntrance.getName(), "success", @@ -233,6 +261,11 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback { if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.inviteFriends) { IntegralLogHelper.INSTANCE.logInviteResult("成功", "微博"); } + if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.communityArticle || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) { + NewLogUtils.logShareResult(true); + } } else { IntegralLogHelper.INSTANCE.logInviteResult("成功", "微博"); } @@ -240,22 +273,7 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback { } @Override - public void onWbShareCancel() { - Utils.toast(this, R.string.share_cancel_hint); - if ("NORMAL".equals(mShareStyle)) { - LogUtils.uploadShareResult(ShareUtils.shareType, ShareUtils.shareEntrance.getName(), "cancel", - ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId); - if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.inviteFriends) { - IntegralLogHelper.INSTANCE.logInviteResult("取消", "微博"); - } - } else { - IntegralLogHelper.INSTANCE.logInviteResult("取消", "微博"); - } - finish(); - } - - @Override - public void onWbShareFail() { + public void onError(UiError uiError) { Utils.toast(this, R.string.share_fail_hint); if ("NORMAL".equals(mShareStyle)) { LogUtils.uploadShareResult(ShareUtils.shareType, ShareUtils.shareEntrance.getName(), "fail", @@ -263,9 +281,34 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback { if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.inviteFriends) { IntegralLogHelper.INSTANCE.logInviteResult("失败", "微博"); } + if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.communityArticle || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) { + NewLogUtils.logShareResult(false); + } } else { IntegralLogHelper.INSTANCE.logInviteResult("失败", "微博"); } finish(); } + + @Override + public void onCancel() { + Utils.toast(this, R.string.share_cancel_hint); + if ("NORMAL".equals(mShareStyle)) { + LogUtils.uploadShareResult(ShareUtils.shareType, ShareUtils.shareEntrance.getName(), "cancel", + ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId); + if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.inviteFriends) { + IntegralLogHelper.INSTANCE.logInviteResult("取消", "微博"); + } + if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.communityArticle || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) { + NewLogUtils.logShareResult(false); + } + } else { + IntegralLogHelper.INSTANCE.logInviteResult("取消", "微博"); + } + finish(); + } } diff --git a/app/src/main/java/com/gh/gamecenter/adapter/LibaoDetailAdapter.java b/app/src/main/java/com/gh/gamecenter/adapter/LibaoDetailAdapter.java index df04310970..29f119a9d0 100644 --- a/app/src/main/java/com/gh/gamecenter/adapter/LibaoDetailAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/adapter/LibaoDetailAdapter.java @@ -12,13 +12,17 @@ import android.view.View; import android.view.ViewGroup; import androidx.core.content.ContextCompat; +import androidx.core.text.HtmlCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView.ViewHolder; import com.gh.base.OnRequestCallBackListener; import com.gh.common.util.DisplayUtils; +import com.gh.common.util.ExtensionsKt; +import com.gh.common.util.ExtraTagHandler; import com.gh.common.util.LibaoUtils; +import com.gh.common.util.PicassoImageGetter; import com.gh.common.util.PlatformUtils; import com.gh.common.util.SpanBuilder; import com.gh.common.util.StringUtils; @@ -235,7 +239,7 @@ public class LibaoDetailAdapter extends BaseRecyclerAdapter { List userDataLibaoList = mLibaoEntity.getMe().getUserDataLibaoList(); LibaoUtils.initLibaoBtn(mContext, holder.libaoCopyBtn, mLibaoEntity, mLibaoDetailEntity.getInstallRequired(), this, false, - StringUtils.buildString(mEntrance, "+(礼包详情[", mLibaoEntity.getName(), "])")); + StringUtils.buildString(mEntrance, "+(礼包详情[", mLibaoEntity.getName(), "])"), null); if (mLibaoEntity.getUniversal()) { holder.libaoDes.setVisibility(View.GONE); } else { @@ -275,7 +279,7 @@ public class LibaoDetailAdapter extends BaseRecyclerAdapter { if (mLibaoEntity.getStatus() != null && mLibaoDetailEntity != null) { LibaoUtils.initLibaoBtn(mContext, holder.libaoCopyBtn, mLibaoEntity, mLibaoDetailEntity.getInstallRequired(), this, false, - StringUtils.buildString(mEntrance, "+(礼包详情[", mLibaoEntity.getName(), "])")); + StringUtils.buildString(mEntrance, "+(礼包详情[", mLibaoEntity.getName(), "])"), null); } // 判断按钮状态是否为空(礼包详情进入),重新获取 @@ -327,11 +331,16 @@ public class LibaoDetailAdapter extends BaseRecyclerAdapter { holder.mLibaodetailTimeStart.setText(StringUtils.buildString("开始时间:", start)); holder.mLibaodetailTimeEnd.setText(StringUtils.buildString("截止时间:", end)); } - - } - if (mLibaoDetailEntity.getDes() != null && position == getItemCount() - 2) { - holder.mLibaodetailDesLl.setVisibility(View.VISIBLE); - holder.mLibaodetailDes.setText(Html.fromHtml(mLibaoDetailEntity.getDes())); + String des = mLibaoDetailEntity.getNewDes(); + if (des == null) { + des = mLibaoDetailEntity.getDes(); + } + if (des != null && position == getItemCount() - 2) { + holder.mLibaodetailDesLl.setVisibility(View.VISIBLE); + CharSequence spanned = HtmlCompat.fromHtml(des, HtmlCompat.FROM_HTML_MODE_COMPACT, + new PicassoImageGetter(holder.mLibaodetailDes), new ExtraTagHandler()); + ExtensionsKt.setTextWithInterceptingInternalUrl(holder.mLibaodetailDes, spanned); + } } } diff --git a/app/src/main/java/com/gh/gamecenter/adapter/ReportReasonAdapter.kt b/app/src/main/java/com/gh/gamecenter/adapter/ReportReasonAdapter.kt new file mode 100644 index 0000000000..cab6368e17 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/adapter/ReportReasonAdapter.kt @@ -0,0 +1,44 @@ +package com.gh.gamecenter.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.util.goneIf +import com.gh.gamecenter.databinding.ItemReportReasonBinding +import com.lightgame.adapter.BaseRecyclerAdapter + +class ReportReasonAdapter( + context: Context, + val items: ArrayList, + val onItemClick: (String) -> Unit +) : + BaseRecyclerAdapter(context) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return ReportReasonViewHolder( + ItemReportReasonBinding.inflate( + LayoutInflater.from(mContext), + parent, + false + ) + ) + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder is ReportReasonViewHolder) { + val item = items[position] + holder.binding.reasonTv.text = item + holder.binding.reasonArrowIv.goneIf(item != "其他原因") + holder.binding.root.setOnClickListener { + onItemClick.invoke(item) + } + } + } + + override fun getItemCount(): Int = items.size + + inner class ReportReasonViewHolder(val binding: ItemReportReasonBinding) : + RecyclerView.ViewHolder(binding.root) +} + diff --git a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/GameViewHolder.java b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/GameViewHolder.java index b07df42731..dfe4b65b5a 100644 --- a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/GameViewHolder.java +++ b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/GameViewHolder.java @@ -8,6 +8,7 @@ import android.widget.TextView; import androidx.annotation.Nullable; +import com.facebook.drawee.view.SimpleDraweeView; import com.gh.base.BaseRecyclerViewHolder; import com.gh.common.view.DrawableView; import com.gh.common.view.GameIconView; @@ -28,7 +29,7 @@ public class GameViewHolder extends BaseRecyclerViewHolder { @Nullable public View recommendContainer; public TextView recommendTv; - public ImageView recommendIv; + public SimpleDraweeView recommendIv; public TextView gameDownloadSpeed; public TextView gameDownloadPercentage; public TextView gameServerType; diff --git a/app/src/main/java/com/gh/gamecenter/amway/AmwaySuccessFragment.kt b/app/src/main/java/com/gh/gamecenter/amway/AmwaySuccessFragment.kt index ff834eed5d..b3e4814e76 100644 --- a/app/src/main/java/com/gh/gamecenter/amway/AmwaySuccessFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/amway/AmwaySuccessFragment.kt @@ -30,7 +30,15 @@ class AmwaySuccessFragment : NormalFragment() { setNavigationTitle("安利墙") checkCommentBtn.setOnClickListener { - GameDetailActivity.startGameDetailCommentActivity(requireContext(), mGameEntity, "安利墙") + if (mGameEntity != null) { + GameDetailActivity.startGameDetailCommentActivity( + requireContext(), + mGameEntity, + "安利墙" + ) + } else { + requireActivity().finish() + } } checkAmwayBtn.setOnClickListener { diff --git a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListAdapter.kt b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListAdapter.kt index daa164d8e1..f04f58f077 100644 --- a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListAdapter.kt @@ -19,7 +19,6 @@ import com.gh.gamecenter.R import com.gh.gamecenter.adapter.viewholder.FooterViewHolder import com.gh.gamecenter.adapter.viewholder.GameViewHolder import com.gh.gamecenter.baselist.ListAdapter -import com.gh.gamecenter.baselist.LoadType import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.eventbus.EBDownloadStatus import com.gh.gamecenter.game.GameItemViewHolder @@ -89,7 +88,6 @@ class NewCatalogListAdapter(context: Context, holder.binding.game = gameEntity holder.initServerType(gameEntity) - holder.binding.hideSize = true holder.binding.executePendingBindings() GameViewUtils.setLabelList(mContext, holder.binding.labelList, gameEntity.tagStyle) diff --git a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListViewModel.kt b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListViewModel.kt index 967577ca10..40af2225c1 100644 --- a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListViewModel.kt @@ -37,6 +37,7 @@ class NewCatalogListViewModel(application: Application) : ListViewModel game.hideSizeInsideDes = true } ExposureUtils.updateExposureSequence(it) mResultLiveData.postValue(it) } diff --git a/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListAdapter.kt b/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListAdapter.kt index ecd9c28efa..31cf755d13 100644 --- a/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListAdapter.kt @@ -1,7 +1,6 @@ package com.gh.gamecenter.category2 import android.content.Context -import android.graphics.Typeface import android.util.SparseArray import android.view.ViewGroup import androidx.databinding.DataBindingUtil @@ -122,7 +121,6 @@ class CategoryV2ListAdapter(context: Context, holder.binding.game = gameEntity holder.initServerType(gameEntity) - holder.binding.hideSize = true holder.binding.executePendingBindings() GameViewUtils.setLabelList(mContext, holder.binding.labelList, gameEntity.tagStyle) diff --git a/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListViewModel.kt b/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListViewModel.kt index ec6885bf61..ba37ae3f18 100644 --- a/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListViewModel.kt @@ -38,6 +38,7 @@ class CategoryV2ListViewModel(application: Application, override fun mergeResultLiveData() { mResultLiveData.addSource(mListLiveData) { ExposureUtils.updateExposureSequence(it) + it.forEach { game -> game.hideSizeInsideDes = true } mResultLiveData.postValue(it) } } diff --git a/app/src/main/java/com/gh/gamecenter/download/DownloadFragment.kt b/app/src/main/java/com/gh/gamecenter/download/DownloadFragment.kt index e11ec51fd1..441bbd238a 100644 --- a/app/src/main/java/com/gh/gamecenter/download/DownloadFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/download/DownloadFragment.kt @@ -15,6 +15,7 @@ import com.gh.common.util.visibleIf import com.gh.download.DownloadManager import com.gh.gamecenter.DownloadManagerActivity import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.TabItemDownloadNumberBinding import com.gh.gamecenter.entity.HomePluggableFilterEntity import com.gh.gamecenter.entity.PluginLocation import com.gh.gamecenter.eventbus.EBDownloadChanged @@ -30,46 +31,42 @@ import org.greenrobot.eventbus.ThreadMode class DownloadFragment : BaseFragment_TabLayout() { - companion object { - const val INDEX_DOWNLOAD = 0 - const val INDEX_UPDATE = 1 - } - // 下载 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 + private lateinit var mDownloadNumberTv: TextView + private lateinit var mUpdateNumberTv: TextView + private val mDownloadManager: DownloadManager by lazy { DownloadManager.getInstance(HaloApp.getInstance().application) } private var mPermanentInactivePluggableApkList: List? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - mDownloadManager = DownloadManager.getInstance(HaloApp.getInstance().application) mPermanentInactivePluggableApkList = HomePluggableHelper.getPermanentInactivePluggablePackage() } override fun initFragmentList(fragments: MutableList) { fragments.add(GameDownloadFragment()) - fragments.add(GameUpdateFragment()) + fragments.add(UpdatableGameFragment()) fragments.add(InstalledGameFragment()) } override fun initTabTitleList(tabTitleList: MutableList) { tabTitleList.add(getString(R.string.download_game)) tabTitleList.add(getString(R.string.download_tab_update)) - tabTitleList.add("已安装") + tabTitleList.add(getString(R.string.download_tab_installed)) } override fun provideTabView(position: Int, tabTitle: String): View? { - var view = LayoutInflater.from(context).inflate(R.layout.tab_item_download_number, null) - (view.findViewById(R.id.tab_title) as TextView).text = tabTitle - when { - INDEX_DOWNLOAD == position -> mDownloadNumber = view.findViewById(R.id.tab_download_number) - INDEX_UPDATE == position -> mUpdateNumber = view.findViewById(R.id.tab_download_number) + val viewBinding = TabItemDownloadNumberBinding.inflate(LayoutInflater.from(context)) + var view: View? = viewBinding.root + viewBinding.tabTitle.text = tabTitle + + when (position) { + INDEX_DOWNLOAD -> mDownloadNumberTv = viewBinding.tabDownloadNumber + INDEX_UPDATE -> mUpdateNumberTv = viewBinding.tabDownloadNumber else -> view = null } return view @@ -86,7 +83,7 @@ class DownloadFragment : BaseFragment_TabLayout() { updateUpdateHint() updateDownloadHint() - if (mDownloadNumber.visibility != View.VISIBLE && mUpdateNumber.visibility == View.VISIBLE) { + if (mDownloadNumberTv.visibility != View.VISIBLE && mUpdateNumberTv.visibility == View.VISIBLE) { mViewPager.currentItem = INDEX_UPDATE } else { // 进入并选中下载管理时立马标记已下载待安装为已读 @@ -116,12 +113,6 @@ class DownloadFragment : BaseFragment_TabLayout() { override fun onPageSelected(index: Int) { EventBus.getDefault().post(EBUISwitch(DownloadManagerActivity.TAG, index)) - val tabName = when (index) { - INDEX_DOWNLOAD -> "游戏下载" - INDEX_UPDATE -> "游戏更新" - else -> "已安装" - } - if (index == INDEX_UPDATE) { mIsUpdateTabHasBeenSelected = true updateUpdateHint() @@ -131,8 +122,6 @@ class DownloadFragment : BaseFragment_TabLayout() { updateDownloadHint() mDownloadManager.markDownloadingTaskAsRead() } - -// MtaHelper.onEvent("下载管理", "Tab", tabName) } @Subscribe(threadMode = ThreadMode.MAIN) @@ -153,13 +142,13 @@ class DownloadFragment : BaseFragment_TabLayout() { } private fun updateDownloadHint() { - if (!::mDownloadNumber.isInitialized || !isAdded) return + if (!::mDownloadNumberTv.isInitialized || !isAdded) return val downloadData = DownloadManager.getInstance(context).allDownloadEntityExcludeSilentUpdate if (downloadData.size > 0) { - mDownloadNumber.visibility = View.VISIBLE + mDownloadNumberTv.visibility = View.VISIBLE } else { - mDownloadNumber.visibility = View.INVISIBLE + mDownloadNumberTv.visibility = View.INVISIBLE return } @@ -170,32 +159,32 @@ class DownloadFragment : BaseFragment_TabLayout() { } } - val layoutParams = mDownloadNumber.layoutParams as LinearLayout.LayoutParams + val layoutParams = mDownloadNumberTv.layoutParams as LinearLayout.LayoutParams 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() + mDownloadNumberTv.setBackgroundColor(Color.TRANSPARENT) + mDownloadNumberTv.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 = "" + mDownloadNumberTv.setBackgroundResource(R.drawable.oval_hint_red_bg) + mDownloadNumberTv.text = "" } - else -> mDownloadNumber.visibility = View.GONE + else -> mDownloadNumberTv.visibility = View.GONE } - mDownloadNumber.layoutParams = layoutParams + mDownloadNumberTv.layoutParams = layoutParams } private fun updateUpdateHint() { - if (!::mUpdateNumber.isInitialized) return + if (!::mUpdateNumberTv.isInitialized) return if (mIsUpdateTabHasBeenSelected) { - mUpdateNumber.visibility = View.INVISIBLE + mUpdateNumberTv.visibility = View.INVISIBLE return } @@ -205,7 +194,7 @@ class DownloadFragment : BaseFragment_TabLayout() { && mPermanentInactivePluggableApkList?.filter { it.pkgName == gameUpdateEntity.packageName }?.size == 0 }) - mUpdateNumber.visibleIf(updateCount != 0) + mUpdateNumberTv.visibleIf(updateCount != 0) } @Subscribe(threadMode = ThreadMode.MAIN) @@ -230,4 +219,9 @@ class DownloadFragment : BaseFragment_TabLayout() { } } + companion object { + const val INDEX_DOWNLOAD = 0 + const val INDEX_UPDATE = 1 + } + } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/download/DownloadedGameIdAndPackageNameDao.kt b/app/src/main/java/com/gh/gamecenter/download/DownloadedGameIdAndPackageNameDao.kt new file mode 100644 index 0000000000..1d5ccce3c8 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/download/DownloadedGameIdAndPackageNameDao.kt @@ -0,0 +1,14 @@ +package com.gh.gamecenter.download + +import com.gh.base.BaseSimpleDao + +/** + * 用来记录光环下载过什么包名和游戏ID件的一个简单类 + */ +class DownloadedGameIdAndPackageNameDao : BaseSimpleDao() { + + override fun getSPKey() = "downloaded_game_id_and_packagename" + + override fun getMaxSize(): Int = 1000 + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java index a894121c6a..f0817d295a 100644 --- a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java +++ b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java @@ -40,6 +40,7 @@ import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; + import butterknife.BindView; import butterknife.OnClick; @@ -65,6 +66,8 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi TextView mNoDataSkipBtn; @BindView(R.id.downloadmanager_tv_allstart) TextView mDownloadmanagerAllstartTv; + @BindView(R.id.downloadingHintContainer) + View mDownloadingHintContainer; GameDownloadFragmentAdapter adapter; RelativeLayout.LayoutParams rparams; @@ -235,6 +238,9 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi mNoDataSkipHintTv.setText("暂无下载"); mNoDataSkipBtn.setText("去首页看看"); mNoDataSkipBtn.setOnClickListener(v -> MainActivity.skipToMainActivity(getActivity(), MainWrapperFragment.INDEX_HOME)); + mDownloadingHintContainer.setOnClickListener(v -> { + mDownloadmanagerRv.scrollToPosition(adapter.getItemCount() - 1); + }); mDownloadmanagerRv.setHasFixedSize(true); adapter = new GameDownloadFragmentAdapter(getActivity(), mNoDataSkip, url); @@ -270,9 +276,9 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi if (adapter.getDoneList().size() != 0 && position == adapter.getDoneList().size()) { - int buttom = layoutManager.findViewByPosition(position).getBottom(); - if (buttom <= mDownloadmanagerHeadRl.getHeight()) { - rparams.topMargin = buttom - mDownloadmanagerHeadRl.getHeight(); + int bottom = layoutManager.findViewByPosition(position).getBottom(); + if (bottom <= mDownloadmanagerHeadRl.getHeight()) { + rparams.topMargin = bottom - mDownloadmanagerHeadRl.getHeight(); mDownloadmanagerHeadRl.setLayoutParams(rparams); } else { rparams.topMargin = 0; @@ -282,6 +288,7 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi rparams.topMargin = 0; mDownloadmanagerHeadRl.setLayoutParams(rparams); } + showScrollToDownloadContainerIfNeeded(); } }); mDownloadmanagerRv.setOnDispatchTouchListener((v, event) -> { @@ -302,6 +309,7 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi adapter.initMap(); DownloadManager.getInstance(getActivity()).addObserver(dataWatcher); adapter.notifyDataSetChanged(); + showScrollToDownloadContainerIfNeeded(); if (adapter.getDownloadingList().isEmpty() && adapter.getDoneList().isEmpty()) { mNoDataSkip.setVisibility(View.VISIBLE); @@ -441,4 +449,18 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi mDownloadmanagerAllstartTv.setTextColor(ContextCompat.getColor(getContext(), R.color.btn_gray)); } + private void showScrollToDownloadContainerIfNeeded() { + LinearLayoutManager layoutManager = (LinearLayoutManager) mDownloadmanagerRv.getLayoutManager(); + if (layoutManager != null) { + int lastCompletelyVisibleItemPosition = layoutManager.findLastCompletelyVisibleItemPosition(); + + if (adapter.getDownloadingList().size() != 0 + && adapter.getDoneList().size() >= lastCompletelyVisibleItemPosition) { + mDownloadingHintContainer.setVisibility(View.VISIBLE); + } else { + mDownloadingHintContainer.setVisibility(View.GONE); + } + } + } + } diff --git a/app/src/main/java/com/gh/gamecenter/download/GameUpdateFragmentAdapter.java b/app/src/main/java/com/gh/gamecenter/download/GameUpdateFragmentAdapter.java index d3a26310c3..69362595d4 100644 --- a/app/src/main/java/com/gh/gamecenter/download/GameUpdateFragmentAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/download/GameUpdateFragmentAdapter.java @@ -341,7 +341,7 @@ class GameUpdateFragmentAdapter extends BaseRecyclerAdapter implemen viewHolder.guName.postDelayed(() -> viewHolder.guName.setSelected(true), 2000); } - String currentVersion = PackageUtils.getVersionByPackage(updateEntity.getPackageName()); + String currentVersion = PackageUtils.getVersionNameByPackageName(updateEntity.getPackageName()); if (TextUtils.isEmpty(currentVersion)) { viewHolder.guCurrent.setText("当前:无"); } else { diff --git a/app/src/main/java/com/gh/gamecenter/download/InstalledGameFragmentAdapter.java b/app/src/main/java/com/gh/gamecenter/download/InstalledGameFragmentAdapter.java index e82bacf7ac..99bd30459f 100644 --- a/app/src/main/java/com/gh/gamecenter/download/InstalledGameFragmentAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/download/InstalledGameFragmentAdapter.java @@ -308,12 +308,12 @@ public class InstalledGameFragmentAdapter extends BaseRecyclerAdapter 0) { name = String.format("%s - %s", gameEntity.getName(), PlatformUtils.getInstance(mContext).getPlatformName(gameEntity.getApk().get(0).getPlatform())); - binding.gameIconIv.setImageDrawable(PackageUtils.getIconByPackage(mContext, gameEntity.getApk().get(0).getPackageName())); + binding.gameIconIv.setImageDrawable(PackageUtils.getIconByPackageName(mContext, gameEntity.getApk().get(0).getPackageName())); binding.gameIconDecoratorIv.setVisibility(View.GONE); if (SimulatorGameManager.isSimulatorGame(gameEntity)) { binding.gameDes.setText(String.format("V%s", gameEntity.getApk().get(0).getVersion())); } else { - binding.gameDes.setText(String.format("V%s", PackageUtils.getVersionByPackage(gameEntity.getApk().get(0).getPackageName()))); + binding.gameDes.setText(String.format("V%s", PackageUtils.getVersionNameByPackageName(gameEntity.getApk().get(0).getPackageName()))); } } else { name = gameEntity.getName(); diff --git a/app/src/main/java/com/gh/gamecenter/download/UpdatableGameAdapter.kt b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameAdapter.kt new file mode 100644 index 0000000000..ad953d615c --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameAdapter.kt @@ -0,0 +1,431 @@ +package com.gh.gamecenter.download + +import android.annotation.SuppressLint +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.core.view.setPadding +import androidx.fragment.app.FragmentActivity +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.exposure.ExposureEvent +import com.gh.common.exposure.ExposureEvent.Companion.createEvent +import com.gh.common.exposure.ExposureSource +import com.gh.common.exposure.IExposable +import com.gh.common.util.* +import com.gh.common.view.BugFixedPopupWindow +import com.gh.download.DownloadManager +import com.gh.download.dialog.DownloadDialog +import com.gh.gamecenter.DownloadManagerActivity +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.* +import com.gh.gamecenter.entity.GameUpdateEntity +import com.gh.gamecenter.eventbus.EBSkip +import com.gh.gamecenter.home.BlankDividerViewHolder +import com.gh.gamecenter.manager.PackagesManager +import com.lightgame.download.DownloadEntity +import com.lightgame.download.DownloadStatus +import org.greenrobot.eventbus.EventBus + +class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) : + RecyclerView.Adapter(), IExposable { + + private var mItemList: ArrayList? = null + private val mExposureSource by lazy { + ArrayList().apply { + add(ExposureSource("下载管理")) + add(ExposureSource("游戏更新")) + } + } + + fun submitList(dataList: ArrayList) { + mItemList = dataList + notifyDataSetChanged() + } + + override fun getItemViewType(position: Int): Int { + val item = mItemList!![position] + return when { + item.header != null || item.ignoredUpdateHeader != null -> TYPE_HEADER + item.normalUpdate != null || item.ignoredUpdate != null -> TYPE_NORMAL_GAME + item.normalUpdateWithArrow != null -> TYPE_NORMAL_GAME_WITH_ARROW + item.otherVersionUpdateHint != null -> TYPE_OTHER_VERSION_GAME_HINT + item.otherVersionUpdate != null -> TYPE_OTHER_VERSION_GAME + item.divider != null -> TYPE_DIVIDER + else -> TYPE_OTHER_VERSION_GAME + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return when (viewType) { + TYPE_HEADER -> UpdatableHeaderViewHolder(parent.toBinding()) + TYPE_NORMAL_GAME -> UpdatableGameViewHolder(parent.toBinding()) + TYPE_NORMAL_GAME_WITH_ARROW -> UpdatableGameViewHolder(parent.toBinding()) + TYPE_OTHER_VERSION_GAME -> UpdatableGameViewHolder(parent.toBinding()) + TYPE_OTHER_VERSION_GAME_HINT -> UpdatableOtherVersionGameHintViewHolder(parent.toBinding()) + TYPE_DIVIDER -> BlankDividerViewHolder(parent.toBinding()).also { + it.binding.container.layoutParams = + it.binding.container.layoutParams.apply { + height = 8F.dip2px() + } + } + else -> BlankDividerViewHolder(parent.toBinding()) + } + } + + @SuppressLint("SetTextI18n") + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + val itemData = mItemList?.get(position)!! + when (holder) { + is UpdatableHeaderViewHolder -> { + itemData.let { + holder.binding.updateAllBtn.enlargeTouchArea() + holder.binding.updateAllBtn.goneIf(!itemData.miscShowUpdateAll) + holder.binding.updateAllBtn.text = itemData.miscUpdateText + holder.binding.updateAllBtn.setOnClickListener { + if (itemData.miscUpdateText == "全部更新") { + mViewModel.updateAllMatchedVersionValidUpdate() + } + } + holder.binding.infoTv.text = itemData.header ?: itemData.ignoredUpdateHeader + if (itemData.header != null) { + holder.binding.infoTv.setTextColor(R.color.text_333333.toColor()) + holder.binding.root.setOnClickListener(null) + holder.binding.infoTv.setCompoundDrawablesWithIntrinsicBounds( + null, + null, + null, + null + ) + } else { + holder.binding.infoTv.setTextColor(R.color.text_999999.toColor()) + holder.binding.root.setOnClickListener { + mViewModel.toggleIgnoredUpdateVisibility() + } + holder.binding.infoTv.setCompoundDrawablesWithIntrinsicBounds( + null, + null, + if (mViewModel.isIgnoredUpdateExpanded()) { + R.drawable.ic_arrow_up_grey.toDrawable() + } else { + R.drawable.ic_arrow_down_grey.toDrawable() + }, + null + ) + } + } + } + is BlankDividerViewHolder -> { + if (itemData.divider == UpdatableGameViewModel.GREY) { + holder.binding.container.setBackgroundColor(R.color.text_F5F5F5.toColor()) + } else if (itemData.divider == UpdatableGameViewModel.BLUE) { + holder.binding.container.setBackgroundColor(R.color.bg_F2F7FC.toColor()) + } else { + holder.binding.container.setBackgroundColor(Color.WHITE) + } + } + is UpdatableGameViewHolder -> { + val update: GameUpdateEntity = (itemData.normalUpdate + ?: itemData.normalUpdateWithArrow + ?: itemData.otherVersionUpdate + ?: itemData.ignoredUpdate)!! + + val context = holder.binding.root.context + val pluginDesc: String = update.pluginDesc.take(3) + val downloadManager = DownloadManager.getInstance(context) + + holder.binding.run { + otherVersionHintIv.goneIf(itemData.normalUpdateWithArrow == null) + + container.setOnClickListener { + DirectUtils.directToGameDetail( + context = context, + id = update.id, + entrance = mViewModel.entrance, + traceEvent = update.exposureEvent + ) + } + + if (itemData.otherVersionUpdate != null) { + container.setBackgroundColor(R.color.bg_F2F7FC.toColor()) + } else { + container.setBackgroundColor(Color.WHITE) + } + + iconIv.displayGameIcon(update.rawIcon ?: update.icon, update.iconSubscript) + val nameText = if (!update.readablePlatform.isNullOrEmpty()) { + update.name + " - " + update.readablePlatform + } else { + update.name + } + nameTv.text = nameText + currentVersionTv.text = "当前:V${update.currentVersion}" + newVersionTv.text = "最新:V${update.version} | ${update.size}" + optionIv.goneIf(itemData.otherVersionUpdate != null) + optionIv.setOnClickListener { + showIgnoreOption(it, update, itemData.ignoredUpdate != null) + } + + val downloadEntity = downloadManager.getDownloadEntityByUrl(update.url) + updateUpdateBtn(updateBtn, downloadEntity, update, pluginDesc, downloadManager) + } + + generateExposureEvent(update) + } + is UpdatableOtherVersionGameHintViewHolder -> { + holder.binding.root.setOnClickListener { + mViewModel.toggleOtherVersionVisibility(itemData.miscPackageName) + } + if (itemData.otherVersionUpdateHint == true) { + holder.binding.selectorTv.setCompoundDrawablesWithIntrinsicBounds( + null, + null, + R.drawable.ic_arrow_up_blue.toDrawable(), + null + ) + } else { + holder.binding.selectorTv.setCompoundDrawablesWithIntrinsicBounds( + null, + null, + R.drawable.ic_arrow_down_blue.toDrawable(), + null + ) + } + holder.binding.closeHintTv.enlargeTouchArea() + holder.binding.closeHintTv.setOnClickListener { + DialogHelper.showDialog( + it.context, + title = "关闭提示", + content = "关闭提示后,将不再提示游戏其他版本的更新", + cancelText = "永不更新", + confirmText = "仅此次", + cancelClickCallback = { + mViewModel.suppressUpdate( + packageName = itemData.miscPackageName, + currentUpdatableVersion = itemData.miscVersion, + true + ) + }, + confirmClickCallback = { + mViewModel.suppressUpdate( + packageName = itemData.miscPackageName, + currentUpdatableVersion = itemData.miscVersion, + false + ) + }, + extraConfig = DialogHelper.Config(showCloseIcon = true) + ) + } + } + } + } + + override fun getItemCount() = mItemList?.size ?: 0 + + override fun getEventByPosition(pos: Int): ExposureEvent? { + return mItemList?.get(pos)?.normalUpdate?.exposureEvent + ?: mItemList?.get(pos)?.normalUpdateWithArrow?.exposureEvent + ?: mItemList?.get(pos)?.otherVersionUpdate?.exposureEvent + ?: mItemList?.get(pos)?.ignoredUpdate?.exposureEvent + } + + override fun getEventListByPosition(pos: Int): List? = null + + private fun showIgnoreOption(view: View, update: GameUpdateEntity, isUpdateIgnored: Boolean) { + val inflater = LayoutInflater.from(view.context) + val mainBinding = LayoutPopupContainerBinding.inflate(inflater) + val popupWindow = BugFixedPopupWindow( + mainBinding.root, + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ) + + LayoutPopupOptionItemBinding.inflate(inflater, mainBinding.container, false).apply { + root.layoutParams = root.layoutParams.apply { + width = 92F.dip2px() + height = 44F.dip2px() + } + hintText.setPadding(0) + if (isUpdateIgnored) { + hintText.text = "取消忽略" + } else { + hintText.text = "忽略更新" + } + + root.setOnClickListener { + if (isUpdateIgnored) { + mViewModel.undoIgnoredUpdate(update.packageName, update.version ?: "") + } else { + mViewModel.ignoreUpdate(update.packageName, update.version ?: "") + } + popupWindow.dismiss() + } + mainBinding.container.addView(root) + } + + popupWindow.isTouchable = true + popupWindow.isFocusable = true + + popupWindow.showAutoOrientation(view) + } + + private fun updateUpdateBtn( + updateBtn: TextView, + downloadEntity: DownloadEntity?, + update: GameUpdateEntity, + pluginDesc: String, + downloadManager: DownloadManager + ) { + if (downloadEntity == null) { + if (PackagesManager.isCanUpdate(update.id, update.packageName)) { + updateBtn.setText(R.string.update) + updateBtn.setTextColor(Color.WHITE) + updateBtn.setBackgroundResource(R.drawable.download_button_normal_style) + } else if (update.isPluggable) { + updateBtn.text = "${pluginDesc}化" + updateBtn.setTextColor(Color.WHITE) + val samePackageNameDownloadEntity = + downloadManager.getDownloadEntityByPackageName(update.packageName) + if (samePackageNameDownloadEntity == null || samePackageNameDownloadEntity.url == update.url) { + updateBtn.isClickable = true + updateBtn.setBackgroundResource(R.drawable.download_button_pluggable_style) + } else { + updateBtn.isClickable = false + updateBtn.setBackgroundResource(R.drawable.game_item_btn_pause_up) + } + } else { + updateBtn.setText(R.string.launch) + updateBtn.setTextColor(Color.WHITE) + updateBtn.setBackgroundResource(R.drawable.download_button_normal_style) + } + } else { + if (update.isPluggable) { + if (downloadEntity.status == DownloadStatus.done) { + updateBtn.setText(R.string.install) + updateBtn.setTextColor(Color.WHITE) + updateBtn.setBackgroundResource(R.drawable.download_button_pluggable_style) + } else { + updateBtn.setText(R.string.downloading) + updateBtn.setTextColor( + ContextCompat.getColorStateList( + updateBtn.context, + R.color.text_downloading_style + ) + ) + updateBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style) + } + } else { + if (downloadEntity.status == DownloadStatus.done) { + updateBtn.setText(R.string.install) + updateBtn.setTextColor(Color.WHITE) + updateBtn.setBackgroundResource(R.drawable.download_button_normal_style) + } else { + updateBtn.setText(R.string.downloading) + updateBtn.setTextColor( + ContextCompat.getColorStateList( + updateBtn.context, + R.color.text_downloading_style + ) + ) + updateBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style) + } + } + } + + updateBtn.setOnClickListener { + val str: String = updateBtn.text.toString() + if ("更新" == str || str.contains("化")) { + (updateBtn.context as FragmentActivity).checkStoragePermissionBeforeAction { + DialogUtils.checkDownload( + updateBtn.context, + update.size + ) { isSubscribe: Boolean -> + if (str.contains("化")) { + if (update.pluggableCollection != null) { + DownloadDialog.showDownloadDialog( + updateBtn.context, + update.transformGameEntity(), + update.exposureEvent, + mViewModel.entrance, + pluginDesc + "化:" + update.name + ) + return@checkDownload + } else { + updateBtn.setText(R.string.downloading) + updateBtn.setTextColor( + ContextCompat.getColorStateList( + updateBtn.context, + R.color.text_plugining_style + ) + ) + updateBtn.setBackgroundResource(R.drawable.game_item_btn_plugining_style) + } + } else { + updateBtn.setText(R.string.downloading) + updateBtn.setTextColor( + ContextCompat.getColorStateList( + updateBtn.context, + R.color.text_downloading_style + ) + ) + updateBtn.setBackgroundResource(R.drawable.game_item_btn_downloading_style) + } + + mViewModel.update(update, isSubscribe) + mViewModel.refreshList() + EventBus.getDefault() + .post( + EBSkip( + DownloadManagerActivity.TAG, + DownloadManagerActivity.INDEX_DOWNLOAD + ) + ) + } + } + } else if (updateBtn.context.getString(R.string.launch) == str) { + PackageUtils.launchApplicationByPackageName(updateBtn.context, update.packageName) + } else if (updateBtn.context.getString(R.string.downloading) == str) { + mViewModel.refreshList() + EventBus.getDefault().post( + EBSkip( + DownloadManagerActivity.TAG, + DownloadManagerActivity.INDEX_DOWNLOAD + ) + ) + } else if (updateBtn.context.getString(R.string.install) == str) { + PackageInstaller.install( + updateBtn.context, + DownloadManager.getInstance(updateBtn.context) + .getDownloadEntityByUrl(update.url) + ) + } + } + } + + private fun generateExposureEvent(updateEntity: GameUpdateEntity) { + updateEntity.exposureEvent = + createEvent(updateEntity.transformGameEntity(), mExposureSource) + } + + companion object { + const val TYPE_DIVIDER = 233 + const val TYPE_HEADER = 234 + const val TYPE_NORMAL_GAME = 235 + const val TYPE_NORMAL_GAME_WITH_ARROW = 236 + const val TYPE_OTHER_VERSION_GAME = 237 + const val TYPE_OTHER_VERSION_GAME_HINT = 238 + } + + class UpdatableHeaderViewHolder(val binding: ItemUpdatableGameHeaderBinding) : + RecyclerView.ViewHolder(binding.root) + + class UpdatableGameViewHolder(val binding: ItemUpdatableGameBinding) : + RecyclerView.ViewHolder(binding.root) + + class UpdatableOtherVersionGameHintViewHolder(val binding: ItemUpdatableOtherGameHintBinding) : + RecyclerView.ViewHolder(binding.root) + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/download/UpdatableGameFragment.kt b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameFragment.kt new file mode 100644 index 0000000000..7dfab6da2f --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameFragment.kt @@ -0,0 +1,84 @@ +package com.gh.gamecenter.download + +import android.view.View +import androidx.recyclerview.widget.LinearLayoutManager +import com.gh.base.fragment.LazyFragment +import com.gh.common.exposure.ExposureListener +import com.gh.common.util.EntranceUtils +import com.gh.common.util.goneIf +import com.gh.common.util.observeNonNull +import com.gh.common.util.viewModelProvider +import com.gh.gamecenter.MainActivity +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.FragmentGameUpdatableBinding +import com.gh.gamecenter.eventbus.EBDownloadStatus +import com.gh.gamecenter.eventbus.EBReuse +import com.gh.gamecenter.fragment.MainWrapperFragment +import com.gh.gamecenter.packagehelper.PackageViewModel +import kotlinx.android.synthetic.main.fragment_game_updatable.* +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +class UpdatableGameFragment : LazyFragment() { + + private var mViewModel: UpdatableGameViewModel? = null + private var mPackageViewModel: PackageViewModel? = null + private var mBinding: FragmentGameUpdatableBinding? = null + private val mAdapter: UpdatableGameAdapter by lazy { UpdatableGameAdapter(mViewModel!!) } + + override fun getRealLayoutId() = R.layout.fragment_game_updatable + override fun onRealLayoutInflated(inflatedView: View) { + mBinding = FragmentGameUpdatableBinding.bind(inflatedView) + } + + override fun onFragmentFirstVisible() { + val packageName = activity?.intent?.getStringExtra(EntranceUtils.KEY_PACKAGENAME) ?: "" + val entrance = activity?.intent?.getStringExtra(EntranceUtils.KEY_ENTRANCE) ?: "" + + mViewModel = viewModelProvider(UpdatableGameViewModel.Factory(packageName, entrance)) + + super.onFragmentFirstVisible() + + mPackageViewModel = viewModelProvider(PackageViewModel.Factory()) + mPackageViewModel?.getGameUpdateIncludeCurrentVersion() + ?.observeNonNull(viewLifecycleOwner) { updatableList -> + mViewModel?.setUpdatableList(updatableList) + } + mViewModel?.updatableData?.observe(viewLifecycleOwner) { + mAdapter.submitList(it) + mBinding?.noDataContainer?.root?.goneIf(!it.isNullOrEmpty()) + } + } + + override fun initRealView() { + super.initRealView() + + mBinding?.run { + noDataContainer.reuseNodataSkipTvHint.text = "暂无更新" + noDataContainer.reuseNodataSkipTvBtn.text = "去首页看看" + noDataContainer.reuseNodataSkipTvBtn.setOnClickListener { + MainActivity.skipToMainActivity(activity, MainWrapperFragment.INDEX_HOME) + } + recyclerView.layoutManager = LinearLayoutManager(requireContext()) + recyclerView.adapter = mAdapter.also { + recyclerView.addOnScrollListener(ExposureListener(this@UpdatableGameFragment, it)) + } + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(status: EBDownloadStatus) { + if ("delete" == status.status || "download" == status.status || "done" == status.status) { + mViewModel?.refreshList() + } + } + + // 更新平台信息 + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(reuse: EBReuse) { + if ("PlatformChanged" == reuse.type && isAdded) { + mViewModel?.refreshList() + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt new file mode 100644 index 0000000000..245cfbe3ac --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt @@ -0,0 +1,660 @@ +package com.gh.gamecenter.download + +import android.app.Application +import android.view.View +import androidx.lifecycle.* +import com.gh.base.BaseSimpleDao +import com.gh.common.constant.Constants +import com.gh.common.exposure.ExposureUtils +import com.gh.common.exposure.ExposureUtils.logADownloadExposureEvent +import com.gh.common.history.HistoryHelper.insertGameEntity +import com.gh.common.util.* +import com.gh.common.util.GsonUtils.toJson +import com.gh.common.util.PackageInstaller.createDownloadId +import com.gh.common.util.PackageInstaller.getDownloadPathWithId +import com.gh.download.DownloadManager +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.entity.GameUpdateEntity +import com.gh.gamecenter.entity.PluginLocation +import com.gh.gamecenter.eventbus.EBDownloadChanged +import com.gh.gamecenter.retrofit.Response +import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp +import com.lightgame.download.DownloadEntity +import com.lightgame.download.DownloadStatus +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers +import org.greenrobot.eventbus.EventBus +import java.util.* +import kotlin.collections.ArrayList + +class UpdatableGameViewModel( + application: Application, + private var mSpecialPackageName: String, + var entrance: String +) : AndroidViewModel(application) { + + private var mRawUpdatableList = ArrayList() + private var mUpdatableItemDataList = ArrayList() // 最终暴露给 View 层装饰好的数据 + + private var mPackageUpdateList = ArrayList() // 包名更新列表,包括了我的版本和其它版本 (如果存在的话) + + private var mUpdatableListLiveData = MutableLiveData>() + + private val mSuppressUpdateDao by lazy { SuppressUpdateDao() } + private val mIgnoredUpdateDao by lazy { IgnoredUpdateDao() } + private val mDownloadedGameIdAndPackageNameDao by lazy { DownloadedGameIdAndPackageNameDao() } + + // 缓存的匹配的游戏列表,列表刷新是会同时更新 + private val mCachedMatchedVersionValidUpdateList by lazy { arrayListOf() } + + private val mOtherVersionExpandedMap by lazy { hashMapOf() } + private var mShouldShowIgnoredUpdate = false + + var updatableData: LiveData> = mUpdatableListLiveData + + /** + * 更新可更新数据列表 + */ + fun setUpdatableList(updatableList: List) { + if (mRawUpdatableList != updatableList) { + mRawUpdatableList.clear() + + for (update in updatableList) { + // 筛选仅下载管理出现的插件化更新 + if (update.isShowPlugin(PluginLocation.only_index)) { + val platform = + PlatformUtils.getInstance(getApplication()).getPlatformName(update.platform) + if (!platform.isNullOrEmpty() && "官方版" != platform) { + update.readablePlatform = platform + } + + mRawUpdatableList.add(update) + } + } + } + + mUpdatableItemDataList.clear() + + sortUpdatableListByType(mRawUpdatableList) + + mPackageUpdateList = constructPackageUpdateList(mRawUpdatableList) + + mUpdatableItemDataList = transformUpdatableListIntoUpdatableItemDataList(mPackageUpdateList) + + if (mRawUpdatableList.isNotEmpty()) { + // TODO 父子 Fragment 共享同一个 ViewModel 来实现数据交流 + EventBus.getDefault().post( + EBDownloadChanged( + "update", + View.VISIBLE, + mCachedMatchedVersionValidUpdateList.size + ) + ) + } + + if (mSpecialPackageName.isNotEmpty()) { + var isAlreadyExisted = false + for (update in mRawUpdatableList) { + if (update.packageName == mSpecialPackageName) { + isAlreadyExisted = true + break + } + } + if (!isAlreadyExisted) { + getUpdateInfoByPackageName(mSpecialPackageName) + } + } + + mUpdatableListLiveData.postValue(mUpdatableItemDataList) + } + + /** + * 构建我的版本和其它版本列表(供后续修改处理) + */ + private fun constructPackageUpdateList(updatableList: ArrayList) + : ArrayList { + // 包名数组列表,因为 hashmap 在不同的系统版本上的实现不一样,在部分系统上会根据 key 的值重排序破坏列表顺序 + val packageNameList = arrayListOf() + val packageNameAndUpdateListMap = hashMapOf>() + val packageUpdateList: ArrayList = arrayListOf() + + // 按包名分 + for (update in updatableList) { + var list = packageNameAndUpdateListMap[update.packageName] + if (list == null) { + list = arrayListOf() + packageNameList.add(update.packageName) + packageNameAndUpdateListMap[update.packageName] = list + } + list.add(update) + } + + // 找到我的版本 + for (packageName in packageNameList) { + val samePackageNameUpdateList = + packageNameAndUpdateListMap[packageName] ?: arrayListOf() + val installedSignature = + PackageUtils.getApkSignatureByPackageName(getApplication(), packageName) + val isInstalledSignByGh = PackageUtils.isSignedByGh(getApplication(), packageName) + val installedGhId = if (isInstalledSignByGh) PackageUtils.getGhId(packageName) else null + val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName) ?: "" + + var matchedVersionUpdate: GameUpdateEntity? = null + val mismatchedVersionUpdateList: ArrayList = arrayListOf() + + // 已安装的游戏为插件游戏,找插件包里的 GH_ID 跟我的版本一样的作为我的版本 + if (isInstalledSignByGh && installedGhId != null) { + for (update in samePackageNameUpdateList) { + if (update.id == installedGhId) { + matchedVersionUpdate = update + } else { + mismatchedVersionUpdateList.add(update) + } + } + } else if (samePackageNameUpdateList.find { it.signature == installedSignature } != null) { + // 存在同包名同签名的游戏,以同包名同签名的游戏作为我的版本 + for (update in samePackageNameUpdateList) { + if (installedSignature == update.signature) { + matchedVersionUpdate = update + } else { + mismatchedVersionUpdateList.add(update) + } + } + } else if (mDownloadedGameIdAndPackageNameDao.getRawString().contains(packageName)) { + // 光环曾经下载过对应包名的游戏,找到对应游戏ID的更新作为我的版本 + val idAndPackageNameString = mDownloadedGameIdAndPackageNameDao.getRawString() + for (update in samePackageNameUpdateList) { + if (matchedVersionUpdate == null && idAndPackageNameString.contains(update.id)) { + matchedVersionUpdate = update + } else { + mismatchedVersionUpdateList.add(update) + } + } + } else { + // 以同包名中七天下载量最高的游戏作为我的版本 + for (update in samePackageNameUpdateList) { + if (update.download >= matchedVersionUpdate?.download ?: 0) { + matchedVersionUpdate = update + } + + mismatchedVersionUpdateList.add(update) + } + + mismatchedVersionUpdateList.remove(matchedVersionUpdate) + mismatchedVersionUpdateList.sortBy { it.download } + } + + // 清理 mismatchedVersionUpdateList 的同版本数据,同版本只在找不到 matchedVersion 的时候作替补用 + val iterator = mismatchedVersionUpdateList.iterator() + while (iterator.hasNext()) { + val update = iterator.next() + if (update.version == installedVersionName) { + iterator.remove() + continue + } + } + + // 不存在匹配版本 + // 或者匹配版本与已安装版本相同,但不是插件化没有其它可更新版本的不需要添加进列表中 + if (matchedVersionUpdate == null || + (matchedVersionUpdate.version == installedVersionName + && !matchedVersionUpdate.isPluggable + && mismatchedVersionUpdateList.isEmpty()) + ) { + continue + } + + // TODO 我的版本应该不会为空吧? + packageUpdateList.add( + PackageUpdate( + matchedVersionUpdate, + mismatchedVersionUpdateList + ) + ) + } + return packageUpdateList + } + + /** + * 将我的版本和其它版本列表变形成列表可显示的数据 + */ + private fun transformUpdatableListIntoUpdatableItemDataList(packageUpdateList: ArrayList) + : ArrayList { + val updatableDataItemList = arrayListOf() + + val validPackageUpdateList: ArrayList = arrayListOf() // 按钮为更新的我的游戏列表 + val invalidPackageUpdateList: ArrayList = arrayListOf() // 按钮为启动的我的游戏列表 + val ignoredPackageUpdateList: ArrayList = arrayListOf() // 被隐藏的我的游戏列表 + + val permanentSuppressedUpdatePackageNameList = mSuppressUpdateDao.getAll() + val ignoredUpdateList = mIgnoredUpdateDao.getAll() + + mCachedMatchedVersionValidUpdateList.clear() + + for (packageUpdate in packageUpdateList) { + val matchedPackageName = packageUpdate.matchedVersionUpdate.packageName + val matchedVersionName = packageUpdate.matchedVersionUpdate.version + val currentlyUpdatableVersion = packageUpdate.matchedVersionUpdate.currentVersion + + // 类型不为单机游戏/gj单机的游戏或选择了临时隐藏或永久隐藏的不需要显示其它版本 + if ((packageUpdate.matchedVersionUpdate.category != "local" && packageUpdate.matchedVersionUpdate.category != "gjlocal") + || permanentSuppressedUpdatePackageNameList?.contains(matchedPackageName) == true + || SPUtils.getBoolean(SP_TEMPORARY_SUPPRESS_UPDATE_PREFIX + matchedPackageName + currentlyUpdatableVersion) + ) { + packageUpdate.mismatchedVersionUpdateList.clear() + } + + // 被忽略的更新不需要显示其它版本 + if (ignoredUpdateList?.contains(matchedPackageName + matchedVersionName) == true) { + // 若我的版本与当前应用版本一致那么取其它版本的第一个来替换成我的版本 (避免出现忽略更新列表显示按钮为启动的问题) +// if (packageUpdate.matchedVersionUpdate.version == PackageUtils.getVersionNameByPackageName(packageName) +// && packageUpdate.mismatchedVersionUpdateList.isNotEmpty()) { +// packageUpdate.matchedVersionUpdate = packageUpdate.mismatchedVersionUpdateList.first() +// } + packageUpdate.mismatchedVersionUpdateList.clear() + } + + // 根据状态分子列表 + // 1. 按钮为更新的我的游戏 + // 2. 按钮为启动的我的游戏 + // 3. 忽略更新的游戏 + when { + ignoredUpdateList?.contains(matchedPackageName + matchedVersionName) == true -> { + ignoredPackageUpdateList.add(packageUpdate) + } + packageUpdate.matchedVersionUpdate.version == currentlyUpdatableVersion + && !packageUpdate.matchedVersionUpdate.isPluggable -> { + invalidPackageUpdateList.add(packageUpdate) + } + else -> { + validPackageUpdateList.add(packageUpdate) + } + } + } + + // 构建装饰好的页面列表 + if (validPackageUpdateList.isNotEmpty()) { + var totalMatchedVersionValidUpdateSize = 0L + val matchedVersionValidUpdateUrlList = arrayListOf() + val updateCount = validPackageUpdateList.size + for (packageUpdate in validPackageUpdateList) { + // 上一个样式为其它版本,添加白色分割线 + if (updatableDataItemList.lastOrNull()?.otherVersionUpdateHint != null + || updatableDataItemList.lastOrNull()?.otherVersionUpdate != null + ) { + updatableDataItemList.add(UpdatableDataItem(divider = WHITE)) + } + + if (packageUpdate.mismatchedVersionUpdateList.isNotEmpty()) { + updatableDataItemList.add(UpdatableDataItem(normalUpdateWithArrow = packageUpdate.matchedVersionUpdate)) + updatableDataItemList.add( + UpdatableDataItem( + otherVersionUpdateHint = mOtherVersionExpandedMap[packageUpdate.matchedVersionUpdate.packageName] == true, + miscPackageName = packageUpdate.matchedVersionUpdate.packageName, + miscVersion = packageUpdate.matchedVersionUpdate.currentVersion ?: "" + ) + ) + if (mOtherVersionExpandedMap[packageUpdate.matchedVersionUpdate.packageName] == true) { + for (update in packageUpdate.mismatchedVersionUpdateList) { + updatableDataItemList.add(UpdatableDataItem(otherVersionUpdate = update)) + } + updatableDataItemList.add(UpdatableDataItem(divider = BLUE)) + } + } else { + updatableDataItemList.add(UpdatableDataItem(normalUpdate = packageUpdate.matchedVersionUpdate)) + } + + mCachedMatchedVersionValidUpdateList.add(packageUpdate.matchedVersionUpdate) + + totalMatchedVersionValidUpdateSize += sizeStringToLong( + packageUpdate.matchedVersionUpdate.size ?: "0M" + ) + + matchedVersionValidUpdateUrlList.add(packageUpdate.matchedVersionUpdate.url ?: "") + } + + val text = getUpdateTextFromUrlList(matchedVersionValidUpdateUrlList) + + updatableDataItemList.add( + 0, + UpdatableDataItem( + header = "${updateCount}个游戏可更新,共${ + totalMatchedVersionValidUpdateSize.toProperReadableSize().replace(" ", "") + }", + miscShowUpdateAll = true, + miscUpdateText = text + ) + ) + updatableDataItemList.add(0, UpdatableDataItem(divider = GREY)) + } + + if (invalidPackageUpdateList.isNotEmpty()) { + if (updatableDataItemList.size != 0) { + updatableDataItemList.add(UpdatableDataItem(divider = WHITE)) + } + updatableDataItemList.add(UpdatableDataItem(divider = GREY)) + updatableDataItemList.add(UpdatableDataItem(header = "以下游戏有其他版本可以更新")) + for (packageUpdate in invalidPackageUpdateList) { + if (packageUpdate.mismatchedVersionUpdateList.isNotEmpty()) { + updatableDataItemList.add(UpdatableDataItem(normalUpdateWithArrow = packageUpdate.matchedVersionUpdate)) + updatableDataItemList.add( + UpdatableDataItem( + otherVersionUpdateHint = mOtherVersionExpandedMap[packageUpdate.matchedVersionUpdate.packageName] == true, + miscPackageName = packageUpdate.matchedVersionUpdate.packageName + ) + ) + if (mOtherVersionExpandedMap[packageUpdate.matchedVersionUpdate.packageName] == true) { + for (update in packageUpdate.mismatchedVersionUpdateList) { + updatableDataItemList.add(UpdatableDataItem(otherVersionUpdate = update)) + } + updatableDataItemList.add(UpdatableDataItem(divider = BLUE)) + } + } else { + updatableDataItemList.add(UpdatableDataItem(normalUpdate = packageUpdate.matchedVersionUpdate)) + } + } + updatableDataItemList.add(UpdatableDataItem(divider = WHITE)) + } + + if (ignoredPackageUpdateList.isNotEmpty()) { + updatableDataItemList.add(UpdatableDataItem(divider = WHITE)) + updatableDataItemList.add(UpdatableDataItem(divider = GREY)) + updatableDataItemList.add(UpdatableDataItem(ignoredUpdateHeader = "${ignoredPackageUpdateList.size}个游戏已忽略更新")) + if (mShouldShowIgnoredUpdate) { + for (packageUpdate in ignoredPackageUpdateList) { + updatableDataItemList.add(UpdatableDataItem(ignoredUpdate = packageUpdate.matchedVersionUpdate)) + } + } + } + + return updatableDataItemList + } + + /** + * 根据所给的 url 列表返回头部右上角的文本内容 + */ + private fun getUpdateTextFromUrlList(matchedVersionValidUpdateUrlList: ArrayList) + : String { + var updateTaskCount = 0 + var updateCompleteTaskCount = 0 + for (url in matchedVersionValidUpdateUrlList) { + val downloadEntity = DownloadManager.getInstance(getApplication()) + .getDownloadEntityByUrl(url) + if (downloadEntity != null) { + updateTaskCount++ + if (downloadEntity.status == DownloadStatus.done) { + updateCompleteTaskCount++ + } + } + } + + return if (updateCompleteTaskCount == matchedVersionValidUpdateUrlList.size) { + "更新完成" + } else { + if (updateTaskCount == matchedVersionValidUpdateUrlList.size) { + "更新中" + } else { + "全部更新" + } + } + } + + /** + * 根据类型排序 + */ + private fun sortUpdatableListByType(list: List) { + tryCatchInRelease { + Collections.sort(list) { lhs, rhs -> + if ("光环助手" == rhs?.name) { + 1 + } else if (lhs?.name?.contains("光环助手") == true) { + -1 + } else if (lhs?.isPluggable != true && rhs?.isPluggable == true) { + -1 + } else if (lhs?.isPluggable == true && rhs?.isPluggable != true) { + 1 + } else { + 0 + } + } + } + } + + private fun getUpdateInfoByPackageName(packageName: String) { + val ghId: Any? = PackageUtils.getMetaData(getApplication(), packageName, "gh_id") + val retrofit = RetrofitManager.getInstance(getApplication()).api + + if (ghId == null) { + retrofit.loadGameDataByPackageName( + UrlFilterUtils.getFilterQuery("package", packageName) + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response?>() { + override fun onResponse(response: List?) { + response?.let { + for (game in response) { + val simpleUpdatableList: List = + PackageUtils.getUpdateData(game) + + if (simpleUpdatableList.isNotEmpty()) { + mRawUpdatableList.addAll(simpleUpdatableList) + } + } + } + refreshList() + } + }) + } else { + retrofit.getGameUpdateById(ghId as String) + .map(ApkActiveUtils.filterMapper) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: GameEntity?) { + val simpleUpdatableList: List = + PackageUtils.getUpdateData(response) + + mRawUpdatableList.addAll(simpleUpdatableList) + + refreshList() + } + }) + } + + mSpecialPackageName = "" + } + + fun toggleIgnoredUpdateVisibility() { + mShouldShowIgnoredUpdate = !mShouldShowIgnoredUpdate + setUpdatableList(mRawUpdatableList) + } + + fun toggleOtherVersionVisibility(packageName: String) { + mOtherVersionExpandedMap[packageName] = !(mOtherVersionExpandedMap[packageName] ?: false) + setUpdatableList(mRawUpdatableList) + } + + fun suppressUpdate( + packageName: String, + currentUpdatableVersion: String, + suppressPermanently: Boolean + ) { + if (suppressPermanently) { + mSuppressUpdateDao.add(packageName) + } else { + SPUtils.setBoolean( + SP_TEMPORARY_SUPPRESS_UPDATE_PREFIX + packageName + currentUpdatableVersion, + true + ) + } + setUpdatableList(mRawUpdatableList) + } + + fun ignoreUpdate(packageName: String, versionName: String) { + mIgnoredUpdateDao.add(packageName + versionName) + setUpdatableList(mRawUpdatableList) + } + + fun undoIgnoredUpdate(packageName: String, versionName: String) { + mIgnoredUpdateDao.delete(packageName + versionName) + setUpdatableList(mRawUpdatableList) + } + + fun isIgnoredUpdateExpanded(): Boolean { + return mShouldShowIgnoredUpdate + } + + /** + * 全部更新 (版本匹配的我的版本) + */ + fun updateAllMatchedVersionValidUpdate() { + for (update in mCachedMatchedVersionValidUpdateList) { + update(update, false) + } + } + + /** + * 更新列表状态 + */ + fun refreshList() { + setUpdatableList(mRawUpdatableList) + } + + /** + * 执行单个更新 + * @param update 更新内容 + * @param isSubscribe 是否延迟到连上 WIFI 才下载 + */ + fun update(update: GameUpdateEntity, isSubscribe: Boolean) { + val downloadType: ExposureUtils.DownloadType + val downloadId = createDownloadId(update.name) + + val downloadEntity = DownloadEntity() + downloadEntity.gameId = update.id + downloadEntity.url = update.url + downloadEntity.name = update.name + downloadEntity.path = getDownloadPathWithId(downloadId, update.format) + downloadEntity.eTag = update.etag + downloadEntity.icon = update.icon + downloadEntity.platform = update.platform + downloadEntity.packageName = update.packageName + downloadEntity.versionName = update.version + downloadEntity.addMetaExtra(Constants.RAW_GAME_ICON, update.rawIcon) + downloadEntity.addMetaExtra(Constants.GAME_ICON_SUBSCRIPT, update.iconSubscript) + downloadEntity.addMetaExtra(Constants.DOWNLOAD_ID, downloadId) + + val platform = PlatformUtils.getInstance(getApplication()).getPlatformName(update.platform) + if ("官方版" != platform) { + downloadEntity.isPlugin = true + } + if (update.isPluggable) { + downloadEntity.isPluggable = true + } else { + downloadEntity.isUpdate = true + } + + // 确定下载类型 + downloadType = when { + downloadEntity.isPluggable -> ExposureUtils.DownloadType.PLUGIN_DOWNLOAD + downloadEntity.isPlugin -> ExposureUtils.DownloadType.PLUGIN_UPDATE + else -> ExposureUtils.DownloadType.UPDATE + } + + val gameEntity = GameEntity(update.id, update.name) + gameEntity.gameVersion = update.version ?: "" + + val event = logADownloadExposureEvent( + gameEntity, + update.platform, + update.exposureEvent, + downloadType + ) + + downloadEntity.exposureTrace = toJson(event) + downloadEntity.entrance = "$entrance+(下载管理:游戏更新)" + downloadEntity.location = "游戏更新:列表" + if (update.name?.contains("光环助手") == true) { + DownloadManager.getInstance(getApplication()).pauseAll() + } + if (isSubscribe) { + DownloadManager.getInstance(getApplication()).subscribe(downloadEntity) + } else { + insertGameEntity(update) + DownloadManager.getInstance(getApplication()).add(downloadEntity) + } + + // 收集下载数据 + DataCollectionUtils.uploadDownload(getApplication(), downloadEntity, "开始") + } + + private fun sizeStringToLong(sizeString: String): Long { + val lastM = sizeString.lastIndexOf("M") + if (lastM != -1) { + return (sizeString.substring(0, lastM).toFloat() * 1024 * 1024).toLong() + } + return 0L + } + + companion object { + const val SP_TEMPORARY_SUPPRESS_UPDATE_PREFIX = "temporary_suppressed_update_prefix_" + + const val WHITE = "white" + const val GREY = "grey" + const val BLUE = "blue" + } + + /** + * - 分割线(包括灰色,白色和浅蓝色) + * - 信息头(包括更新信息和普通文本) + * - 忽略更新信息头 + * - 普通游戏 + * - 含小箭头的普通游戏 + * - 其它版本游戏 + * - 其它版本游戏提示(包括展开和收起状态) + * + * - 其它信息(包名) + */ + data class UpdatableDataItem( + var divider: String? = null, + var header: String? = null, + var ignoredUpdateHeader: String? = null, + var normalUpdate: GameUpdateEntity? = null, + var normalUpdateWithArrow: GameUpdateEntity? = null, + var ignoredUpdate: GameUpdateEntity? = null, + var otherVersionUpdate: GameUpdateEntity? = null, + var otherVersionUpdateHint: Boolean? = null, + + // 其它信息,是上面单独 item 信息的补充 + var miscPackageName: String = "", // 包名 + var miscVersion: String = "", // 版本 + var miscShowUpdateAll: Boolean = false, // 显示更新全部按钮 + var miscUpdateText: String = "" // 更新按钮的文案 (有`全部更新`,`更新中`,`已更新`三种) + ) + + private data class PackageUpdate( + var matchedVersionUpdate: GameUpdateEntity, // AKA 我的版本 + var mismatchedVersionUpdateList: ArrayList + ) + + private class SuppressUpdateDao : BaseSimpleDao() { + override fun getSPKey(): String = "suppressed_update" + } + + private class IgnoredUpdateDao : BaseSimpleDao() { + override fun getSPKey(): String = "ignored_update" + } + + class Factory(private var mSpecialPackageName: String, private var mEntrance: String) : + ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T { + return UpdatableGameViewModel( + HaloApp.getInstance().application, + mSpecialPackageName, + mEntrance + ) as T + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/energy/CommodityFragment.kt b/app/src/main/java/com/gh/gamecenter/energy/CommodityFragment.kt index 90d49b237f..e8bb2c0eab 100644 --- a/app/src/main/java/com/gh/gamecenter/energy/CommodityFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/energy/CommodityFragment.kt @@ -56,7 +56,7 @@ class CommodityFragment : ListFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - mListRv.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) + mListRv?.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) mListRv?.layoutParams = (mListRv?.layoutParams as ViewGroup.MarginLayoutParams).apply { leftMargin = 12F.dip2px() rightMargin = 12F.dip2px() @@ -81,11 +81,11 @@ class CommodityFragment : ListFragment() { sizeTv.text = entity.name if (index == mCurrentIndex) { - sizeTv.setTextColor(R.color.theme_font.toColor()) - sizeTv.setBackgroundResource(R.drawable.button_round_e6f9fa) + sizeTv.setTextColor(R.color.white.toColor()) + sizeTv.setBackgroundResource(R.drawable.button_round_00dba4) } else { sizeTv.setTextColor(R.color.text_333333.toColor()) - sizeTv.setBackgroundResource(R.drawable.button_round_f5f5f5) + sizeTv.setBackgroundResource(R.drawable.button_round_ebf9fa) } root.setOnClickListener { @@ -125,7 +125,7 @@ class CommodityFragment : ListFragment() { sizeTv.text = "更多 >" sizeTv.setTextColor(R.color.text_333333.toColor()) - sizeTv.setBackgroundResource(R.drawable.button_round_f5f5f5) + sizeTv.setBackgroundResource(R.drawable.button_round_ebf9fa) root.setOnClickListener { IntegralLogHelper.run { @@ -160,12 +160,12 @@ class CommodityFragment : ListFragment() { } } - mListRv.addOnScrollListener(object : RecyclerView.OnScrollListener() { + mListRv?.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { super.onScrollStateChanged(recyclerView, newState) - if (mEntrance == "光能中心" && mListRv.layoutManager?.itemCount ?:0 == 11) { - mListRv.layoutManager?.run { + if (mEntrance == "光能中心" && mListRv?.layoutManager?.itemCount ?:0 == 11) { + mListRv?.layoutManager?.run { if (childCount > 0 && newState == RecyclerView.SCROLL_STATE_IDLE && mLastVisibleItemPosition >= itemCount - 1) { mBinding.bottom.visibility = View.VISIBLE } else { @@ -177,8 +177,8 @@ class CommodityFragment : ListFragment() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) - if (mEntrance == "光能中心" && mListRv.layoutManager?.itemCount ?:0 == 11) { - mListRv.layoutManager?.run { + if (mEntrance == "光能中心" && mListRv?.layoutManager?.itemCount ?:0 == 11) { + mListRv?.layoutManager?.run { if (mLastPositions == null) { mLastPositions = IntArray((this as StaggeredGridLayoutManager).spanCount) } @@ -209,11 +209,11 @@ class CommodityFragment : ListFragment() { sizeTv.text = entity.name if (index == mCurrentIndex) { - sizeTv.setTextColor(R.color.theme_font.toColor()) - sizeTv.setBackgroundResource(R.drawable.button_round_e6f9fa) + sizeTv.setTextColor(R.color.white.toColor()) + sizeTv.setBackgroundResource(R.drawable.button_round_00dba4) } else { sizeTv.setTextColor(R.color.text_333333.toColor()) - sizeTv.setBackgroundResource(R.drawable.button_round_f5f5f5) + sizeTv.setBackgroundResource(R.drawable.button_round_ebf9fa) } root.setOnClickListener { @@ -243,7 +243,7 @@ class CommodityFragment : ListFragment() { sizeTv.text = "更多 >" sizeTv.setTextColor(R.color.text_333333.toColor()) - sizeTv.setBackgroundResource(R.drawable.button_round_f5f5f5) + sizeTv.setBackgroundResource(R.drawable.button_round_ebf9fa) root.setOnClickListener { IntegralLogHelper.run { @@ -276,11 +276,11 @@ class CommodityFragment : ListFragment() { for (index in 0 until categoryContainer.childCount) { val sizeTv = categoryContainer.getChildAt(index) as TextView if (index == mCurrentIndex) { - sizeTv.setTextColor(R.color.theme_font.toColor()) - sizeTv.setBackgroundResource(R.drawable.button_round_e6f9fa) + sizeTv.setTextColor(R.color.white.toColor()) + sizeTv.setBackgroundResource(R.drawable.button_round_00dba4) } else { sizeTv.setTextColor(R.color.text_333333.toColor()) - sizeTv.setBackgroundResource(R.drawable.button_round_f5f5f5) + sizeTv.setBackgroundResource(R.drawable.button_round_ebf9fa) } } } @@ -325,9 +325,9 @@ class CommodityFragment : ListFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - if (mEntrance == "光能中心") { +// if (mEntrance == "光能中心") { mListRefresh?.isNestedScrollingEnabled = false - } +// } } override fun onDestroyView() { @@ -345,15 +345,15 @@ class CommodityFragment : ListFragment() { override fun onLoadEmpty() { super.onLoadEmpty() // RecyclerView 被隐藏的话会导致不能 AppBar 不能滑动 - mListRv.visibility = View.VISIBLE + mListRv?.visibility = View.VISIBLE } override fun onLoadError() { super.onLoadError() - mListRv.visibility = View.VISIBLE + mListRv?.visibility = View.VISIBLE } fun setNestedScrollingEnabled(enable: Boolean) { - mListRv.isNestedScrollingEnabled = enable + mListRv?.isNestedScrollingEnabled = enable } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/energy/EnergyCenterActivity.kt b/app/src/main/java/com/gh/gamecenter/energy/EnergyCenterActivity.kt index 0005058712..ac81cc2502 100644 --- a/app/src/main/java/com/gh/gamecenter/energy/EnergyCenterActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/energy/EnergyCenterActivity.kt @@ -24,20 +24,11 @@ class EnergyCenterActivity : NormalActivity() { companion object { fun getIntent(context: Context?): Intent? { - return getIntent(context, false, 0) - } - - fun getIntent(context: Context?, isSign: Boolean): Intent? { - return getIntent(context, isSign, 0) + return getIntent(context, 0) } fun getIntent(context: Context?, initTabIndex: Int): Intent? { - return getIntent(context, false, initTabIndex) - } - - fun getIntent(context: Context?, isSign: Boolean = false, initTabIndex: Int): Intent? { val bundle = Bundle() - bundle.putBoolean(EntranceUtils.KEY_IS_SIGN, isSign) bundle.putInt(EntranceUtils.KEY_TAB_INDEX, if (initTabIndex == 0 || initTabIndex == 1) initTabIndex else 0) return getTargetIntent(context, EnergyCenterActivity::class.java, EnergyCenterFragment::class.java, bundle) } diff --git a/app/src/main/java/com/gh/gamecenter/energy/EnergyCenterFragment.kt b/app/src/main/java/com/gh/gamecenter/energy/EnergyCenterFragment.kt index 8dfc4f1c19..b6602b7940 100644 --- a/app/src/main/java/com/gh/gamecenter/energy/EnergyCenterFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/energy/EnergyCenterFragment.kt @@ -1,22 +1,20 @@ package com.gh.gamecenter.energy +import android.graphics.Typeface import android.os.Build import android.os.Bundle import android.util.DisplayMetrics import android.view.LayoutInflater import android.view.View -import android.widget.CheckedTextView -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.RelativeLayout +import android.widget.* import androidx.fragment.app.Fragment import butterknife.OnClick import com.gh.base.adapter.FragmentAdapter import com.gh.base.fragment.BaseLazyFragment -import com.gh.common.constant.Constants import com.gh.common.util.* import com.gh.gamecenter.R import com.gh.gamecenter.databinding.FragmentEnergyCenterBinding +import com.gh.gamecenter.databinding.TabItemMainBinding import com.gh.gamecenter.entity.CommodityCategoryEntity import com.gh.gamecenter.entity.SignStatusEntity import com.gh.gamecenter.entity.UserInfoEntity @@ -24,8 +22,8 @@ import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.personalhome.UserHomeViewModel import com.gh.gamecenter.user.UserViewModel import com.google.android.material.bottomsheet.BottomSheetBehavior -import com.google.android.material.tabs.TabLayout import com.halo.assistant.HaloApp +import kotlin.math.abs class EnergyCenterFragment : BaseLazyFragment() { @@ -35,11 +33,11 @@ class EnergyCenterFragment : BaseLazyFragment() { private var mUserHomeViewModel: UserHomeViewModel? = null private var mEnergyCenterViewModel: EnergyCenterViewModel? = null private val mTitleList = listOf("赚光能", "兑换区") + private var mTabList = arrayListOf() private var mFragmentsList = ArrayList() private var mCategoryList = ArrayList() private var mUserInfo: UserInfoEntity? = null - private var mEnergy = 0 - private var mAutoSign = false + private var mEnergy = 0L private var mSignStatus: SignStatusEntity? = null private var mInitTabIndex = 0 private var mBehavior: BottomSheetBehavior? = null @@ -52,20 +50,6 @@ class EnergyCenterFragment : BaseLazyFragment() { override fun onFragmentResume() { super.onFragmentResume() - // 6:00-18:59 展示白天背景,否则展示夜晚背景 - if (System.currentTimeMillis() >= TimeUtils.getTimeOfToday(6) - && System.currentTimeMillis() < TimeUtils.getTimeOfToday(19) ) { - mBinding?.run { - background.setImageResource(R.drawable.bg_energy_center_day) - signTitle.setTextColor(R.color.theme_font.toColor()) - } - } else { - mBinding?.run { - background.setImageResource(R.drawable.bg_energy_center_night) - signTitle.setTextColor(R.color.white.toColor()) - } - } - if (NetworkUtils.isNetworkConnected(requireContext())) { if (CheckLoginUtils.isLogin()) { mUserHomeViewModel?.getUserEnergy() @@ -77,7 +61,6 @@ class EnergyCenterFragment : BaseLazyFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - mAutoSign = arguments?.getBoolean(EntranceUtils.KEY_IS_SIGN) ?: false mInitTabIndex = arguments?.getInt(EntranceUtils.KEY_TAB_INDEX) ?: 0 if (mInitTabIndex != 0 && mInitTabIndex != 1) mInitTabIndex = 0 @@ -107,13 +90,12 @@ class EnergyCenterFragment : BaseLazyFragment() { mUserHomeViewModel?.energy?.observeNonNull(viewLifecycleOwner) { mEnergy = it - mBinding?.userEnergy?.text = "${it}光能" + mBinding?.userEnergy?.text = it.toString() } mUserHomeViewModel?.sign?.observeNonNull(this) { mSignStatus = it DialogUtils.showSignSuccessDialog(requireContext()) { - initSignView(it) mUserHomeViewModel?.getUserEnergy() refreshTaskList() } @@ -121,18 +103,17 @@ class EnergyCenterFragment : BaseLazyFragment() { mUserHomeViewModel?.signStatus?.observeNonNull(this) { mSignStatus = it - initSignView(it) // 今天未签到且需要自动签到才调用签到接口 - if (!it.todaySignIn && mAutoSign && !ClickUtils.isFastDoubleClick(990)) { + if (!it.todaySignIn && !ClickUtils.isFastDoubleClick(990)) { mUserHomeViewModel?.signIn() } } mBinding?.run { - background.layoutParams = background.layoutParams.apply { - val screenWidth = resources.displayMetrics.widthPixels - height = screenWidth * 400 / 360 - } +// background.layoutParams = background.layoutParams.apply { +// val screenWidth = resources.displayMetrics.widthPixels +// height = screenWidth * 400 / 360 +// } val screenHeight = when { Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 -> { @@ -154,15 +135,22 @@ class EnergyCenterFragment : BaseLazyFragment() { } mBehavior = BottomSheetBehavior.from(bottomSheet) - val toolbarHeight = screenHeight - DisplayUtils.getStatusBarHeight(resources) - 48F.dip2px() - mBehavior?.peekHeight = screenHeight - 312F.dip2px() +// val toolbarHeight = screenHeight - DisplayUtils.getStatusBarHeight(resources) - 48F.dip2px() + mBehavior?.peekHeight = screenHeight - 320F.dip2px() - val layoutParams = bottomSheet.layoutParams - layoutParams.height = toolbarHeight - bottomSheet.layoutParams = layoutParams +// val layoutParams = bottomSheet.layoutParams +// layoutParams.height = toolbarHeight +// bottomSheet.layoutParams = layoutParams mBehavior?.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onStateChanged(bottomSheet: View, newState: Int) { + + if (newState == BottomSheetBehavior.STATE_COLLAPSED) { + mBinding?.topContainer?.visibility = View.VISIBLE + } else { + mBinding?.topContainer?.visibility = View.INVISIBLE + } + if (newState == BottomSheetBehavior.STATE_HIDDEN) { mBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED } @@ -173,30 +161,18 @@ class EnergyCenterFragment : BaseLazyFragment() { } } - override fun onSlide(bottomSheet: View, slideOffset: Float) {} - }) - } - } - - private fun initSignView(entity: SignStatusEntity) { - mBinding?.run { - if (entity.todaySignIn) { - signToday.visibility = View.GONE - signedContainer.visibility = View.VISIBLE - serialSignTv.text = "已连续签到${entity.serialSign}天" - } else { - signToday.visibility = View.VISIBLE - signedContainer.visibility = View.GONE - } - - if (entity.sevenDaySerialSign == 0) return - - for (i in 1..entity.sevenDaySerialSign) { - updateSignedViewForDay(i) - if (i != 7) { - updateLineViewForDay(i, i != entity.sevenDaySerialSign) + override fun onSlide(bottomSheet: View, slideOffset: Float) { + mBinding?.run { + if (slideOffset > 0.95) { + collapsedBg.visibility = View.GONE + expandedBg.visibility = View.VISIBLE + } else { + collapsedBg.visibility = View.VISIBLE + expandedBg.visibility = View.GONE + } + } } - } + }) } } @@ -206,29 +182,6 @@ class EnergyCenterFragment : BaseLazyFragment() { } } - private fun updateSignedViewForDay(day: Int) { - mBinding?.run { - val index = (day - 1) * 2 - val dayContainer = signDaysContainer.getChildAt(index) as RelativeLayout - val dayIv = dayContainer.getChildAt(0) as ImageView - dayIv.setImageResource(R.drawable.ic_energy_center_signed) - } - } - - private fun updateLineViewForDay(day: Int, isStraight: Boolean) { - mBinding?.run { - val index = (day - 1) * 2 + 1 - val lineContainer = signDaysContainer.getChildAt(index) as LinearLayout - val straightLine = lineContainer.getChildAt(0) - val dottedLine = lineContainer.getChildAt(1) - if (isStraight) { - straightLine.visibility = View.VISIBLE - } else { - dottedLine.visibility = View.VISIBLE - } - } - } - private fun initViewpager() { mBinding?.run { mFragmentsList.clear() @@ -249,33 +202,56 @@ class EnergyCenterFragment : BaseLazyFragment() { viewpager.offscreenPageLimit = mFragmentsList.size viewpager.adapter = FragmentAdapter(childFragmentManager, mFragmentsList, mTitleList) + viewpager.doOnScroll( + onPageSelected = { position -> + updateTabTextStyle(position, 0F) + }, + onPageScrolled = { position, positionOffset, _ -> + if (position + 1 != mTabList.size) { + mTabList[position].run { + textSize = (DEFAULT_TAB_TEXT_SIZE + ((1 - positionOffset) * 4)).roundTo(1) +// setTextColor(ColorUtils.blendARGB(TAB_DEFAULT_COLOR, TAB_SELECTED_COLOR, 1 - positionOffset)) + } + mTabList[position + 1].run { + textSize = (DEFAULT_TAB_TEXT_SIZE + ((positionOffset) * 4)).roundTo(1) +// setTextColor(ColorUtils.blendARGB(TAB_DEFAULT_COLOR, TAB_SELECTED_COLOR, positionOffset)) + } + + // 多 tab 切换的时候可能会出现某些 tab 的文字没有回归到原始大小的问题的问题 (positionOffset 不保证连续) + for ((index, tabTv) in mTabList.withIndex()) { + if (abs(index - position) >= 2) { + if (tabTv.textSize != DEFAULT_TAB_TEXT_SIZE) { + tabTv.textSize = DEFAULT_TAB_TEXT_SIZE +// tabTv.setTextColor(TAB_DEFAULT_COLOR) + } + } + } + } + + updateTabTextStyle(position, positionOffset) + } + ) + tabLayout.setupWithViewPager(viewpager) + indicatorView.run { + setupWithTabLayout(tabLayout) + setupWithViewPager(viewpager) + setIndicatorWidth(18) + } for (i in 0 until tabLayout.tabCount) { val tab = tabLayout.getTabAt(i) ?: continue val tabTitle = if (tab.text != null) tab.text.toString() else "" - val tabView = getTabView(tabTitle) - tab.customView = tabView + val tabViewBinding = generateTabView(tabTitle) + mTabList.add(tabViewBinding.tabTitle) + tab.customView = tabViewBinding.root + tab.view.setPadding(0, 0, 0, 0) } viewpager.currentItem = mInitTabIndex - tabLayout.getTabAt(mInitTabIndex)?.let { updateTabStyle(it, true) } + tabLayout.getTabAt(mInitTabIndex)?.let { updateTabTextStyle(mInitTabIndex, 0F) } if (mInitTabIndex == 1) setNestedScrollingEnabledForIndex(mInitTabIndex) - tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { - override fun onTabReselected(tab: TabLayout.Tab?) { - updateTabStyle(tab, true) - } - - override fun onTabUnselected(tab: TabLayout.Tab?) { - updateTabStyle(tab, false) - } - - override fun onTabSelected(tab: TabLayout.Tab?) { - updateTabStyle(tab, true) - } - }) - // 处理BottomSheetBehavior的ViewPager嵌套RecyclerView滑动冲突问题 viewpager.addOnPageChangeListener { if (it == 0) { @@ -289,31 +265,44 @@ class EnergyCenterFragment : BaseLazyFragment() { } } + private fun updateTabTextStyle(selectedPosition: Int, positionOffset: Float) { + for ((index, titleTv) in mTabList.withIndex()) { + if (index == selectedPosition) { +// titleTv.setTextColor(TAB_SELECTED_COLOR) + if (positionOffset == 0F) { + titleTv.setTypeface(null, Typeface.NORMAL) + titleTv.setTypeface(titleTv.typeface, Typeface.BOLD) + } + } else { +// titleTv.setTextColor(TAB_DEFAULT_COLOR) + if (positionOffset == 0F) { + titleTv.setTypeface(null, Typeface.NORMAL) + } + } + } + } + + private fun generateTabView(title: String): TabItemMainBinding { + val binding = TabItemMainBinding.inflate(LayoutInflater.from(requireContext())) + binding.tabTitle.run { + text = title + textSize = DEFAULT_TAB_TEXT_SIZE + setTextColor(TAB_TEXT_COLOR) + } + binding.invisibleTabTitle.run { + text = title + textSize = DEFAULT_TAB_TEXT_SIZE + } + return binding + } + private fun setNestedScrollingEnabledForIndex(index: Int) { (mFragmentsList[0] as TaskFragment).setNestedScrollingEnabled(index == 0) (mFragmentsList[1] as CommodityFragment).setNestedScrollingEnabled(index == 1) mBinding?.bottomSheet?.requestLayout() } - private fun getTabView(title: String): View { - val view = LayoutInflater.from(HaloApp.getInstance().application.baseContext).inflate(R.layout.tab_item_energy_center, null) - val tabTitle = view.findViewById(R.id.tab_title) - if (tabTitle is CheckedTextView) { - tabTitle.text = title - } - return view - } - - private fun updateTabStyle(tab: TabLayout.Tab?, isChecked: Boolean) { - val tabView = tab?.customView - tabView?.run { - val tabIndicator = findViewById(R.id.tab_indicator) - tabIndicator.visibility = if (isChecked) View.VISIBLE else View.INVISIBLE - } - } - - @OnClick(R.id.backIv, R.id.userEnergyContainer, R.id.energyRuleTv, R.id.inviteFriends, R.id.signToday, R.id.signRule, - R.id.oneDay, R.id.twoDay, R.id.threeDay, R.id.fourDay, R.id.fiveDay, R.id.sixDay, R.id.sevenDay) + @OnClick(R.id.backIv, R.id.userEnergyContainer, R.id.energyRuleTv, R.id.signIv, R.id.inviteIv) fun onViewClicked(v: View) { when (v.id) { R.id.backIv -> requireActivity().finish() @@ -338,7 +327,15 @@ class EnergyCenterFragment : BaseLazyFragment() { DirectUtils.directToEnergyRulePage(requireContext()) } - R.id.inviteFriends -> { + R.id.signIv -> { + ifLogin("光能中心-每日签到") { + mSignStatus?.run { + DialogUtils.showEnergySignDialog(requireContext(), sevenDaySerialSign) + } + } + } + + R.id.inviteIv -> { IntegralLogHelper.run { log("click_invite_friend", LOCATION) log("view_invite_friend", "邀请好友页") @@ -348,87 +345,6 @@ class EnergyCenterFragment : BaseLazyFragment() { DirectUtils.directToInviteFriends(requireContext()) } } - - R.id.signRule -> { - IntegralLogHelper.log("click_sign_rule", LOCATION) - DialogUtils.showSignRuleDialog(requireContext()) - } - - R.id.signToday -> { - ifLogin("光能中心-签到气泡") { - dealSignIn() - } - } - - R.id.oneDay -> { - ifLogin("光能中心-1天") { - mSignStatus?.run { - if (!todaySignIn && sevenDaySerialSign == 0) { - dealSignIn() - } - } - } - } - - R.id.twoDay -> { - ifLogin("光能中心-2天") { - mSignStatus?.run { - if (!todaySignIn && sevenDaySerialSign == 1) { - dealSignIn() - } - } - } - } - - R.id.threeDay -> { - ifLogin("光能中心-3天") { - mSignStatus?.run { - if (!todaySignIn && sevenDaySerialSign == 2) { - dealSignIn() - } - } - } - } - - R.id.fourDay -> { - ifLogin("光能中心-4天") { - mSignStatus?.run { - if (!todaySignIn && sevenDaySerialSign == 3) { - dealSignIn() - } - } - } - } - - R.id.fiveDay -> { - ifLogin("光能中心-5天") { - mSignStatus?.run { - if (!todaySignIn && sevenDaySerialSign == 4) { - dealSignIn() - } - } - } - } - - R.id.sixDay -> { - ifLogin("光能中心-6天") { - mSignStatus?.run { - if (!todaySignIn && sevenDaySerialSign == 5) { - dealSignIn() - } - } - } - } - - R.id.sevenDay -> { - ifLogin("光能中心-7天") { - mSignStatus?.run { - if (!todaySignIn && sevenDaySerialSign == 6) { - dealSignIn() - } - } - } - } } } @@ -448,5 +364,7 @@ class EnergyCenterFragment : BaseLazyFragment() { companion object { const val LOCATION = "光能中心" + var TAB_TEXT_COLOR: Int = R.color.text_00DBA4.toColor() + var DEFAULT_TAB_TEXT_SIZE = 16F } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/energy/EnergyHouseFragment.kt b/app/src/main/java/com/gh/gamecenter/energy/EnergyHouseFragment.kt index 167facd369..add79f3e6c 100644 --- a/app/src/main/java/com/gh/gamecenter/energy/EnergyHouseFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/energy/EnergyHouseFragment.kt @@ -1,10 +1,12 @@ package com.gh.gamecenter.energy +import android.graphics.Typeface +import android.os.Build import android.os.Bundle +import android.util.DisplayMetrics import android.view.LayoutInflater import android.view.View -import android.widget.CheckedTextView -import android.widget.ImageView +import android.widget.RelativeLayout import android.widget.TextView import androidx.core.os.bundleOf import androidx.fragment.app.Fragment @@ -14,13 +16,14 @@ import com.gh.base.fragment.BaseLazyFragment import com.gh.common.util.* import com.gh.gamecenter.R import com.gh.gamecenter.databinding.FragmentEnergyHouseBinding +import com.gh.gamecenter.databinding.TabItemCommodityBinding import com.gh.gamecenter.entity.CommodityCategoryEntity import com.gh.gamecenter.entity.SubjectSettingEntity import com.gh.gamecenter.entity.UserInfoEntity import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.personalhome.UserHomeViewModel import com.gh.gamecenter.user.UserViewModel -import com.google.android.material.appbar.AppBarLayout +import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.tabs.TabLayout import com.halo.assistant.HaloApp import kotlin.math.abs @@ -34,13 +37,15 @@ class EnergyHouseFragment: BaseLazyFragment() { private var mCommodityCategories: List? = null private var mUserInfo: UserInfoEntity? = null private val mTitleList = ArrayList() + private var mTabList = arrayListOf() private val mFragments = ArrayList() private val mRollNotices = ArrayList() private var mCurrentSizeIndex = 0 private var mCurrentSize = SubjectSettingEntity.Size() - private var mEnergy = 0 + private var mEnergy = 0L private var mCategoryId = "" private var mInitIndex = 0 + private var mBehavior: BottomSheetBehavior? = null override fun getLayoutId() = 0 @@ -83,7 +88,7 @@ class EnergyHouseFragment: BaseLazyFragment() { mEnergy = it mBinding?.run { userEnergyContainer.visibility = View.VISIBLE - userEnergy.text = "${it}光能" + userEnergy.text = it.toString() } } @@ -103,26 +108,45 @@ class EnergyHouseFragment: BaseLazyFragment() { } mBinding?.run { - appbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _, verticalOffset -> - val invisibleOffset = (104F - 48F).dip2px() - DisplayUtils.getStatusBarHeight(resources) - if (abs(verticalOffset) >= invisibleOffset) { - toolbar.setBackgroundColor(R.color.white.toColor()) - backIv.setImageResource(R.drawable.ic_bar_back) - title.setTextColor(R.color.text_333333.toColor()) - exchangeRuleTv.setTextColor(R.color.text_333333.toColor()) - EnergyRuleIv.setImageResource(R.drawable.icon_doubt_black) - tabLayout.setBackgroundColor(R.color.white.toColor()) - sizeContainer.setBackgroundColor(R.color.white.toColor()) - DisplayUtils.setStatusBarColor(requireActivity(), R.color.white, true) - } else { - toolbar.setBackgroundColor(R.color.transparent.toColor()) - backIv.setImageResource(R.drawable.ic_bar_back_light) - title.setTextColor(R.color.white.toColor()) - exchangeRuleTv.setTextColor(R.color.white.toColor()) - EnergyRuleIv.setImageResource(R.drawable.icon_doubt_white) - tabLayout.setBackgroundColor(R.color.transparent.toColor()) - sizeContainer.setBackgroundColor(R.color.transparent.toColor()) - DisplayUtils.setStatusBarColor(requireActivity(), R.color.transparent, true) +// background.layoutParams = background.layoutParams.apply { +// val screenWidth = resources.displayMetrics.widthPixels +// height = screenWidth * 400 / 360 +// } + + val screenHeight = when { + Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 -> { + resources.displayMetrics.heightPixels + } + + Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { + DisplayMetrics() + .apply { requireActivity().display?.getRealMetrics(this) } + .heightPixels + } + + else -> { + @Suppress("DEPRECATION") + DisplayMetrics() + .apply { requireActivity().windowManager.defaultDisplay.getRealMetrics(this) } + .heightPixels + } + } + + mBehavior = BottomSheetBehavior.from(bottomSheet) + mBehavior?.peekHeight = screenHeight - 288F.dip2px() + + val layoutParams = bottomSheet.layoutParams + layoutParams.height = screenHeight - 40F.dip2px() + bottomSheet.layoutParams = layoutParams + + mBehavior?.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { + override fun onStateChanged(bottomSheet: View, newState: Int) { + if (newState == BottomSheetBehavior.STATE_HIDDEN) { + mBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED + } + } + + override fun onSlide(bottomSheet: View, slideOffset: Float) { } }) } @@ -165,28 +189,69 @@ class EnergyHouseFragment: BaseLazyFragment() { } else super.getPageTitle(position) } } + + viewpager.doOnScroll( + onPageSelected = { position -> + updateTabTextStyle(position, 0F) + }, + onPageScrolled = { position, positionOffset, _ -> + if (position + 1 != mTabList.size) { + mTabList[position].run { + textSize = (DEFAULT_TAB_TEXT_SIZE + ((1 - positionOffset) * 4)).roundTo(1) +// setTextColor(ColorUtils.blendARGB(TAB_DEFAULT_COLOR, TAB_SELECTED_COLOR, 1 - positionOffset)) + } + mTabList[position + 1].run { + textSize = (DEFAULT_TAB_TEXT_SIZE + ((positionOffset) * 4)).roundTo(1) +// setTextColor(ColorUtils.blendARGB(TAB_DEFAULT_COLOR, TAB_SELECTED_COLOR, positionOffset)) + } + + // 多 tab 切换的时候可能会出现某些 tab 的文字没有回归到原始大小的问题的问题 (positionOffset 不保证连续) + for ((index, tabTv) in mTabList.withIndex()) { + if (abs(index - position) >= 2) { + if (tabTv.textSize != DEFAULT_TAB_TEXT_SIZE) { + tabTv.textSize = DEFAULT_TAB_TEXT_SIZE +// tabTv.setTextColor(TAB_DEFAULT_COLOR) + } + } + } + } + + updateTabTextStyle(position, positionOffset) + } + ) + tabLayout.setupWithViewPager(viewpager) + indicatorView.run { + setupWithTabLayout(tabLayout) + setupWithViewPager(viewpager) + setIndicatorWidth(18) + } for (i in 0 until tabLayout.tabCount) { val tab = tabLayout.getTabAt(i) ?: continue val tabTitle = if (tab.text != null) tab.text.toString() else "" - val tabView = getTabView(tabTitle) - tab.customView = tabView + val tabViewBinding = generateTabView( + tabTitle, + i == 0, + i == tabLayout.tabCount - 1 + ) + mTabList.add(tabViewBinding.tabTitle) + tab.customView = tabViewBinding.root + tab.view.setPadding(0, 0, 0, 0) } viewpager.currentItem = mInitIndex - tabLayout.getTabAt(mInitIndex)?.let { updateTabStyle(it, true) } + tabLayout.getTabAt(mInitIndex)?.let { updateTabTextStyle(mInitIndex, 0F) } + setNestedScrollingEnabledForIndex(mInitIndex) + tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { override fun onTabReselected(tab: TabLayout.Tab?) { - updateTabStyle(tab, true) } override fun onTabUnselected(tab: TabLayout.Tab?) { - updateTabStyle(tab, false) } override fun onTabSelected(tab: TabLayout.Tab?) { - updateTabStyle(tab, true) tab?.run { mCommodityCategories?.get(position)?.run { IntegralLogHelper.logCommodityCategory( @@ -200,29 +265,53 @@ class EnergyHouseFragment: BaseLazyFragment() { } } }) + + viewpager.addOnPageChangeListener { + setNestedScrollingEnabledForIndex(it) + } } initSize() } - - private fun getTabView(title: String): View { - val view = LayoutInflater.from(HaloApp.getInstance().application.baseContext).inflate(R.layout.tab_item_energy_house, null) - val tabTitle = view.findViewById(R.id.tab_title) - if (tabTitle is CheckedTextView) { - tabTitle.text = title + private fun setNestedScrollingEnabledForIndex(currentIndex: Int) { + mFragments.forEachIndexed { index, fragment -> + (fragment as CommodityFragment).setNestedScrollingEnabled(currentIndex == index) } - return view + + mBinding?.bottomSheet?.requestLayout() } - private fun updateTabStyle(tab: TabLayout.Tab?, isChecked: Boolean) { - val tabView = tab?.customView - tabView?.run { - val tabIndicator = findViewById(R.id.tab_indicator) - tabIndicator.visibility = if (isChecked) View.VISIBLE else View.INVISIBLE + private fun updateTabTextStyle(selectedPosition: Int, positionOffset: Float) { + for ((index, titleTv) in mTabList.withIndex()) { + if (index == selectedPosition) { +// titleTv.setTextColor(TAB_SELECTED_COLOR) + if (positionOffset == 0F) { + titleTv.setTypeface(null, Typeface.NORMAL) + titleTv.setTypeface(titleTv.typeface, Typeface.BOLD) + } + } else { +// titleTv.setTextColor(TAB_DEFAULT_COLOR) + if (positionOffset == 0F) { + titleTv.setTypeface(null, Typeface.NORMAL) + } + } } } + private fun generateTabView(title: String, isFirst: Boolean, isLast: Boolean): TabItemCommodityBinding { + val binding = TabItemCommodityBinding.inflate(LayoutInflater.from(requireContext())) + binding.tabTitle.run { + val padLeft = if (isFirst) 16F.dip2px() else 8F.dip2px() + val padRight = if (isLast) 16F.dip2px() else 8F.dip2px() + setPadding(padLeft, 0, padRight, 0) + text = title + textSize = DEFAULT_TAB_TEXT_SIZE + setTextColor(TAB_TEXT_COLOR) + } + return binding + } + private fun getDefaultSizeFilterArray(): ArrayList { return arrayListOf().apply { add(SubjectSettingEntity.Size(min = -1, max = -1, text = "全部")) @@ -261,11 +350,11 @@ class EnergyHouseFragment: BaseLazyFragment() { val item = sizeContainer.getChildAt(index) val tv = item.findViewById(R.id.size_tv) if (position == index) { - tv.setTextColor(R.color.theme_font.toColor()) - tv.setBackgroundResource(R.drawable.button_round_e6f8fa) + tv.setTextColor(R.color.white.toColor()) + tv.setBackgroundResource(R.drawable.button_round_00dba4) } else { - tv.setTextColor(R.color.text_666666.toColor()) - tv.setBackgroundResource(R.drawable.button_round_f5f5f5) + tv.setTextColor(R.color.text_333333.toColor()) + tv.setBackgroundResource(R.drawable.button_round_ebf9fa) } } } @@ -344,5 +433,7 @@ class EnergyHouseFragment: BaseLazyFragment() { companion object { const val LOCATION = "光能屋" + var TAB_TEXT_COLOR: Int = R.color.text_00DBA4.toColor() + var DEFAULT_TAB_TEXT_SIZE = 14F } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/energy/HorizontalTaskAdapter.kt b/app/src/main/java/com/gh/gamecenter/energy/HorizontalTaskAdapter.kt index 89204f14df..54223e7527 100644 --- a/app/src/main/java/com/gh/gamecenter/energy/HorizontalTaskAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/energy/HorizontalTaskAdapter.kt @@ -37,12 +37,10 @@ class HorizontalTaskAdapter(context: Context, if (task.status == "finished") { taskBtn.text = "已完成" - taskBtn.setTextColor(R.color.text_cccccc.toColor()) - taskBtn.setBackgroundResource(R.drawable.button_round_f5f5f5) + taskBtn.setBackgroundResource(R.drawable.bg_energy_task_btn_finished) } else { - taskBtn.text = "去完成" - taskBtn.setTextColor(R.color.theme_font.toColor()) - taskBtn.setBackgroundResource(R.drawable.button_round_ebfdff) + taskBtn.text = "+${task.energy}光能" + taskBtn.setBackgroundResource(R.drawable.bg_energy_task_btn_normal) } taskNotice.setOnClickListener { diff --git a/app/src/main/java/com/gh/gamecenter/energy/TaskAdapter.kt b/app/src/main/java/com/gh/gamecenter/energy/TaskAdapter.kt index 7c1eaa656c..8caab18f40 100644 --- a/app/src/main/java/com/gh/gamecenter/energy/TaskAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/energy/TaskAdapter.kt @@ -16,6 +16,7 @@ import com.gh.gamecenter.baselist.ListAdapter import com.gh.gamecenter.baselist.LoadStatus import com.gh.gamecenter.databinding.DailyTaskItemBinding import com.gh.gamecenter.databinding.NoviceTasksItemBinding +import com.gh.gamecenter.databinding.TaskBottomItemBinding import com.gh.gamecenter.databinding.TaskTitleItemBinding import com.gh.gamecenter.gamedetail.dialog.InviteCodeDialog import com.gh.gamecenter.manager.UserManager @@ -25,21 +26,19 @@ class TaskAdapter(context: Context) : ListAdapter(context) { private val mEntrance = "光能中心-任务列表" override fun getItemCount(): Int { - return if (mEntityList.isNullOrEmpty()) 0 else mEntityList.size + FOOTER_ITEM_COUNT + return if (mEntityList.isNullOrEmpty()) 0 else mEntityList.size } override fun getItemViewType(position: Int): Int { - return if (position == itemCount - 1) { - ItemViewType.ITEM_FOOTER - } else { - val item = mEntityList[position] - when { + val item = mEntityList[position] + return when { item.noviceTasks != null -> TYPE_NOVICE item.title != null -> TYPE_TITLE - else -> TYPE_DAILY - } + item.dailyTask != null -> TYPE_DAILY + + else -> TYPE_BOTTOM } } @@ -59,6 +58,8 @@ class TaskAdapter(context: Context) : ListAdapter(context) { (oldItem.dailyTask?.id == newItem.dailyTask?.id && oldItem.dailyTask?.status == newItem.dailyTask?.status) } + oldItem?.bottom != null && newItem?.bottom != null -> true + else -> super.areItemsTheSame(oldItem, newItem) } } @@ -75,6 +76,8 @@ class TaskAdapter(context: Context) : ListAdapter(context) { (oldItem.dailyTask?.id == newItem.dailyTask?.id && oldItem.dailyTask?.status == newItem.dailyTask?.status) } + oldItem?.bottom != null && newItem?.bottom != null -> true + else -> super.areContentsTheSame(oldItem, newItem) } } @@ -102,6 +105,8 @@ class TaskAdapter(context: Context) : ListAdapter(context) { TYPE_TITLE -> TaskTitleViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.task_title_item, parent, false)) + TYPE_BOTTOM -> TaskBottomViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.task_bottom_item, parent, false)) + else -> DailyTaskViewHolder(DataBindingUtil.inflate(mLayoutInflater, R.layout.daily_task_item, parent, false)) } } @@ -119,13 +124,7 @@ class TaskAdapter(context: Context) : ListAdapter(context) { is TaskTitleViewHolder -> { holder.binding.run { val titleStr = mEntityList[position].title!! - var top = if (titleStr == "新手任务") 16F.dip2px() else 32F.dip2px() - var bottom = if (titleStr == "新手任务") 16F.dip2px() else 5F.dip2px() - root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply { - topMargin = top - bottomMargin = bottom - } - title.text = titleStr + topPic.setImageResource(if (titleStr == "日常任务") R.drawable.pic_daily_task_title else R.drawable.pic_fix_task_title) } } @@ -135,7 +134,15 @@ class TaskAdapter(context: Context) : ListAdapter(context) { entity = task executePendingBindings() - if (task.isFixed) progress.text = "" +// if (task.isFixed) progress.text = "" + + if (task.status == "finished") { + taskBtn.text = "已完成" + taskBtn.setBackgroundResource(R.drawable.bg_energy_task_btn_finished) + } else { + taskBtn.text = "+${task.energy}光能" + taskBtn.setBackgroundResource(R.drawable.bg_energy_task_btn_normal) + } taskNotice.setOnClickListener { DialogUtils.showEnergyTaskNoticeDialog(mContext, task.name, task.descr) @@ -178,12 +185,14 @@ class TaskAdapter(context: Context) : ListAdapter(context) { } } - is FooterViewHolder -> { - holder.itemView.setPadding(0, 0, 0, 40F.dip2px()) - holder.itemView.layoutParams = holder.itemView.layoutParams.apply { - height = 88F.dip2px() + is TaskBottomViewHolder -> { + holder.binding.run { + val isLastBottom = mEntityList[position].bottom!! + holder.itemView.layoutParams = (holder.itemView.layoutParams as ViewGroup.MarginLayoutParams).apply { + val marginBottom = if (isLastBottom) 40F.dip2px() else 0 + setMargins(16F.dip2px(), 0, 16F.dip2px(), marginBottom) + } } - holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver) } } } @@ -191,6 +200,7 @@ class TaskAdapter(context: Context) : ListAdapter(context) { inner class NoviceTasksViewHolder(val binding: NoviceTasksItemBinding): BaseRecyclerViewHolder(binding.root) inner class TaskTitleViewHolder(val binding: TaskTitleItemBinding): BaseRecyclerViewHolder(binding.root) inner class DailyTaskViewHolder(val binding: DailyTaskItemBinding): BaseRecyclerViewHolder(binding.root) + inner class TaskBottomViewHolder(val binding: TaskBottomItemBinding): BaseRecyclerViewHolder(binding.root) companion object { private const val TYPE_NOVICE = 900 @@ -198,5 +208,7 @@ class TaskAdapter(context: Context) : ListAdapter(context) { private const val TYPE_TITLE = 901 private const val TYPE_DAILY = 902 + + private const val TYPE_BOTTOM = 903 } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/energy/TaskItemData.kt b/app/src/main/java/com/gh/gamecenter/energy/TaskItemData.kt index 642d79516c..b45ad0db1f 100644 --- a/app/src/main/java/com/gh/gamecenter/energy/TaskItemData.kt +++ b/app/src/main/java/com/gh/gamecenter/energy/TaskItemData.kt @@ -3,5 +3,6 @@ package com.gh.gamecenter.energy import com.gh.gamecenter.entity.TaskEntity data class TaskItemData(var noviceTasks: List? = null, - var title: String? = null, - var dailyTask: TaskEntity? = null) \ No newline at end of file + var title: String? = null, + var dailyTask: TaskEntity? = null, + var bottom: Boolean? = null) \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/energy/TaskViewModel.kt b/app/src/main/java/com/gh/gamecenter/energy/TaskViewModel.kt index 115c0f53f7..ddceebf9b6 100644 --- a/app/src/main/java/com/gh/gamecenter/energy/TaskViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/energy/TaskViewModel.kt @@ -44,21 +44,22 @@ class TaskViewModel(application: Application) } }, {}, { if (mNoviceTasks.isNotEmpty()) { - itemDataList.add(TaskItemData(title = "新手任务")) itemDataList.add(TaskItemData(noviceTasks = mNoviceTasks)) } + itemDataList.add(TaskItemData(title = "日常任务")) + list.forEach { + itemDataList.add(TaskItemData(dailyTask = it)) + } + itemDataList.add(TaskItemData(bottom = mFixedTasks.isEmpty())) + if (mFixedTasks.isNotEmpty()) { itemDataList.add(TaskItemData(title = "常驻任务")) mFixedTasks.forEach { it.isFixed = true itemDataList.add(TaskItemData(dailyTask = it)) } - } - - itemDataList.add(TaskItemData(title = "日常任务")) - list.forEach { - itemDataList.add(TaskItemData(dailyTask = it)) + itemDataList.add(TaskItemData(bottom = true)) } mResultLiveData.postValue(itemDataList) diff --git a/app/src/main/java/com/gh/gamecenter/entity/ApkEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/ApkEntity.kt index 734ae474de..d702a22b8a 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/ApkEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/ApkEntity.kt @@ -33,6 +33,10 @@ data class ApkEntity(@SerializedName("package") @SerializedName("download_instruction") val downloadInstruction: String = "", var recommend: Recommend? = null, + @SerializedName("sign") + var signature: String? = "", + @SerializedName("version_code") + var versionCode: Int = 0, // 以下是历史版本用的字段,其它地方可能会没有 @SerializedName("update_time") diff --git a/app/src/main/java/com/gh/gamecenter/entity/ApplyModeratorStatusEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/ApplyModeratorStatusEntity.kt index 5c8a70ab30..bcc0453de0 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/ApplyModeratorStatusEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/ApplyModeratorStatusEntity.kt @@ -9,7 +9,9 @@ data class ApplyModeratorStatusEntity( val condition: Condition = Condition(), val status: String = "", @SerializedName("qq_group") - val qqGroup: String = "" + val qqGroup: String = "", + @SerializedName("qa_group_key") + val qqGroupKey: String = "" ) : Parcelable { @Parcelize data class Condition( diff --git a/app/src/main/java/com/gh/gamecenter/entity/ForumVideoEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/ForumVideoEntity.kt index 2bf0ce92ee..a7a53024a4 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/ForumVideoEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/ForumVideoEntity.kt @@ -8,45 +8,54 @@ import kotlinx.android.parcel.Parcelize @Parcelize open class ForumVideoEntity( - @SerializedName("_id") - var id: String = "", - var title: String = "", - var des: String = "", - var poster: String = "", - var url: String = "", - val user: PersonalEntity = PersonalEntity(), - val me: MeEntity = MeEntity(), - val size: Long = 0, - var length: Long = 0, - // 有三种状态 pass通过,fail未通过,pending审核中 - var status: String = "", - val format: String = "Mp4", - var game: GameEntity? = null, - @SerializedName("tag_activity_id") - var tagActivityId: String = "",//活动标签的id - @SerializedName("tag_activity_name") - var tagActivityName: String = "", - @SerializedName("bbs_id") - var bbsId: String = "", - @SerializedName("game_id") - var gameId: String = "", - var type: String = "", - var share: Int = 0, - var time: Time = Time(), - @SerializedName("video_info") - var videoInfo: VideoInfo = VideoInfo(), - @SerializedName("is_jx") - var isHighlighted: Boolean = true, - var bbs: CommunityEntity? = null, - var count: Count = Count(), - val original: String = "",//是否原创 //是否原创 yes/no 默认为空字符串 - val source: String = "",//转载来源, 当 original=yes - @SerializedName("choiceness_status") - val choicenessStatus: String = "",// 精选状态 null, apply(申请), cancel(不予精选或未精选), pass(已精选) - @IgnoredOnParcel - var videoIsMuted: Boolean = false, //是否静音标记 - var duration: String = "" -) : Parcelable + @SerializedName("_id") + var id: String = "", + var title: String = "", + var des: String = "", + var poster: String = "", + var url: String = "", + val user: PersonalEntity = PersonalEntity(), + val me: MeEntity = MeEntity(), + val size: Long = 0, + var length: Long = 0, + // 有三种状态 pass通过,fail未通过,pending审核中 + var status: String = "", + val format: String = "Mp4", + var game: GameEntity? = null, + @SerializedName("tag_activity_id") + var tagActivityId: String = "",//活动标签的id + @SerializedName("tag_activity_name") + var tagActivityName: String = "", + @SerializedName("bbs_id") + var bbsId: String = "", + @SerializedName("game_id") + var gameId: String = "", + var type: String = "", + var share: Int = 0, + var time: Time = Time(), + @SerializedName("video_info") + var videoInfo: VideoInfo = VideoInfo(), + @SerializedName("is_jx") + var isHighlighted: Boolean = true, + var bbs: CommunityEntity? = null, + var count: Count = Count(), + val original: String = "",//是否原创 //是否原创 yes/no 默认为空字符串 + val source: String = "",//转载来源, 当 original=yes + @SerializedName("choiceness_status") + var choicenessStatus: String = "",// apply(申请), pass already(已精选) cancel not_yet(未精选) + @IgnoredOnParcel + var videoIsMuted: Boolean = false, //是否静音标记 + var duration: String = "" +) : Parcelable { + + fun getSimplifyChoicenessStatus(): String { + return when (choicenessStatus) { + "already" -> "pass" + "not_yet" -> "cancel" + else -> choicenessStatus + } + } +} @Parcelize data class Time(val upload: Long = 0, val audit: Long = 0, val update: Long = 0) : Parcelable diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt index da255a100c..3b210771ef 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt @@ -1,6 +1,7 @@ package com.gh.gamecenter.entity import android.os.Parcelable +import android.text.TextUtils import com.gh.common.constant.Config import com.gh.common.constant.Constants import com.gh.common.exposure.ExposureEvent @@ -19,239 +20,239 @@ import kotlin.collections.ArrayList @Parcelize data class GameEntity( - @SerializedName("_id") - var id: String = "", - @SerializedName("icon") - private var mIcon: String? = null, - @SerializedName("ori_icon") - private var mRawIcon: String? = null, - @SerializedName("name") - private var mName: String? = null, // 将 name 变成私有 mName 调用 name 时直接拼接成 mName + nameSuffix - @SerializedName("name_suffix") - var nameSuffix: String = "", - @SerializedName("brief") - private var mBrief: String? = null, + @SerializedName("_id") + var id: String = "", + @SerializedName("icon") + private var mIcon: String? = null, + @SerializedName("ori_icon") + private var mRawIcon: String? = null, + @SerializedName("name") + private var mName: String? = null, // 将 name 变成私有 mName 调用 name 时直接拼接成 mName + nameSuffix + @SerializedName("name_suffix") + var nameSuffix: String = "", + @SerializedName("brief") + private var mBrief: String? = null, - @SerializedName("appointment") - private var mReservable: Boolean = false, // 此游戏是否处于可预约状态 - @SerializedName("appointment_button") - var reserveStatus: String = "", // 预约状态供用户预约列表使用,值存在的话,有两种值 -> appointment(已预约), download(已上线) + @SerializedName("appointment") + private var mReservable: Boolean = false, // 此游戏是否处于可预约状态 + @SerializedName("appointment_button") + var reserveStatus: String = "", // 预约状态供用户预约列表使用,值存在的话,有两种值 -> appointment(已预约), download(已上线) - // 插件标签 - private var tag: ArrayList? = null, - private var apk: ArrayList? = null, - @SerializedName("apk_normal") - private var apkNormal: ArrayList? = null, - @SerializedName("apk_search") - var apkSearch: ArrayList? = null, + // 插件标签 + private var tag: ArrayList? = null, + private var apk: ArrayList? = null, + @SerializedName("apk_normal") + private var apkNormal: ArrayList? = null, + @SerializedName("apk_search") + var apkSearch: ArrayList? = null, - @SerializedName("apk_index") - var apkIndex: ArrayList? = null, + @SerializedName("apk_index") + var apkIndex: ArrayList? = null, - var collection: ArrayList = ArrayList(), - var slide: String? = null, - var test: TestEntity? = null, + var collection: ArrayList = ArrayList(), + var slide: String? = null, + var test: TestEntity? = null, - @SerializedName("d_button_add_word") - private var mDownloadAddWord: String? = null, + @SerializedName("d_button_add_word") + private var mDownloadAddWord: String? = null, - var image: String? = null, - var type: String? = null, - var isPluggable: Boolean = false, - var link: String? = null, - var text: String? = "", - @SerializedName("link_community", alternate = ["community"]) - var community: CommunityEntity? = CommunityEntity(), - var display: Display? = null, + var image: String? = null, + var type: String? = null, + var isPluggable: Boolean = false, + var link: String? = null, + var text: String? = "", + @SerializedName("link_community", alternate = ["community"]) + var community: CommunityEntity? = CommunityEntity(), + var display: Display? = null, - @SerializedName("apk_link") - var apkLink: ArrayList? = null, + @SerializedName("apk_link") + var apkLink: ArrayList? = null, - @SerializedName("concern_article_exists") - var isNewsExists: Boolean = true, + @SerializedName("concern_article_exists") + var isNewsExists: Boolean = true, - @SerializedName("download_off_text") - private var mDownloadOffText: String? = null, + @SerializedName("download_off_text") + private var mDownloadOffText: String? = null, - @SerializedName("download_off_status") - private var mDownloadOffStatus: String? = null, // "off/dialog/toast", 只关闭、关闭且弹窗、关闭且toast + @SerializedName("download_off_status") + private var mDownloadOffStatus: String? = null, // "off/dialog/toast", 只关闭、关闭且弹窗、关闭且toast - @SerializedName("download_off_dialog") - private var mDownloadOffDialog: Dialog? = null, + @SerializedName("download_off_dialog") + private var mDownloadOffDialog: Dialog? = null, - @SerializedName("libao_exists") - var isLibaoExists: Boolean = false, + @SerializedName("libao_exists") + var isLibaoExists: Boolean = false, - @SerializedName("server_remark") - var serverRemark: String? = null, + @SerializedName("server_remark") + var serverRemark: String? = null, - @SerializedName("server_type") - var serverType: String? = null, + @SerializedName("server_type") + var serverType: String? = null, - @SerializedName("server_label") - var serverLabel: ColorEntity? = null, + @SerializedName("server_label") + var serverLabel: ColorEntity? = null, - @SerializedName("server") - var serverEntity: ServerCalendarEntity? = null, + @SerializedName("server") + var serverEntity: ServerCalendarEntity? = null, - @SerializedName("server_genre") - var serverGenre: String? = null, + @SerializedName("server_genre") + var serverGenre: String? = null, - @SerializedName("remaining_server") - var serverRemaining: List? = null, + @SerializedName("remaining_server") + var serverRemaining: List? = null, - var kaifuTimeHint: Long? = null, + var kaifuTimeHint: Long? = null, - var subjectData: GameSubjectData? = null, + var subjectData: GameSubjectData? = null, - // 所有标签(插件标签和游戏标签) - @SerializedName(value = "tag_style", alternate = arrayOf("new_tag_style")) - private var mTagStyle: ArrayList = ArrayList(), - var des: String? = null, - // 用来标记在专题中的序号,仅用于曝光记录 - var sequence: Int? = -1, - // 用来标记在外部页面中的序号,仅用于曝光记录,具体细节可见 https://git.ghzs.com/pm/halo-app-issues/-/issues/1087 - var outerSequence: Int? = -1, - // 用来标记平台名称,仅用于曝光记录 - var platform: String? = "", + // 所有标签(插件标签和游戏标签) + @SerializedName(value = "tag_style", alternate = arrayOf("new_tag_style")) + private var mTagStyle: ArrayList = ArrayList(), + var des: String? = null, + // 用来标记在专题中的序号,仅用于曝光记录 + var sequence: Int? = -1, + // 用来标记在外部页面中的序号,仅用于曝光记录,具体细节可见 https://git.ghzs.com/pm/halo-app-issues/-/issues/1087 + var outerSequence: Int? = -1, + // 用来标记平台名称,仅用于曝光记录 + var platform: String? = "", - // 用来标记下载的类型,仅用于曝光记录 - @SerializedName("download_type") - var downloadType: String? = "", + // 用来标记下载的类型,仅用于曝光记录 + @SerializedName("download_type") + var downloadType: String? = "", - // 用来标记下载完成的类型,仅用于曝光记录 - @SerializedName("download_complete_type") - var downloadCompleteType: String? = "", + // 用来标记下载完成的类型,仅用于曝光记录 + @SerializedName("download_complete_type") + var downloadCompleteType: String? = "", - // 用于开服表标记是否为置顶项目 - @SerializedName("is_fixed_top") - var fixedTop: Boolean? = false, - var fixedTopHint: Boolean? = false, + // 用于开服表标记是否为置顶项目 + @SerializedName("is_fixed_top") + var fixedTop: Boolean? = false, + var fixedTopHint: Boolean? = false, - @SerializedName("download_notice") - val downloadAd: LinkEntity? = null, + @SerializedName("download_notice") + val downloadAd: LinkEntity? = null, - // 社区名字,用于首页替换游戏曝光时使用 - var subjectName: String? = null, + // 社区名字,用于首页替换游戏曝光时使用 + var subjectName: String? = null, - // 关联应用,供首页替换游戏确定该游戏是否应该被替换使用 - @SerializedName("relation_game_ids") - var relatedGameIds: ArrayList? = arrayListOf(), + // 关联应用,供首页替换游戏确定该游戏是否应该被替换使用 + @SerializedName("relation_game_ids") + var relatedGameIds: ArrayList? = arrayListOf(), - @SerializedName("download_dialog") - var downloadDialog: ArrayList? = arrayListOf(), + @SerializedName("download_dialog") + var downloadDialog: ArrayList? = arrayListOf(), - var auth: Auth? = null, + var auth: Auth? = null, - @SerializedName("auth_dialog") - var authDialog: AuthDialogEntity? = null, + @SerializedName("auth_dialog") + var authDialog: AuthDialogEntity? = null, - @SerializedName("is_related") - var isRelated: Boolean = false, + @SerializedName("is_related") + var isRelated: Boolean = false, - @SerializedName("rating_open") - var isRatingOpen: Boolean = false, + @SerializedName("rating_open") + var isRatingOpen: Boolean = false, - @SerializedName("zone_open") - var isZoneOpen: Boolean = false, + @SerializedName("zone_open") + var isZoneOpen: Boolean = false, - @SerializedName("show_comment") - var showComment: Boolean = false, // 游戏评论是否打开 + @SerializedName("show_comment") + var showComment: Boolean = false, // 游戏评论是否打开 - // 分类,取值有 online (网络游戏) , local (单机游戏), welfare (福利游戏),simulator(模拟器游戏) - @SerializedName("category") - private var mCategory: String? = "", - // 7天下载量 - var download: Int = 0, - // subject -> imageSlide - val games: List? = null, + // 分类,取值有 online (网络游戏) , local (单机游戏), welfare (福利游戏),simulator(模拟器游戏) + @SerializedName("category") + private var mCategory: String? = "", + // 7天下载量 + var download: Int = 0, + // subject -> imageSlide + val games: List? = null, - //首页设置 - @SerializedName("home_setting") - val homeSetting: HomeSetting = HomeSetting(), - var linkType: String = "", - @SerializedName("index_plugin") - var indexPlugin: String = "open", + //首页设置 + @SerializedName("home_setting") + val homeSetting: HomeSetting = HomeSetting(), + var linkType: String = "", + @SerializedName("index_plugin") + var indexPlugin: String = "open", - // 游戏版本 (本地字段),供下载统计使用 - var gameVersion: String = "", + // 游戏版本 (本地字段),供下载统计使用 + var gameVersion: String = "", - // icon 角标 - @SerializedName("icon_subscript") - var mIconSubscript: String? = null, + // icon 角标 + @SerializedName("icon_subscript") + var mIconSubscript: String? = null, - @SerializedName("info") - var info: GameInfo? = null, + @SerializedName("info") + var info: GameInfo? = null, - @SerializedName("permission_dialog_status") - var permissionDialogStatus: String? = "", // 权限弹窗,off(关闭)、on(开启),默认:off + @SerializedName("permission_dialog_status") + var permissionDialogStatus: String? = "", // 权限弹窗,off(关闭)、on(开启),默认:off - // 镜像数据,细节见 [RegionSettingHelper] - @SerializedName("mirror_status") - var mirrorStatus: String? = "", - @SerializedName("mirror_data") - var mirrorData: GameEntity? = null, + // 镜像数据,细节见 [RegionSettingHelper] + @SerializedName("mirror_status") + var mirrorStatus: String? = "", + @SerializedName("mirror_data") + var mirrorData: GameEntity? = null, - // 游戏评分 - @SerializedName("new_star") - val star: Float = 10F, - // 游戏评分数量 - @SerializedName("comment_count") - var commentCount: Int = 0, - // 是否支持不安装直接评论 - @SerializedName("direct_comment") - var directComment: Boolean = false, - // xxx人想玩 - @SerializedName("h5_link") - private var mH5Link: LinkEntity? = null, - val visit: Int = 0, - @SerializedName("played_time") - val playedTime: Long = 0, - @SerializedName("played_game_id") - val playedGameId: String = "", - @SerializedName("mutex_package") - val mutexPackage: List? = null, - @SerializedName("version_number") - private val mVersionNumber: String = "",// 无版号无内购无弹窗、无版号无内购有弹窗、无版号有内购、有版号 - @SerializedName("plugin_link") - val pluginLink: List = arrayListOf(), - @SerializedName("p_button_add_word") - var pluginDesc: String = "", //插件功能描述 - var pluggableCollection: GameCollectionEntity? = null, //插件化包所在的合集 - @SerializedName("assign_remark") - val assignRemark: AssignRemark = AssignRemark(), - @SerializedName("zone_setting") - var zone: ZoneEntity = ZoneEntity(), - @SerializedName("comment_description") - var commentDescription: String = "", - @SerializedName("ignore_comment") - var ignoreComment: Boolean = false, - @SerializedName("overseas_address_dialog") - var overseasAddressDialog: OverseasAddressDialog? = null, - var simulator: SimulatorEntity? = null, - @SerializedName("simulator_type") - var simulatorType: String = "", - @SerializedName("is_recently_played") - var isRecentlyPlayed: Boolean = false, - var active: Boolean = true, - @SerializedName("package_dialog") - val packageDialog: PackageDialogEntity? = null, - @SerializedName("top_video") - val topVideo: SimpleVideoEntity? = null, - @SerializedName("column_recommend") - val columnRecommend: LinkEntity? = null, + // 游戏评分 + @SerializedName("new_star") + val star: Float = 10F, + // 游戏评分数量 + @SerializedName("comment_count") + var commentCount: Int = 0, + // 是否支持不安装直接评论 + @SerializedName("direct_comment") + var directComment: Boolean = false, + // xxx人想玩 + @SerializedName("h5_link") + private var mH5Link: LinkEntity? = null, + val visit: Int = 0, + @SerializedName("played_time") + val playedTime: Long = 0, + @SerializedName("played_game_id") + val playedGameId: String = "", + @SerializedName("mutex_package") + val mutexPackage: List? = null, + @SerializedName("version_number") + private val mVersionNumber: String = "",// 无版号无内购无弹窗、无版号无内购有弹窗、无版号有内购、有版号 + @SerializedName("plugin_link") + val pluginLink: List = arrayListOf(), + @SerializedName("p_button_add_word") + var pluginDesc: String = "", //插件功能描述 + var pluggableCollection: GameCollectionEntity? = null, //插件化包所在的合集 + @SerializedName("assign_remark") + val assignRemark: AssignRemark = AssignRemark(), + @SerializedName("zone_setting") + var zone: ZoneEntity = ZoneEntity(), + @SerializedName("comment_description") + var commentDescription: String = "", + @SerializedName("ignore_comment") + var ignoreComment: Boolean = false, + @SerializedName("overseas_address_dialog") + var overseasAddressDialog: OverseasAddressDialog? = null, + var simulator: SimulatorEntity? = null, + @SerializedName("simulator_type") + var simulatorType: String = "", + @SerializedName("is_recently_played") + var isRecentlyPlayed: Boolean = false, + var active: Boolean = true, + @SerializedName("package_dialog") + val packageDialog: PackageDialogEntity? = null, + @SerializedName("top_video") + val topVideo: SimpleVideoEntity? = null, + @SerializedName("column_recommend") + val columnRecommend: LinkEntity? = null, - @SerializedName("simulator_game_config") - val simulatorGameConfig: String? = "", + @SerializedName("simulator_config_url") + val simulatorGameConfig: String? = "", - // 本地字段,使用镜像信息 - var useMirrorInfo: Boolean = false, - // 本地字段,曝光用 - var displayContent: String = "", - var isPlatformRecommend: Boolean = false, - // 从启动弹窗跳转到对应游戏列表时候记录的启动弹窗数据 (ugly ugly ugly) - var welcomeDialogId: String? = null, - var welcomeDialogTitle: String? = null + // 本地字段,使用镜像信息 + var useMirrorInfo: Boolean = false, + // 本地字段,曝光用 + var displayContent: String = "", + var isPlatformRecommend: Boolean = false, + // 从启动弹窗跳转到对应游戏列表时候记录的启动弹窗数据 (ugly ugly ugly) + var welcomeDialogId: String? = null, + var welcomeDialogTitle: String? = null ) : Parcelable { constructor(id: String?) : this() { @@ -264,7 +265,8 @@ data class GameEntity( } @IgnoredOnParcel - private var entryMap: androidx.collection.ArrayMap? = androidx.collection.ArrayMap() + private var entryMap: androidx.collection.ArrayMap? = + androidx.collection.ArrayMap() @IgnoredOnParcel var gameLocation: GameLocation? = null @@ -286,7 +288,7 @@ data class GameEntity( var name: String? get() = if (shouldUseMirrorInfo()) { mirrorData?.mName?.removeSuffix(".") + if (shouldShowNameSuffix) mirrorData?.nameSuffix - ?: "" else "" + ?: "" else "" } else { mName?.removeSuffix(".") + if (shouldShowNameSuffix) nameSuffix else "" } @@ -319,7 +321,9 @@ data class GameEntity( @IgnoredOnParcel val nameWithoutSuffix: String? - get() = if (shouldUseMirrorInfo()) mirrorData?.mName?.removeSuffix(".") else mName?.removeSuffix(".") + get() = if (shouldUseMirrorInfo()) mirrorData?.mName?.removeSuffix(".") else mName?.removeSuffix( + "." + ) @IgnoredOnParcel var isReservable: Boolean @@ -363,14 +367,37 @@ data class GameEntity( mBrief = value } + @IgnoredOnParcel + var hideSizeInsideDes: Boolean = false + + @IgnoredOnParcel + val decoratedDes: String? + get() = if ( + (apk != null && apk!!.size > 0) + && !hideSizeInsideDes + && ((TextUtils.isEmpty(briefStyle) + || briefStyle?.contains("size") == true) + || briefStyle?.contains("recommend") == true) + ) { + getApk()[0].size + " " + brief + } else { + brief + } + @IgnoredOnParcel val downloadOffText: String? get() = if (shouldUseMirrorInfo()) mirrorData?.mDownloadOffText else mDownloadOffText @IgnoredOnParcel var tagStyle: ArrayList - get() = if (shouldUseMirrorInfo()) mirrorData?.mTagStyle?.apply { removeAll { it.name.toLowerCase(Locale.getDefault()) == "mod版" } } - ?: arrayListOf() else mTagStyle + get() = if (shouldUseMirrorInfo()) mirrorData?.mTagStyle?.apply { + removeAll { + it.name.toLowerCase( + Locale.getDefault() + ) == "mod版" + } + } + ?: arrayListOf() else mTagStyle set(value) { mTagStyle = value } @@ -583,61 +610,66 @@ data class GameEntity( } @Parcelize - data class Dialog(var title: String = "", - var content: String = "", - var sites: List = listOf(), - @SerializedName("close_button_text") - var closeButtonText: String = "", - @SerializedName("confirm_button") - var confirmButton: LinkEntity = LinkEntity(), - var rule: Rule = Rule(), - // 值可能是 ONCE_A_DAY / EVERY_TIME_OPEN - var alert: String = "") : Parcelable { + data class Dialog( + var title: String = "", + var content: String = "", + var sites: List = listOf(), + @SerializedName("close_button_text") + var closeButtonText: String = "", + @SerializedName("confirm_button") + var confirmButton: LinkEntity = LinkEntity(), + var rule: Rule = Rule(), + // 值可能是 ONCE_A_DAY / EVERY_TIME_OPEN + var alert: String = "" + ) : Parcelable { @Parcelize data class Rule( - @SerializedName("package") - var packageName: String = "", - var models: ArrayList = arrayListOf(), - @SerializedName("system_versions") - var systemVersions: ArrayList = arrayListOf(), - @SerializedName("notice_versions") - var noticeVersions: ArrayList = arrayListOf() + @SerializedName("package") + var packageName: String = "", + var models: ArrayList = arrayListOf(), + @SerializedName("system_versions") + var systemVersions: ArrayList = arrayListOf(), + @SerializedName("notice_versions") + var noticeVersions: ArrayList = arrayListOf() ) : Parcelable @Parcelize data class Site( - var url: String = "", - var text: String = "" + var url: String = "", + var text: String = "" ) : Parcelable } @Parcelize - data class PluginLink(@SerializedName("link_id") - var linkId: String = "", - var title: String = "", - @SerializedName("link_type") - var linkType: String = "", // article,Q&A,dialog - @SerializedName("link_text") - var linkText: String = "", - var content: String = "", - @SerializedName("link_community") - var community: CommunityEntity? = CommunityEntity(), - var display: Display? = null) : Parcelable { + data class PluginLink( + @SerializedName("link_id") + var linkId: String = "", + var title: String = "", + @SerializedName("link_type") + var linkType: String = "", // article,Q&A,dialog + @SerializedName("link_text") + var linkText: String = "", + var content: String = "", + @SerializedName("link_community") + var community: CommunityEntity? = CommunityEntity(), + var display: Display? = null + ) : Parcelable { fun getLinkEntity(): LinkEntity { return LinkEntity( - link = linkId, - title = title, - type = linkType, - text = linkText, - community = community, - display = display + link = linkId, + title = title, + type = linkType, + text = linkText, + community = community, + display = display ) } } @Parcelize - data class OverseasAddressDialog(var status: String? = "", var link: String? = "") : Parcelable { + data class OverseasAddressDialog(var status: String? = "", var link: String? = "") : + Parcelable { fun isEnable(): Boolean { return status == "show" || status == "show&download" } @@ -661,44 +693,45 @@ data class GameEntity( @Parcelize data class AssignRemark( - @SerializedName("first_line") - val firstLine: String = "", - @SerializedName("second_line") - val secondLine: String = "", - @SerializedName("marked_red") - val markedRed: Boolean = false, - val recommend: Boolean = false, - @SerializedName("start_time") - val startTime: Long = 0, - @SerializedName("end_time") - val endTime: Long = 0 + @SerializedName("first_line") + val firstLine: String = "", + @SerializedName("second_line") + val secondLine: String = "", + @SerializedName("marked_red") + val markedRed: Boolean = false, + val recommend: Boolean = false, + @SerializedName("start_time") + val startTime: Long = 0, + @SerializedName("end_time") + val endTime: Long = 0 ) : Parcelable @Parcelize data class Auth( - val switch: String? = null, // 开关 - @SerializedName("time_start") - val timeStart: String? = "", // 开始时间 - @SerializedName("time_end") - val timeEnd: String? = "" // 结束时间 + val switch: String? = null, // 开关 + @SerializedName("time_start") + val timeStart: String? = "", // 开始时间 + @SerializedName("time_end") + val timeEnd: String? = "" // 结束时间 ) : Parcelable } @Parcelize data class SimpleGame( - @SerializedName("_id") - var id: String? = null, - @SerializedName("name") - var mName: String? = "", - @SerializedName("name_suffix") - var nameSuffix: String? = null, - @SerializedName("icon") - private var mIcon: String? = null, - @SerializedName("ori_icon") - private var mRawIcon: String? = null, - @SerializedName("icon_subscript") - var iconSubscript: String? = null, - var active: Boolean = false) : Parcelable { + @SerializedName("_id") + var id: String? = null, + @SerializedName("name") + var mName: String? = "", + @SerializedName("name_suffix") + var nameSuffix: String? = null, + @SerializedName("icon") + private var mIcon: String? = null, + @SerializedName("ori_icon") + private var mRawIcon: String? = null, + @SerializedName("icon_subscript") + var iconSubscript: String? = null, + var active: Boolean = false +) : Parcelable { @IgnoredOnParcel val name: String? diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameGuidePopupEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/GameGuidePopupEntity.kt new file mode 100644 index 0000000000..3551ec0126 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/entity/GameGuidePopupEntity.kt @@ -0,0 +1,10 @@ +package com.gh.gamecenter.entity + +import com.google.gson.annotations.SerializedName + +data class GameGuidePopupEntity( + @SerializedName("_id") + val id: String = "", + val content: String = "", + val jump: LinkEntity +) diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameInstall.kt b/app/src/main/java/com/gh/gamecenter/entity/GameInstall.kt index eee109902c..ac98d2f447 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/GameInstall.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/GameInstall.kt @@ -11,7 +11,7 @@ data class GameInstall( var name: String? = "", var icon: String? = "", var iconSubScript: String? = "", - var isSignature: Boolean = false, + var isSignByGh: Boolean = false, var installTime: Long = 0, var version: String = "", var tag: Any? = null) { @@ -20,13 +20,13 @@ data class GameInstall( fun transformGameInstall(game: GameEntity, installedPkgName: String): GameInstall { val gameInstall = GameInstall() val application = HaloApp.getInstance().application - gameInstall.isSignature = PackageUtils.isSignedByGh(application, installedPkgName) + gameInstall.isSignByGh = PackageUtils.isSignedByGh(application, installedPkgName) gameInstall.installTime = PackageUtils.getInstalledTime(application, installedPkgName) gameInstall.id = game.id gameInstall.name = game.name gameInstall.icon = game.rawIcon ?: game.icon gameInstall.iconSubScript = game.iconSubscript - gameInstall.version = PackageUtils.getVersionByPackage(installedPkgName) + gameInstall.version = PackageUtils.getVersionNameByPackageName(installedPkgName) gameInstall.packageName = installedPkgName return gameInstall } diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameUpdateEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/GameUpdateEntity.kt index f18ca384a8..cd5d2bdfb0 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/GameUpdateEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/GameUpdateEntity.kt @@ -17,10 +17,12 @@ data class GameUpdateEntity( var packageName: String = "", var size: String? = null, var version: String? = null, + var currentVersion: String? = null, @SerializedName("gh_version") var ghVersion: String? = null, var url: String? = null, var platform: String? = null, + var readablePlatform: String? = "", var isPluggable: Boolean = false, var etag: String? = null, var brief: String? = null, @@ -36,7 +38,9 @@ data class GameUpdateEntity( @SerializedName("p_button_add_word") var pluginDesc: String = "", //插件功能描述 var pluggableCollection: GameCollectionEntity? = null, // 插件化包所在的合集 - var format: String = "" + var format: String = "", + var signature: String? = "", + var category: String? = "" ) { fun isShowPlugin(location: PluginLocation): Boolean { @@ -61,6 +65,7 @@ data class GameUpdateEntity( gameEntity.indexPlugin = indexPlugin gameEntity.pluginDesc = pluginDesc gameEntity.pluggableCollection = pluggableCollection + gameEntity.category = category val apkEntity = ApkEntity() apkEntity.url = url @@ -72,6 +77,7 @@ data class GameUpdateEntity( apkEntity.etag = etag apkEntity.plugin = plugin apkEntity.format = format + apkEntity.signature = signature val apk = ArrayList() apk.add(apkEntity) diff --git a/app/src/main/java/com/gh/gamecenter/entity/HelpEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/HelpEntity.kt index b54068678a..7adf74f309 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/HelpEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/HelpEntity.kt @@ -7,6 +7,7 @@ import kotlinx.android.parcel.Parcelize @Parcelize data class HelpEntity(@SerializedName("_id") val id: String = "", + @SerializedName(value = "title", alternate = ["index_title"]) val title: String = "", val type: String = "", val content: String = ""): Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/entity/LibaoDetailEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/LibaoDetailEntity.kt index 2721a6ba62..ee8c63f5fa 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/LibaoDetailEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/LibaoDetailEntity.kt @@ -12,6 +12,9 @@ class LibaoDetailEntity { var des: String? = null + @SerializedName("new_des") + var newDes: String? = null + @SerializedName("install_required") var installRequired: Boolean = false diff --git a/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt index cd4af55426..53a94a8d8d 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt @@ -106,8 +106,8 @@ class MeEntity(@SerializedName("is_community_voted") @SerializedName("permissions") val moderatorPermissions: Permissions = Permissions(), - @SerializedName("is_answer_author", alternate = ["is_community_article_author", "is_question_author"]) - val isArticleOrAnswerAuthor: Boolean = false, //用于判断是否是当前评论关联的回答/文章/问题的作者 + @SerializedName("is_answer_author", alternate = ["is_community_article_author", "is_question_author", "is_video_author"]) + val isContentAuthor: Boolean = false, //用于判断是否是当前评论关联的回答/文章/问题/视频的作者 @SerializedName("article_draft") var articleDraft: ArticleDraftEntity? = null,//帖子详情可能返回草稿 diff --git a/app/src/main/java/com/gh/gamecenter/entity/ServerPublishEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/ServerPublishEntity.kt new file mode 100644 index 0000000000..a5c59dcc32 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/entity/ServerPublishEntity.kt @@ -0,0 +1,11 @@ +package com.gh.gamecenter.entity + +import com.google.gson.annotations.SerializedName + +data class ServerPublishEntity( + @SerializedName("prev_server_id") + var prevId: String = "", + @SerializedName("next_server_id") + var nextId: String = "", + var data: List = listOf() +) \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt index ad65cb2ace..69700b3d50 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt @@ -7,34 +7,34 @@ import com.google.gson.annotations.SerializedName import com.halo.assistant.HaloApp data class SettingsEntity( - var download: List? = listOf(), - var suggestion: Suggestion? = null, - var search: Search? = null, - var community: CommunityEntity? = null, - var image: Image? = null, - var support: Support? = null, - @SerializedName("community_entrance") - private var communityEntrance: String? = "", - @SerializedName("game_comment_blacklist") - var gameCommentBlackList: List? = listOf(), - @SerializedName("game_download_blacklist") - var gameDownloadBlackList: List = listOf(), - @SerializedName("game_package_match") - var gamePackageMatch: List? = listOf(), - @SerializedName("ad") - var adList: List? = listOf(), - @SerializedName("appointment_success") - var appointment: Appointment? = Appointment(), - @SerializedName("article_entrance") - private var articleEntrance: String = "", - @SerializedName("video_advertisement") - var videoAdvertisement: VideoAds? = null, //新增字段video_advertisement,可能为空,代表广告关闭 - @SerializedName("game_dome_switch") - var gameDomeSwitch: String = "",//试玩显示开关,on打开 - @SerializedName("permission_popup_switch") - var permissionPopupSwitch: String = "off",//权限引导弹窗开关,on/off - @SerializedName("permission_popup_applied_versions") - var permissionPopupAppliedVersions: PermissionPopupAppliedVersions = PermissionPopupAppliedVersions() + var download: List? = listOf(), + var suggestion: Suggestion? = null, + var search: Search? = null, + var community: CommunityEntity? = null, + var image: Image? = null, + var support: Support? = null, + @SerializedName("community_entrance") + private var communityEntrance: String? = "", + @SerializedName("game_comment_blacklist") + var gameCommentBlackList: List? = listOf(), + @SerializedName("game_download_blacklist") + var gameDownloadBlackList: List = listOf(), + @SerializedName("game_package_match") + var gamePackageMatch: List? = listOf(), + @SerializedName("ad") + var adList: List? = listOf(), + @SerializedName("appointment_success") + var appointment: Appointment? = Appointment(), + @SerializedName("article_entrance") + private var articleEntrance: String = "", + @SerializedName("video_advertisement") + var videoAdvertisement: VideoAds? = null, //新增字段video_advertisement,可能为空,代表广告关闭 + @SerializedName("game_dome_switch") + var gameDomeSwitch: String = "",//试玩显示开关,on打开 + @SerializedName("permission_popup_switch") + var permissionPopupSwitch: String = "off",//权限引导弹窗开关,on/off + @SerializedName("permission_popup_applied_versions") + var permissionPopupAppliedVersions: PermissionPopupAppliedVersions = PermissionPopupAppliedVersions() ) { fun setCommunityEntrance(communityEntrance: String) { @@ -43,9 +43,9 @@ data class SettingsEntity( fun showCommunityEntrance(): Boolean { val preferences = - PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().application) + PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().application) val isFixCommunity = - preferences.getBoolean(Config.FIX_COMMUNITY_KEY, false) + preferences.getBoolean(Config.FIX_COMMUNITY_KEY, false) if (isFixCommunity) return true if ("on" == communityEntrance) { @@ -61,9 +61,9 @@ data class SettingsEntity( fun showArticleEntrance(): Boolean { val preferences = - PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().application) + PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance().application) val isFixArticle = - preferences.getBoolean(Config.FIX_ARTICLE_KEY, false) + preferences.getBoolean(Config.FIX_ARTICLE_KEY, false) if (isFixArticle) return true if ("on" == articleEntrance) { @@ -74,62 +74,68 @@ data class SettingsEntity( } data class Support( - var qq: String? = "", - @SerializedName("qq-group") - var qQun: String? = "", - @SerializedName("qq-group-key") - var qQunKey: String? = "") + var qq: String? = "", + @SerializedName("qq-group") + var qQun: String? = "", + @SerializedName("qq-group-key") + var qQunKey: String? = "" + ) data class Oss( - var jpeg: String? = "", - var gif: String? = "", - var webp: String? = "", - @SerializedName("gif_thumb") - var gitThumb: String? = "", - @SerializedName("gif_watermark") - var gifWaterMark: String? = "") + var jpeg: String? = "", + var gif: String? = "", + var webp: String? = "", + @SerializedName("gif_thumb") + var gitThumb: String? = "", + @SerializedName("gif_watermark") + var gifWaterMark: String? = "" + ) data class Image( - @SerializedName("upload_limit_size") - var uploadLimitSize: Long = 0, - @SerializedName("process_limit_size") - var processLimitSize: Long = 0, - var size: Int = 0, - var quality: Int = 0, - var ratio: Int = 0, - var oss: Oss? = null) + @SerializedName("upload_limit_size") + var uploadLimitSize: Long = 0, + @SerializedName("process_limit_size") + var processLimitSize: Long = 0, + var size: Int = 0, + var quality: Int = 0, + var ratio: Int = 0, + var oss: Oss? = null + ) data class Search( - @SerializedName("default") - var defaultData: List? = listOf(), - @SerializedName("remen") - var hotSearch: List? = listOf(), - @SerializedName("tag") - var hotTag: List? = listOf()) + @SerializedName("default") + var defaultData: List? = listOf(), + @SerializedName("remen") + var hotSearch: List? = listOf(), + @SerializedName("tag") + var hotTag: List? = listOf() + ) data class Suggestion( - var plugin: List? = listOf(), - var game: List? = listOf(), - var libao: List? = listOf(), - var service: List? = listOf(), - var report: List? = listOf(), - @SerializedName("online_game") - var onlineGame: List? = listOf(), - @SerializedName("local_game") - var localGame: List? = listOf(), - @SerializedName("welfare_game") - var welfareGame: List? = listOf(), - @SerializedName("gjlocal_game") - var internationalLocalGame: List? = listOf(), - @SerializedName("gjonline_game") - var internationalOnlineGame: List? = listOf(), - var video: List? = listOf()) + var plugin: List? = listOf(), + var game: List? = listOf(), + var libao: List? = listOf(), + var service: List? = listOf(), + var report: List? = listOf(), + @SerializedName("online_game") + var onlineGame: List? = listOf(), + @SerializedName("local_game") + var localGame: List? = listOf(), + @SerializedName("welfare_game") + var welfareGame: List? = listOf(), + @SerializedName("gjlocal_game") + var internationalLocalGame: List? = listOf(), + @SerializedName("gjonline_game") + var internationalOnlineGame: List? = listOf(), + var video: List? = listOf() + ) data class Download( - var game: String? = "", - var policy: String? = "", - var pluginfy: Boolean = false, - var time: TimeEntity? = null) { + var game: String? = "", + var policy: String? = "", + var pluginfy: Boolean = false, + var time: TimeEntity? = null + ) { class TimeEntity { var start: Long = 0 var end: Long = 0 @@ -137,38 +143,47 @@ data class SettingsEntity( } data class AD( - var location: String? = "", - var image: String? = "", - var title: String? = "", - var type: String? = "", - var text: String? = "", - var link: String? = "", - @SerializedName("link_community", alternate = ["community"]) - var community: CommunityEntity? = CommunityEntity()) { + var location: String? = "", + var image: String? = "", + var title: String? = "", + var type: String? = "", + var text: String? = "", + var link: String? = "", + @SerializedName("link_community", alternate = ["community"]) + var community: CommunityEntity? = CommunityEntity() + ) { fun toLinkEntity(): LinkEntity { - return LinkEntity(title = title, image = image, link = link, type = type, text = text, community = community) + return LinkEntity( + title = title, + image = image, + link = link, + type = type, + text = text, + community = community + ) } } data class GameWithPackages( - @SerializedName("game_id") - var gameId: String? = "", - var packages: List? = listOf() + @SerializedName("game_id") + var gameId: String? = "", + var packages: List? = listOf() ) data class HotSearch( - @SerializedName("_id") - var id: String, - var name: String, - val icon: String, - @SerializedName("name_suffix") - var nameSuffix: String? = null, - @SerializedName("ori_icon") - var rawIcon: String? = null, - @SerializedName("icon_subscript") - var iconSubscript: String? = null, - @SerializedName("recommend_type") - var recommendType: String? = "none"//none:无、hot: 热门、new: 上新、surge: 飙升 + @SerializedName("_id") + var id: String, + var name: String, + val icon: String, + @SerializedName("name_suffix") + var nameSuffix: String? = null, + @SerializedName("ori_icon") + var rawIcon: String? = null, + @SerializedName("icon_subscript") + var iconSubscript: String? = null, + @SerializedName("recommend_type") + var recommendType: String? = "none",//none:无、hot: 热门、new: 上新、surge: 飙升 + var type: String? = ""//论坛类型 ) { var exposureEvent: ExposureEvent? = null @@ -178,10 +193,11 @@ data class SettingsEntity( } data class Appointment( - @SerializedName("with_mobile") - var withMobile: DialogConfig = DialogConfig(), - @SerializedName("without_mobile") - var withoutMobile: DialogConfig = DialogConfig()) { + @SerializedName("with_mobile") + var withMobile: DialogConfig = DialogConfig(), + @SerializedName("without_mobile") + var withoutMobile: DialogConfig = DialogConfig() + ) { class DialogConfig { @SerializedName("html_content") var htmlContent: String = "" @@ -196,31 +212,31 @@ data class SettingsEntity( } data class VideoAds( - var center: ArrayList? = null, - var left: ArrayList? = null, - var right: ArrayList? = null + var center: ArrayList? = null, + var left: ArrayList? = null, + var right: ArrayList? = null ) data class Advertisement( - var duration: Int = -1, //广告总显示秒数 - var frequency: Int = -1,//广告出现频率 - var image: String = "", - var link: String = "", - @SerializedName("link_community") - var linkCommunity: CommunityEntity? = null, - @SerializedName("link_type") - var linkType: String = "", - var title: String = "", - var type: String = "", //广告类型。revolving走马灯,image图片 - @SerializedName("link_text") - var text: String = "", - var display: Display? = Display() + var duration: Int = -1, //广告总显示秒数 + var frequency: Int = -1,//广告出现频率 + var image: String = "", + var link: String = "", + @SerializedName("link_community") + var linkCommunity: CommunityEntity? = null, + @SerializedName("link_type") + var linkType: String = "", + var title: String = "", + var type: String = "", //广告类型。revolving走马灯,image图片 + @SerializedName("link_text") + var text: String = "", + var display: Display? = Display() ) data class PermissionPopupAppliedVersions( - val install: ArrayList = arrayListOf(), - @SerializedName("xapk_unzip") - val xapkUnzip: ArrayList = arrayListOf() + val install: ArrayList = arrayListOf(), + @SerializedName("xapk_unzip") + val xapkUnzip: ArrayList = arrayListOf() ) } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/entity/TaskEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/TaskEntity.kt index 7a091ffb3d..39ef23d208 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/TaskEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/TaskEntity.kt @@ -14,7 +14,7 @@ data class TaskEntity( var descr: String = "", var icon: String = "", var action: String = "", - var energy: Int = 0, + var energy: Long = 0, var done: Int = 0, var limit: Int = 0, var quota: Int = 0, // 任务指标,代表需要做多少个才算完成 diff --git a/app/src/main/java/com/gh/gamecenter/entity/TestEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/TestEntity.kt index e2b65baadf..ba2c6d674a 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/TestEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/TestEntity.kt @@ -7,6 +7,7 @@ import com.google.gson.annotations.SerializedName class TestEntity : Parcelable { var type: String? = null + var text: String? = null var start: Long = 0 var end: Long = 0 diff --git a/app/src/main/java/com/gh/gamecenter/entity/WelcomeDialogEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/WelcomeDialogEntity.kt index a4c96ab45e..9a9e5d3bfd 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/WelcomeDialogEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/WelcomeDialogEntity.kt @@ -5,6 +5,8 @@ import kotlinx.android.parcel.Parcelize @Parcelize data class WelcomeDialogEntity( - @SerializedName("_id") - var id: String? = "", - var time: Long? = 0):LinkEntity() \ No newline at end of file + @SerializedName("_id") + var id: String? = "", + var time: Long? = 0, + var packages: ArrayList? = arrayListOf() +) : LinkEntity() \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListAdapter.kt index d5885fe719..50e7e47111 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListAdapter.kt @@ -11,6 +11,7 @@ import com.gh.common.constant.ItemViewType import com.gh.common.syncpage.ISyncAdapterHandler import com.gh.common.util.MtaHelper import com.gh.common.util.NewLogUtils +import com.gh.common.util.dip2px import com.gh.gamecenter.R import com.gh.gamecenter.adapter.viewholder.FooterViewHolder import com.gh.gamecenter.baselist.ListAdapter @@ -71,6 +72,11 @@ class ForumArticleAskListAdapter(context: Context, val bbsId: String, val mEntra val binding = answerViewHolder.binding binding.forumNameLl.visibility = View.GONE + val contentMarginTop = if (answer.type == "answer") 3F.dip2px() else 12F.dip2px() + binding.content.layoutParams = (binding.content.layoutParams as ViewGroup.MarginLayoutParams).apply { + topMargin = contentMarginTop + } + val params = binding.includeVoteAndComment.root.layoutParams as LinearLayout.LayoutParams params.width = LinearLayout.LayoutParams.MATCH_PARENT params.leftMargin = 0 @@ -94,7 +100,7 @@ class ForumArticleAskListAdapter(context: Context, val bbsId: String, val mEntra "video" -> { NewLogUtils.logForumDetailFeedContentClick("click_forum_detail_content", userId, contentId, "视频帖", sequence, bbsId, bbsType, tabInfo) MtaHelper.onEvent(holder.getEventId(entrance), holder.getKey(entrance), "${answer.articleTitle}(${answer.id})") - mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, answer.id ?:"")) + mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, answer.id ?:"", bbsId)) } "question" -> { NewLogUtils.logForumDetailFeedContentClick("click_forum_detail_content", userId, contentId, "提问帖", sequence, bbsId, bbsType, tabInfo) diff --git a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListFragment.kt index ff073c0796..ceac78c1b4 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListFragment.kt @@ -12,6 +12,7 @@ import com.gh.gamecenter.baselist.ListAdapter import com.gh.gamecenter.baselist.ListFragment import com.gh.gamecenter.eventbus.EBDeleteDetail import com.gh.gamecenter.eventbus.EBTypeChange +import com.gh.gamecenter.eventbus.EBUserFollow import com.gh.gamecenter.forum.home.ForumScrollCalculatorHelper import com.gh.gamecenter.qa.CommunityFragment import com.gh.gamecenter.qa.entity.AnswerEntity @@ -245,4 +246,18 @@ class ForumArticleAskListFragment : ListFragment 1) notifyDataSetChanged() + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailActivity.kt b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailActivity.kt index a79d0f88d9..f5d4c85b05 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailActivity.kt @@ -32,6 +32,8 @@ class ForumDetailActivity : BaseActivity() { return Pair(intent.getStringExtra(EntranceUtils.KEY_BBS_ID) ?: "", "") } + override fun preventRecreateFragmentByFragmentManager(): Boolean = true + companion object { @JvmStatic fun getIntent(context: Context, bbsId: String, entrance: String): Intent { diff --git a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailFragment.kt index b77b4ba1c0..dcfb8abd00 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailFragment.kt @@ -298,9 +298,7 @@ class ForumDetailFragment : BaseLazyTabFragment() { mBinding.followTv.setTextColor(ContextCompat.getColor(requireContext(), if (me.isFollower) R.color.text_999999 else R.color.white)) mBinding.followTv.background = ContextCompat.getDrawable(requireContext(), if (me.isFollower) R.drawable.bg_shape_f5_radius_999 else R.drawable.login_btn_bg) - mBinding.moderatorContainer.post { - showModeratorGuide() - } + showModeratorGuide() } } @@ -309,23 +307,35 @@ class ForumDetailFragment : BaseLazyTabFragment() { if (time >= 2) return mBinding.run { - val location = IntArray(2) - moderatorTv.getLocationOnScreen(location) - moderatorGuideContainer.visibility = View.VISIBLE - moderatorGuideContainer.layoutParams = (moderatorGuideContainer.layoutParams as ViewGroup.MarginLayoutParams).apply { - leftMargin = location[0] - 16F.dip2px() - } - moderatorGuideClose.setOnClickListener { - moderatorGuideContainer.visibility = View.GONE - } - postDelayedRunnable({ tryCatchInRelease { - moderatorGuideContainer.visibility = View.GONE - } - }, 3000) + val location = IntArray(2) + moderatorTv.getLocationOnScreen(location) + moderatorGuideContainer.layoutParams = (moderatorGuideContainer.layoutParams as ViewGroup.MarginLayoutParams).apply { + leftMargin = location[0] - 16F.dip2px() + } + moderatorGuideContainer.alpha = 0F + moderatorGuideContainer.visibility = View.VISIBLE + moderatorGuideContainer.animate().alpha(1F).setDuration(200).start() + moderatorGuideClose.setOnClickListener { + if (moderatorGuideContainer.visibility != View.GONE) { + moderatorGuideContainer.animate().alpha(0F).setDuration(200) + .withEndAction { moderatorGuideContainer.visibility = View.GONE }.start() + } + } - SPUtils.setInt(Constants.SP_FORUM_DETAIL_MODERATOR_GUIDE, ++time) + postDelayedRunnable({ + tryCatchInRelease { + if (moderatorGuideContainer.visibility != View.GONE) { + moderatorGuideContainer.animate().alpha(0F).setDuration(200) + .withEndAction { moderatorGuideContainer.visibility = View.GONE }.start() + } + } + }, 3000) + + SPUtils.setInt(Constants.SP_FORUM_DETAIL_MODERATOR_GUIDE, ++time) + } + }, 1000) } } @@ -394,13 +404,19 @@ class ForumDetailFragment : BaseLazyTabFragment() { R.id.followTv -> { debounceActionWithInterval(R.id.followTv) { ifLogin(mEntrance) { - val forumEntity = ForumEntity(mForumDetail?.id - ?: "", mForumDetail?.game!!, mForumDetail?.name ?: "") + val forumEntity = ForumEntity( + id = mForumDetail?.id ?: "", + game = mForumDetail?.game!!, + name = mForumDetail?.name ?: "", + type = mForumDetail?.type ?: "", + icon = mForumDetail?.icon ?: "" + ) if (mForumDetail?.me?.isFollower == true) { mViewModel?.unFollowForum { MtaHelper.onEvent("论坛详情", "顶部区域", "取消关注") mForumDetail?.me?.isFollower = false + ToastUtils.showToast("取消成功") initUI() EventBus.getDefault().post(EBForumFollowChange(forumEntity, false)) } diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeFragment.kt index 21e4558ca5..fd59cc97d4 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeFragment.kt @@ -107,7 +107,7 @@ class CommunityHomeFragment : LazyFragment() { tryCatchInRelease { guideTipIv.animate().alpha(1F).setDuration(200).start() } - }, 100) + }, 500) } SPUtils.setBoolean(Constants.SP_COMMUNITY_HOME_GUIDE, true) } @@ -146,6 +146,11 @@ class CommunityHomeFragment : LazyFragment() { 1 -> NewLogUtils.logCommunityHomeEvent("click_forum_tab") 2 -> NewLogUtils.logCommunityHomeEvent("click_activity_tab") } + + if (position == 2) { + FloatingBackViewManager.disableBackView() + FloatingBackViewManager.dismissBackView(requireActivity()) + } }, onPageScrolled = { position, positionOffset, _ -> if (position + 1 != mTabList.size) { @@ -322,7 +327,7 @@ class CommunityHomeFragment : LazyFragment() { tryCatchInRelease { guideTipIv.animate().alpha(1F).setDuration(200).start() } - }, 100) + }, 500) SPUtils.setBoolean(Constants.SP_COMMUNITY_HOME_VIDEO_GUIDE, true) } @@ -367,6 +372,8 @@ class CommunityHomeFragment : LazyFragment() { @Subscribe(threadMode = ThreadMode.MAIN) fun onEventMainThread(status: EBTypeChange) { + if (mBinding?.viewPager?.currentItem != 0) return + if (status.type == CommunityFragment.EB_SHOW_QUESTION_BUTTON) { setPutQuestionButtonStatus(View.VISIBLE) } else if (status.type == CommunityFragment.EB_HIDE_QUESTION_BUTTON) { @@ -377,6 +384,7 @@ class CommunityHomeFragment : LazyFragment() { private fun setPutQuestionButtonStatus(visibility: Int) { mBinding?.run { if (communityEditBtn.visibility == visibility) return + if (visibility == View.GONE) { val animation = AnimationUtils.loadAnimation(context, R.anim.button_anim_exit) communityEditBtn.startAnimation(animation) diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumActivityAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumActivityAdapter.kt index 533c9aa95b..7ac584ee5e 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumActivityAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumActivityAdapter.kt @@ -125,7 +125,7 @@ class ForumActivityAdapter(context: Context, if (status == "正在评奖") ToastUtils.toast("活动正在评奖中") if (status == "奖励发放中") ToastUtils.toast("活动奖励发放中~") if (status == "已结束") ToastUtils.toast("活动已结束~") - DirectUtils.directToActivityDetail(mContext, activityEntity.id, mEntrance) + DirectUtils.directToActivityDetail(mContext, activityEntity.id, mViewModel.categoryId, mEntrance) } } } diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleAskItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleAskItemViewHolder.kt index a03ef08793..257b29932f 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleAskItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleAskItemViewHolder.kt @@ -11,6 +11,7 @@ import com.gh.gamecenter.R import com.gh.gamecenter.databinding.CommunityAnswerItemBinding import com.gh.gamecenter.entity.CommunityEntity import com.gh.gamecenter.entity.ForumVideoEntity +import com.gh.gamecenter.eventbus.EBUserFollow import com.gh.gamecenter.forum.detail.ForumDetailActivity import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.qa.answer.BaseAnswerOrArticleItemViewHolder @@ -24,6 +25,7 @@ import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack import com.shuyu.gsyvideoplayer.utils.OrientationUtils +import org.greenrobot.eventbus.EventBus class ForumArticleAskItemViewHolder(val binding: CommunityAnswerItemBinding) : BaseAnswerOrArticleItemViewHolder(binding.root) { @@ -43,16 +45,25 @@ class ForumArticleAskItemViewHolder(val binding: CommunityAnswerItemBinding) : B binding.userIcon.display(entity.user.border, entity.user.icon, entity.user.auth?.icon) binding.forumNameTv.text = entity.bbs.name + binding.content.maxLines = if (entity.type == "answer") 3 else 2 if (entity.type == "answer") { binding.content.goneIf(entity.content.isEmpty()) binding.content.text = entity.content val title = " ${entity.questions.title}" - binding.questionTitle.text = SpanBuilder(title).image(0, 1, R.drawable.ic_ask_label).build() + val drawable = R.drawable.ic_ask_label.toDrawable() + drawable?.run { + setBounds(0, 0, 16F.dip2px(), 16F.dip2px()) + binding.questionTitle.text = SpanBuilder(title).image(0, 1, this).build() + } } else if (entity.type == "question") { binding.content.goneIf(entity.questions.description.isNullOrEmpty()) binding.content.text = entity.questions.description val title = " ${entity.questions.title}" - binding.title.text = SpanBuilder(title).image(0, 1, R.drawable.ic_ask_label).build() + val drawable = R.drawable.ic_ask_label.toDrawable() + drawable?.run { + setBounds(0, 0, 16F.dip2px(), 16F.dip2px()) + binding.title.text = SpanBuilder(title).image(0, 1, this).build() + } } else { binding.content.visibility = View.VISIBLE if (entity.type == "video") { @@ -137,6 +148,8 @@ class ForumArticleAskItemViewHolder(val binding: CommunityAnswerItemBinding) : B binding.concernBtn.visibility = View.GONE binding.followedUserTv.visibility = View.VISIBLE binding.time.text = " · ${binding.time.text}" + ToastUtils.toast("关注成功") + EventBus.getDefault().post(EBUserFollow(userId, true)) } }) } @@ -274,8 +287,9 @@ class ForumArticleAskItemViewHolder(val binding: CommunityAnswerItemBinding) : B MtaHelper.onEvent(getEventId(entrance), getKey(entrance), "评论图标") } "video" -> { + val communityId = if (entity.bbs.id.isNotEmpty()) entity.bbs.id else UserManager.getInstance().community.id itemView.context.startActivity(ForumVideoDetailActivity.getIntent(itemView.context, entity.id - ?: "",true)) + ?: "",communityId, true)) } "question" -> { if (entity.questions.answerCount == 0) { diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListAdapter.kt index 9db55aa20f..84e1bd38bf 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListAdapter.kt @@ -124,7 +124,7 @@ class ForumArticleListAdapter(context: Context, } "video" -> { MtaHelper.onEvent("论坛首页", viewHolder.getKey(BaseActivity.mergeEntranceAndPath(mEntrance, path)), "${articleEntity.title}(${articleEntity.id})") - mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, articleEntity.id ?:"")) + mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, articleEntity.id ?:"", articleEntity.community.id)) } "question" -> { MtaHelper.onEvent("论坛首页", viewHolder.getKey(BaseActivity.mergeEntranceAndPath(mEntrance, path)), "${articleEntity.title}(${articleEntity.id})") diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListFragment.kt index 86c54675bd..80b85093c7 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumArticleListFragment.kt @@ -12,9 +12,7 @@ import com.gh.gamecenter.R import com.gh.gamecenter.baselist.LazyListFragment import com.gh.gamecenter.databinding.FragmentForumListBinding import com.gh.gamecenter.entity.ForumEntity -import com.gh.gamecenter.eventbus.EBDeleteDetail -import com.gh.gamecenter.eventbus.EBForumRecordChange -import com.gh.gamecenter.eventbus.EBTypeChange +import com.gh.gamecenter.eventbus.* import com.gh.gamecenter.forum.home.ForumScrollCalculatorHelper.Companion.getPlaySchedule import com.gh.gamecenter.forum.home.ForumScrollCalculatorHelper.Companion.savePlaySchedule import com.gh.gamecenter.qa.CommunityFragment @@ -309,4 +307,18 @@ class ForumArticleListFragment : LazyListFragment 1) notifyDataSetChanged() + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumFragment.kt index 47f0bb1a34..deee1ac205 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumFragment.kt @@ -49,6 +49,7 @@ class ForumFragment: LazyFragment(), SwipeRefreshLayout.OnRefreshListener { mUserViewModel?.loginObsUserinfo?.observe(this, Observer { if (!mIsFirst) { if (it?.data == null) { + mViewModel?.followForums?.clear() mBinding?.followForumContainer?.visibility = View.GONE } onRefresh() diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumViewModel.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumViewModel.kt index a2a79caf7d..cc3510a914 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumViewModel.kt @@ -101,7 +101,7 @@ class ForumViewModel(application: Application) : AndroidViewModel(application) { @SuppressLint("CheckResult") fun getHotForum() { - api.getHotForumWithPageSize(1, 100) + api.getHotForum(1) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Response>() { diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/HotForumsAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/home/HotForumsAdapter.kt index 0b812f84df..23b61c43c2 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/HotForumsAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/HotForumsAdapter.kt @@ -59,6 +59,7 @@ class HotForumsAdapter(context: Context, followTv.setBackgroundResource(R.drawable.button_round_f0f8fa) followTv.setTextColor(R.color.theme_font.toColor()) followTv.text = "关注" + ToastUtils.showToast("取消成功") EventBus.getDefault().post(EBForumFollowChange(forumEntity, false)) } } else { diff --git a/app/src/main/java/com/gh/gamecenter/forum/moderator/ApplyModeratorActivity.kt b/app/src/main/java/com/gh/gamecenter/forum/moderator/ApplyModeratorActivity.kt index 5e96bb8289..195f6f6eb2 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/moderator/ApplyModeratorActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/moderator/ApplyModeratorActivity.kt @@ -9,12 +9,14 @@ import com.gh.common.util.DisplayUtils import com.gh.common.util.EntranceUtils import com.gh.gamecenter.NormalActivity import com.gh.gamecenter.R +import com.gh.gamecenter.entity.ApplyModeratorStatusEntity class ApplyModeratorActivity : NormalActivity() { companion object { - fun getIntent(context: Context, bbsId: String): Intent { + fun getIntent(context: Context, bbsId: String, status: ApplyModeratorStatusEntity): Intent { val bundle = Bundle() bundle.putString(EntranceUtils.KEY_BBS_ID, bbsId) + bundle.putParcelable("status", status) return getTargetIntent( context, ApplyModeratorActivity::class.java, @@ -34,10 +36,11 @@ class ApplyModeratorActivity : NormalActivity() { setStatusBarTransparent() } - private fun setStatusBarTransparent(){ + private fun setStatusBarTransparent() { DisplayUtils.transparentStatusBar(this) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR + window.decorView.systemUiVisibility = + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR } } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/moderator/ApplyModeratorFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/moderator/ApplyModeratorFragment.kt index 4e90cd518a..c711820772 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/moderator/ApplyModeratorFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/moderator/ApplyModeratorFragment.kt @@ -30,15 +30,17 @@ class ApplyModeratorFragment : NormalFragment() { private var mAdapter: ModeratorTaskAdapter? = null private var mDataList = ArrayList() private var mBbsId = "" + private var mStatus = ApplyModeratorStatusEntity() override fun getInflatedLayout() = FragmentApplyModeratorBinding - .inflate(layoutInflater, null, false) - .apply { mBinding = this } - .root + .inflate(layoutInflater, null, false) + .apply { mBinding = this } + .root override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mBbsId = arguments?.getString(EntranceUtils.KEY_BBS_ID) ?: "" + mStatus = arguments?.getParcelable("status") ?: ApplyModeratorStatusEntity() val factory = ApplyModeratorViewModel.Factory(mBbsId) mDataList = getModeratorTaskList() mViewModel = viewModelProvider(factory) @@ -57,92 +59,99 @@ class ApplyModeratorFragment : NormalFragment() { NewLogUtils.logApplyModeratorFApplyOrQQClick("click_QQ_number", UserManager.getInstance().userId) DirectUtils.directToQqGroup( requireContext(), - groupTv.text.toString() + mStatus.qqGroupKey ) } + groupTv.text = mStatus.qqGroup } mAdapter?.setListData(mDataList) mViewModel?.statusEntity?.observe(this, Observer { it?.let { checkStatus(it) - mBinding?.groupTv?.text = it.qqGroup } }) + if (mStatus.status == "todo") { + changeToAudit() + } } private fun getModeratorTaskList(): ArrayList { return arrayListOf( - ApplyModeratorTaskEntity().apply { - taskName = "通过礼仪考试" - taskIcon = R.drawable.ic_moderator_task_etiquette - taskAction = View.OnClickListener { - val taskState = if (finishedTask) "已完成" else "未完成" - NewLogUtils.logApplyModeratorFinishClick(taskName, taskState) - if (!finishedTask) { - DirectUtils.directToRegulationTestPage(requireContext()) - } - } - }, - - ApplyModeratorTaskEntity().apply { - taskName = "完成实名认证" - taskIcon = R.drawable.ic_moderator_task_id_card - taskAction = View.OnClickListener { - val taskState = if (finishedTask) "已完成" else "未完成" - NewLogUtils.logApplyModeratorFinishClick(taskName, taskState) - if (!finishedTask) { - val currentActivity = AppManager.getInstance().currentActivity() - AvoidOnResultManager.getInstance(currentActivity as AppCompatActivity) - .startForResult( - UserInfoEditActivity.getIntent( - context, - UserViewModel.TYPE_ID_CARD - ), object : - Callback { - override fun onActivityResult(resultCode: Int, data: Intent?) { - - } - }) - } - } - }, - - ApplyModeratorTaskEntity().apply { - taskName = "论坛活跃度" - taskIcon = R.drawable.ic_moderator_task_activity - taskDescription = "活跃度=发帖数量+回帖数量+回复数量≥20" - taskAction = View.OnClickListener { - val taskState = if (finishedTask) "已完成" else "未完成" - NewLogUtils.logApplyModeratorFinishClick(taskName, taskState) - if (!finishedTask) { - startActivity( - ForumDetailActivity.getIntent( - requireContext(), - mBbsId, - "版主申请" - ) - ) - } - } - }, - - ApplyModeratorTaskEntity().apply { - taskName = "论坛精品帖≥2" - taskIcon = R.drawable.ic_moderator_task_choiceness - taskAction = View.OnClickListener { - val taskState = if (finishedTask) "已完成" else "未完成" - NewLogUtils.logApplyModeratorFinishClick(taskName, taskState) - if (!finishedTask) { - startActivity( - ForumDetailActivity.getIntent( - requireContext(), - mBbsId, - "版主申请" - ) - ) - } + ApplyModeratorTaskEntity().apply { + taskName = "通过礼仪考试" + taskIcon = R.drawable.ic_moderator_task_etiquette + taskAction = View.OnClickListener { + val taskState = if (finishedTask) "已完成" else "未完成" + NewLogUtils.logApplyModeratorFinishClick(taskName, taskState) + if (!finishedTask) { + DirectUtils.directToRegulationTestPage(requireContext()) } } + finishedTask = mStatus.condition.etiquette + }, + + ApplyModeratorTaskEntity().apply { + taskName = "完成实名认证" + taskIcon = R.drawable.ic_moderator_task_id_card + taskAction = View.OnClickListener { + val taskState = if (finishedTask) "已完成" else "未完成" + NewLogUtils.logApplyModeratorFinishClick(taskName, taskState) + if (!finishedTask) { + val currentActivity = AppManager.getInstance().currentActivity() + AvoidOnResultManager.getInstance(currentActivity as AppCompatActivity) + .startForResult( + UserInfoEditActivity.getIntent( + context, + UserViewModel.TYPE_ID_CARD + ), object : + Callback { + override fun onActivityResult(resultCode: Int, data: Intent?) { + + } + }) + } + } + finishedTask = mStatus.condition.idCard + }, + + ApplyModeratorTaskEntity().apply { + taskName = "论坛活跃度" + taskIcon = R.drawable.ic_moderator_task_activity + taskDescription = "活跃度=发帖数量+回帖数量+回复数量≥20" + taskAction = View.OnClickListener { + val taskState = if (finishedTask) "已完成" else "未完成" + NewLogUtils.logApplyModeratorFinishClick(taskName, taskState) + if (!finishedTask) { + startActivity( + ForumDetailActivity.getIntent( + requireContext(), + mBbsId, + "版主申请" + ) + ) + } + } + finishedTask = mStatus.condition.activity + }, + + ApplyModeratorTaskEntity().apply { + taskName = "论坛精品帖≥2" + taskIcon = R.drawable.ic_moderator_task_choiceness + taskAction = View.OnClickListener { + val taskState = if (finishedTask) "已完成" else "未完成" + NewLogUtils.logApplyModeratorFinishClick(taskName, taskState) + if (!finishedTask) { + startActivity( + ForumDetailActivity.getIntent( + requireContext(), + mBbsId, + "版主申请" + ) + ) + } + } + finishedTask = mStatus.condition.choiceness + } ) } @@ -172,25 +181,33 @@ class ApplyModeratorFragment : NormalFragment() { } mBinding?.applyTv?.alpha = if (allFinished) 1F else 0.4F val listener = View.OnClickListener { - NewLogUtils.logApplyModeratorFApplyOrQQClick("click_apply", UserManager.getInstance().userId) - mViewModel?.applyModerator { - ApplyModeratorDialogFragment.show( - requireActivity() as AppCompatActivity, - mBinding?.groupTv?.text.toString() - ) { - mViewModel?.getModeratorsApplyStatus() + if (!ClickUtils.isFastDoubleClick(R.id.applyTv)) { + NewLogUtils.logApplyModeratorFApplyOrQQClick("click_apply", UserManager.getInstance().userId) + mViewModel?.applyModerator { + ApplyModeratorDialogFragment.show( + requireActivity() as AppCompatActivity, + mStatus.qqGroup, + mStatus.qqGroupKey + ) { + mViewModel?.getModeratorsApplyStatus() + changeToAudit() + } } } } mBinding?.applyTv?.setOnClickListener(if (allFinished) listener else null) } if (status.status == "todo") { - mBinding?.run { - applyTv.text = "审核中" - applyTv.alpha = 0.4F - applyTv.setOnClickListener(null) - addGroupContainer.visibility = View.VISIBLE - } + changeToAudit() + } + } + + private fun changeToAudit() { + mBinding?.run { + applyTv.text = "审核中" + applyTv.alpha = 0.4F + applyTv.setOnClickListener(null) + addGroupContainer.visibility = View.VISIBLE } } diff --git a/app/src/main/java/com/gh/gamecenter/forum/moderator/ModeratorListFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/moderator/ModeratorListFragment.kt index e0ce7310ff..409663d637 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/moderator/ModeratorListFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/moderator/ModeratorListFragment.kt @@ -13,6 +13,7 @@ import com.gh.common.constant.Constants import com.gh.common.util.* import com.gh.gamecenter.NewsDetailActivity import com.gh.gamecenter.R +import com.gh.gamecenter.entity.ApplyModeratorStatusEntity import com.gh.gamecenter.eventbus.EBUserFollow import com.gh.gamecenter.normal.NormalFragment import kotterknife.bindView @@ -24,15 +25,14 @@ class ModeratorListFragment : NormalFragment() { private val mReuseLoading by bindView(R.id.reuse_ll_loading) private val mNoConnection by bindView(R.id.reuse_no_connection) private val mNoneData by bindView(R.id.reuse_none_data) - private val mGroupContainer by bindView(R.id.groupContainer) private val mToolbar by bindView(R.id.toolbar) private val mDoubtIv by bindView(R.id.doubtIv) private val mApplyTv by bindView(R.id.applyTv) - private val mGroupTv by bindView(R.id.groupTv) private var mViewModel: ModeratorListViewModel? = null private var mAdapter: ModeratorListAdapter? = null private var mBbsId: String = "" private var mBbsType: String = "" + private var mStatus: ApplyModeratorStatusEntity = ApplyModeratorStatusEntity() override fun getLayoutId(): Int = R.layout.fragment_moderator_list override fun onCreate(savedInstanceState: Bundle?) { @@ -43,10 +43,6 @@ class ModeratorListFragment : NormalFragment() { val factory = ModeratorListViewModel.Factory(mBbsId) mViewModel = viewModelProvider(factory) - mViewModel?.qqGroupNumber?.observe(this, Observer { - mGroupTv.text = it - }) - mViewModel?.isModerators?.observe(this, Observer { if (it) { mApplyTv.background = R.drawable.bg_forum_follow.toDrawable() @@ -65,7 +61,6 @@ class ModeratorListFragment : NormalFragment() { mNoConnection.visibility = View.GONE if (it.isNotEmpty()) { mNoneData.visibility = View.GONE - mGroupContainer.visibility = View.VISIBLE mAdapter?.setListData(it) } else { mNoneData.visibility = View.VISIBLE @@ -75,6 +70,10 @@ class ModeratorListFragment : NormalFragment() { mNoConnection.visibility = View.VISIBLE } }) + + mViewModel?.statusEntity?.observe(this, Observer { + it?.run { mStatus = this } + }) } @@ -107,17 +106,12 @@ class ModeratorListFragment : NormalFragment() { requireContext().startActivity( ApplyModeratorActivity.getIntent( requireContext(), - mBbsId + mBbsId, + mStatus ) ) } } - mGroupTv.setOnClickListener { - DirectUtils.directToQqGroup( - requireContext(), - mGroupTv.text.toString() - ) - } } @Subscribe(threadMode = ThreadMode.MAIN) @@ -130,6 +124,7 @@ class ModeratorListFragment : NormalFragment() { override fun onResume() { super.onResume() mViewModel?.getModeratorsInfo() + mViewModel?.getModeratorsApplyStatus() } override fun onStop() { diff --git a/app/src/main/java/com/gh/gamecenter/forum/moderator/ModeratorListViewModel.kt b/app/src/main/java/com/gh/gamecenter/forum/moderator/ModeratorListViewModel.kt index 6da7016c11..df0f3fc78b 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/moderator/ModeratorListViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/moderator/ModeratorListViewModel.kt @@ -7,7 +7,9 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import com.gh.gamecenter.R +import com.gh.gamecenter.entity.ApplyModeratorStatusEntity import com.gh.gamecenter.entity.PersonalEntity +import com.gh.gamecenter.eventbus.EBUserFollow import com.gh.gamecenter.retrofit.BiResponse import com.gh.gamecenter.retrofit.Response import com.gh.gamecenter.retrofit.RetrofitManager @@ -17,6 +19,7 @@ import com.lightgame.utils.Utils import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody +import org.greenrobot.eventbus.EventBus import retrofit2.HttpException class ModeratorListViewModel(application: Application, val bbsId: String) : @@ -24,11 +27,29 @@ class ModeratorListViewModel(application: Application, val bbsId: String) : val moderators = MutableLiveData>() val qqGroupNumber = MutableLiveData() + val qqGroupKey = MutableLiveData() val isModerators = MutableLiveData() + val statusEntity = MutableLiveData() init { getModerators() - getModeratorsInfo() + } + + fun getModeratorsApplyStatus() { + RetrofitManager.getInstance(getApplication()).api.getApplyModeratorStatus(bbsId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: ApplyModeratorStatusEntity?) { + super.onResponse(response) + statusEntity.postValue(response) + } + + override fun onFailure(e: HttpException?) { + super.onFailure(e) + statusEntity.postValue(null) + } + }) } fun getModerators() { @@ -57,6 +78,7 @@ class ModeratorListViewModel(application: Application, val bbsId: String) : override fun onSuccess(data: JsonObject) { isModerators.postValue(data["is_moderators"].asBoolean) qqGroupNumber.postValue(data["moderators_qq_group"].asString) + qqGroupKey.postValue(data["moderators_qq_group_key"].asString) } override fun onFailure(exception: Exception) { @@ -84,6 +106,7 @@ class ModeratorListViewModel(application: Application, val bbsId: String) : } else { Utils.toast(getApplication(), R.string.concern_cancel) } + EventBus.getDefault().post(EBUserFollow(userId, isFollow)) } override fun onFailure(e: HttpException?) { diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListAdapter.kt index 15f2a99d2e..0c28930e73 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListAdapter.kt @@ -111,7 +111,7 @@ class ForumContentSearchListAdapter(context: Context, val mListViewModel: ForumC "video" -> { NewLogUtils.logForumSearchResultClick("内容tab", answer.bbs.id, bbsType, answer.id ?: "", "视频帖", answer.user.id ?: "", position + 1) MtaHelper.onEvent(holder.getEventId(entrance), holder.getKey(entrance), "${answer.articleTitle}(${answer.id})") - mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, answer.id ?:"")) + mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, answer.id ?:"", answer.bbs.id)) } else -> { NewLogUtils.logForumSearchResultClick("内容tab", answer.bbs.id, bbsType, answer.id ?: "", "提问帖", answer.user.id ?: "", position + 1) @@ -150,7 +150,7 @@ class ForumContentSearchListAdapter(context: Context, val mListViewModel: ForumC val answerViewHolder = ForumArticleAskItemViewHolder(includedAnswerItem) answerViewHolder.bindForumAnswerItem(answer, mEntrance, "") answerViewHolder.itemView.setOnClickListener { - mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, answer.id ?:"")) + mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, answer.id ?:"", answer.bbs.id)) } } } else { @@ -194,7 +194,7 @@ class ForumContentSearchListAdapter(context: Context, val mListViewModel: ForumC } "video" -> { NewLogUtils.logForumSearchResultClick("", answer.bbs.id, bbsType, answer.id ?: "", "视频帖", answer.user.id ?: "", position + 1) - mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, answer.id ?:"")) + mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, answer.id ?:"", answer.bbs.id)) } else -> { NewLogUtils.logForumSearchResultClick("", answer.bbs.id, bbsType, answer.id ?: "", "提问帖", answer.user.id ?: "", position + 1) diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchDefaultFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchDefaultFragment.kt index c0bf8fc80a..abec2f6861 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchDefaultFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchDefaultFragment.kt @@ -1,18 +1,51 @@ package com.gh.gamecenter.forum.search +import android.os.Bundle import android.view.View import androidx.constraintlayout.widget.ConstraintLayout +import androidx.recyclerview.widget.GridLayoutManager import com.gh.common.util.DialogUtils import com.gh.common.util.dip2px +import com.gh.common.util.viewModelProvider import com.gh.gamecenter.databinding.FragmentSearchDefaultBinding import com.gh.gamecenter.eventbus.EBSearch +import com.gh.gamecenter.forum.detail.ForumDetailActivity import com.gh.gamecenter.search.SearchDefaultFragment +import com.gh.gamecenter.search.SearchDefaultHotAdapter import com.lightgame.utils.Util_System_Keyboard import org.greenrobot.eventbus.EventBus class ForumOrUserSearchDefaultFragment : SearchDefaultFragment() { private lateinit var mSearchDao: ForumSearchDao + private lateinit var mViewModel: ForumOrUserSearchDefaultViewModel + private var mAdapter: SearchDefaultHotAdapter? = null + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mViewModel = viewModelProvider() + mViewModel.hotSearchLiveData.observe(viewLifecycleOwner) { + mHotSearchList = it + initHotSearch() + } + } + + private fun initHotSearch() { + mBinding.isExistHotSearch = mHotSearchList?.isNotEmpty() + mBinding.hotList.run { + layoutManager = GridLayoutManager(context, 2) + adapter = SearchDefaultHotAdapter(context, mHotSearchList, callBack = { + requireActivity().startActivity( + ForumDetailActivity.getIntent( + requireContext(), + it.id, + "搜索论坛-热门搜索" + ) + ) + Util_System_Keyboard.hideSoftKeyboardByIBinder(context, windowToken) + }).apply { mAdapter = this } + } + } override fun initDao() { mSearchDao = ForumSearchDao() @@ -23,20 +56,20 @@ class ForumOrUserSearchDefaultFragment : SearchDefaultFragment() { mBinding = FragmentSearchDefaultBinding.bind(mCachedView) mBinding.hotTagTitle.visibility = View.GONE mBinding.hotTagFlexContainer.visibility = View.GONE - mBinding.hotTitle.visibility = View.GONE - mBinding.hotList.visibility = View.GONE + mBinding.hotTitle.text = "热门论坛" val params = mBinding.historyTitle.layoutParams as ConstraintLayout.LayoutParams params.topMargin = 0.5f.dip2px() mBinding.historyTitle.layoutParams = params - - mBinding.isExistHistory = mHistoryList?.isNotEmpty() mBinding.historyFlexContainer.setLimitHeight(mFlexMaxHeight) createFlexContent(mBinding.historyFlex, mHistoryList, clickListener = { val key = mHistoryList!![it] mSearchDao.add(key) EventBus.getDefault().post(EBSearch("history", key)) - Util_System_Keyboard.hideSoftKeyboardByIBinder(context, mBinding.historyFlex.windowToken) + Util_System_Keyboard.hideSoftKeyboardByIBinder( + context, + mBinding.historyFlex.windowToken + ) }) mBinding.historyClear.setOnClickListener { diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchDefaultViewModel.kt b/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchDefaultViewModel.kt new file mode 100644 index 0000000000..7cf853b1b0 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/forum/search/ForumOrUserSearchDefaultViewModel.kt @@ -0,0 +1,31 @@ +package com.gh.gamecenter.forum.search + +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData +import com.gh.common.util.observableToMain +import com.gh.gamecenter.entity.SettingsEntity +import com.gh.gamecenter.retrofit.Response +import com.gh.gamecenter.retrofit.RetrofitManager + +class ForumOrUserSearchDefaultViewModel(application: Application) : AndroidViewModel(application) { + val hotSearchLiveData = MutableLiveData>() + + init { + getHotSearch() + } + + private fun getHotSearch() { + RetrofitManager.getInstance(getApplication()).api + .hotSearches + .compose(observableToMain()) + .subscribe(object : Response>() { + override fun onResponse(response: List?) { + super.onResponse(response) + if (!response.isNullOrEmpty()) { + hotSearchLiveData.postValue(response) + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/UserSearchListViewModel.kt b/app/src/main/java/com/gh/gamecenter/forum/search/UserSearchListViewModel.kt index 0585b50a74..2e15dc5606 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/search/UserSearchListViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/search/UserSearchListViewModel.kt @@ -57,6 +57,7 @@ class UserSearchListViewModel(application: Application) : ListViewModel() + private var mIsBannerShow = false + private var mHomeTab: SubjectRecommendEntity? = null + private var mHomeTabPosition = -1 + private var mOffsetRatio = 0f + private var mOffsetCritical = 0.7f + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -69,19 +76,26 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() { override fun onFragmentFirstVisible() { mViewModel = viewModelProviderFromParent() - mSearchToolbarFragment = childFragmentManager.findFragmentById(R.id.wrapper_toolbar) as SearchToolbarFragment? + mSearchToolbarFragment = + childFragmentManager.findFragmentById(R.id.wrapper_toolbar) as SearchToolbarFragment? ?: SearchToolbarFragment() setSearchHints() - mBinding?.wrapperLl?.setPadding(0, 0, 0, requireContext().resources.getDimension(R.dimen.main_bottom_tab_height).toInt()) + mBinding?.wrapperLl?.setPadding( + 0, + 0, + 0, + requireContext().resources.getDimension(R.dimen.main_bottom_tab_height).toInt() + ) mBinding?.appbar?.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset -> mViewModel?.appBarOffset = abs(verticalOffset) }) - mSearchToolbarFragment?.arguments = Bundle().apply { putString(EntranceUtils.KEY_LOCATION, "首页") } + mSearchToolbarFragment?.arguments = + Bundle().apply { putString(EntranceUtils.KEY_LOCATION, "首页") } childFragmentManager.beginTransaction() - .replace(R.id.wrapper_toolbar, mSearchToolbarFragment!!) - .commitAllowingStateLoss() + .replace(R.id.wrapper_toolbar, mSearchToolbarFragment!!) + .commitAllowingStateLoss() updateAppBarStyle(Color.WHITE, false) @@ -89,6 +103,8 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() { if (mDefaultSelectedTab == -1) { mDefaultSelectedTab = mViewModel?.defaultTabPosition ?: 0 } + mHomeTab = it?.find { tab -> tab.type == "home" } + mHomeTabPosition = it.indexOf(mHomeTab) initViewPager(it) // 当 tab 为一个的时候隐藏顶部 tab 栏,停用 nestedScroll @@ -124,7 +140,8 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() { super.onSaveInstanceState(outState) } - override fun getInflatedLayout() = FragmentMainHomeWrapperBinding.inflate(layoutInflater).apply { mBinding = this }.root + override fun getInflatedLayout() = + FragmentMainHomeWrapperBinding.inflate(layoutInflater).apply { mBinding = this }.root private fun initViewPager(tabList: ArrayList) { val fragmentList = generateFragments(tabList).apply { mFragmentList = this } @@ -138,11 +155,13 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() { if (mCurrentAppBarColor == Color.WHITE) return - var offsetRatio: Float = abs(recyclerView.computeVerticalScrollOffset()).toFloat() / COLOR_CHANGE_DISTANCE + var offsetRatio: Float = + abs(recyclerView.computeVerticalScrollOffset()).toFloat() / COLOR_CHANGE_DISTANCE if (offsetRatio > 1) offsetRatio = 1F - val colorInBetween = ColorUtils.blendARGB(mCurrentAppBarColor, Color.WHITE, offsetRatio) + val colorInBetween = + ColorUtils.blendARGB(mCurrentAppBarColor, Color.WHITE, offsetRatio) Utils.log("offset", offsetRatio) @@ -153,79 +172,117 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() { mBinding?.run { viewPager.offscreenPageLimit = fragmentList.size viewPager.doOnScroll( - onPageSelected = { position -> - notifyChildFragmentLifecycle(position) - updateTabTextStyle(position, 0F) - mViewModel?.forumTabPair?.let { - if (it.first == position) { - DirectUtils.directForumDetail(requireContext(), it.second, "首页") - viewPager.post { viewPager.currentItem = position - 1 } - } + onPageSelected = { position -> + notifyChildFragmentLifecycle(position) + updateTabTextStyle(position, 0F) + mViewModel?.forumTabPair?.let { + if (it.first == position) { + DirectUtils.directForumDetail(requireContext(), it.second, "首页") + viewPager.post { viewPager.currentItem = position - 1 } } - mViewModel?.tabs?.value?.run { - this.safelyGetInRelease(position).let { - LogUtils.logHomeTopTabClick(it?.name, it?.type, it?.text, position) - } + } + mViewModel?.tabs?.value?.run { + this.safelyGetInRelease(position).let { + LogUtils.logHomeTopTabClick(it?.name, it?.type, it?.text, position) } + } // viewPager.getChildAt(position)?.findViewById(R.id.list_rv)?.let { // it.removeOnScrollListener(onScrollChangeListener) // it.addOnScrollListener(onScrollChangeListener) // } - }, - onPageScrolled = { position, positionOffset, _ -> - if (position + 1 != mTabTitleList.size) { - val currentAppBarColor = tabList.safelyGetInRelease(position)?.primaryColor ?: Color.WHITE - val incomingAppBarColor = tabList.safelyGetInRelease(position + 1)?.primaryColor ?: Color.WHITE + }, + onPageScrolled = { position, positionOffset, _ -> + if (position + 1 != mTabTitleList.size) { + val currentAppBarColor = + tabList.safelyGetInRelease(position)?.primaryColor ?: Color.WHITE + val incomingAppBarColor = + tabList.safelyGetInRelease(position + 1)?.primaryColor ?: Color.WHITE - val proximatelySelectedPosition = if (positionOffset < 0.5) position else position + 1 + val proximatelySelectedPosition = + if (positionOffset < 0.5) position else position + 1 - val appBarColorInBetween = if (currentAppBarColor == incomingAppBarColor) { - currentAppBarColor - } else { - ColorUtils.blendARGB(currentAppBarColor, incomingAppBarColor, positionOffset) - } - - // 颜色显示是否变更 - val isContentStyleChanged = tabList.safelyGetInRelease(proximatelySelectedPosition)?.useLightStyle != mIsDisplayingLightContent - mIsDisplayingLightContent = tabList.safelyGetInRelease(proximatelySelectedPosition)?.useLightStyle ?: false - - mTabSelectedColor = if (mIsDisplayingLightContent) TAB_DEFAULT_COLOR_LIGHT else TAB_SELECTED_COLOR - mTabDefaultColor = if (mIsDisplayingLightContent) TAB_DEFAULT_COLOR_LIGHT else TAB_DEFAULT_COLOR - - if (isContentStyleChanged) { - if (mIsDisplayingLightContent) { - indicatorView.updateIndicatorDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_home_tab_indicator_white)) - } else { - indicatorView.updateIndicatorDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_home_tab_indicator_colorful)) - } - DisplayUtils.setLightStatusBar(requireActivity(), !mIsDisplayingLightContent) - } - - mTabTitleList[position].run { - textSize = (DEFAULT_TAB_TEXT_SIZE + ((1 - positionOffset) * 4)).roundTo(1) - setTextColor(ColorUtils.blendARGB(mTabDefaultColor, mTabSelectedColor, 1 - positionOffset)) - } - mTabTitleList[position + 1].run { - textSize = (DEFAULT_TAB_TEXT_SIZE + ((positionOffset) * 4)).roundTo(1) - setTextColor(ColorUtils.blendARGB(mTabDefaultColor, mTabSelectedColor, positionOffset)) - } - - // 多 tab 切换的时候可能会出现某些 tab 的文字没有回归到原始大小的问题的问题 (positionOffset 不保证连续) - for ((index, tabTv) in mTabTitleList.withIndex()) { - if (abs(index - position) >= 2) { - if (tabTv.textSize != DEFAULT_TAB_TEXT_SIZE) { - tabTv.textSize = DEFAULT_TAB_TEXT_SIZE - tabTv.setTextColor(mTabDefaultColor) - } - } - } - - mCurrentAppBarColor = appBarColorInBetween - updateAppBarStyle(appBarColorInBetween, mIsDisplayingLightContent) + val appBarColorInBetween = if (currentAppBarColor == incomingAppBarColor) { + currentAppBarColor + } else { + ColorUtils.blendARGB( + currentAppBarColor, + incomingAppBarColor, + positionOffset + ) } - updateTabTextStyle(position, positionOffset) + // 颜色显示是否变更 + val isContentStyleChanged = + tabList.safelyGetInRelease(proximatelySelectedPosition)?.useLightStyle != mIsDisplayingLightContent + mIsDisplayingLightContent = + tabList.safelyGetInRelease(proximatelySelectedPosition)?.useLightStyle + ?: false + + mTabSelectedColor = + if (mIsDisplayingLightContent) TAB_DEFAULT_COLOR_LIGHT else TAB_SELECTED_COLOR + mTabDefaultColor = + if (mIsDisplayingLightContent) TAB_DEFAULT_COLOR_LIGHT else TAB_DEFAULT_COLOR + + if (isContentStyleChanged) { + if (mIsDisplayingLightContent) { + indicatorView.updateIndicatorDrawable( + ContextCompat.getDrawable( + requireContext(), + R.drawable.ic_home_tab_indicator_white + ) + ) + } else { + indicatorView.updateIndicatorDrawable( + ContextCompat.getDrawable( + requireContext(), + R.drawable.ic_home_tab_indicator_colorful + ) + ) + } + DisplayUtils.setLightStatusBar( + requireActivity(), + !mIsDisplayingLightContent + ) + } + + mTabTitleList[position].run { + textSize = + (DEFAULT_TAB_TEXT_SIZE + ((1 - positionOffset) * 4)).roundTo(1) + setTextColor( + ColorUtils.blendARGB( + mTabDefaultColor, + mTabSelectedColor, + 1 - positionOffset + ) + ) + } + mTabTitleList[position + 1].run { + textSize = (DEFAULT_TAB_TEXT_SIZE + ((positionOffset) * 4)).roundTo(1) + setTextColor( + ColorUtils.blendARGB( + mTabDefaultColor, + mTabSelectedColor, + positionOffset + ) + ) + } + + // 多 tab 切换的时候可能会出现某些 tab 的文字没有回归到原始大小的问题的问题 (positionOffset 不保证连续) + for ((index, tabTv) in mTabTitleList.withIndex()) { + if (abs(index - position) >= 2) { + if (tabTv.textSize != DEFAULT_TAB_TEXT_SIZE) { + tabTv.textSize = DEFAULT_TAB_TEXT_SIZE + tabTv.setTextColor(mTabDefaultColor) + } + } + } + + mCurrentAppBarColor = appBarColorInBetween + updateAppBarStyle(appBarColorInBetween, mIsDisplayingLightContent) } + + updateTabTextStyle(position, positionOffset) + } ) // 设置默认 position 避免 position 为 0 的 fragment 被先加载显示再跳转至具体页面 @@ -233,6 +290,7 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() { val field = ViewPager::class.java.getDeclaredField("mRestoredCurItem") field.isAccessible = true field.set(viewPager, mDefaultSelectedTab) + mLastSelectedPosition = mDefaultSelectedTab } viewPager.adapter = FragmentAdapter(childFragmentManager, fragmentList, tabTitleList) tabLayout.setupWithViewPager(mBinding?.viewPager) @@ -250,12 +308,68 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() { } } + fun onScrollChanged(totalHeight: Int, offset: Int) { + mOffsetRatio = offset / totalHeight.toFloat() + if (mIsBannerShow && offset >= totalHeight) { + mIsBannerShow = false + mHomeTab?.primaryColor = Color.WHITE + mHomeTab?.useLightStyle = false + mIsDisplayingLightContent = false + updateAppBarColorWhenScrollChanged(Color.WHITE) + DisplayUtils.setLightStatusBar(requireActivity(), !mIsDisplayingLightContent) + mTabSelectedColor = TAB_SELECTED_COLOR + mTabDefaultColor = TAB_DEFAULT_COLOR + mBinding?.indicatorView?.updateIndicatorDrawable(R.drawable.ic_home_tab_indicator_colorful.toDrawable()) + updateTabTextStyle(mLastSelectedPosition, 0f) + } else if (offset < totalHeight) { + mIsBannerShow = true + val colorInBetween = + ColorUtils.blendARGB(mCurrentSelectBannerColor, Color.WHITE, mOffsetRatio) + mHomeTab?.primaryColor = colorInBetween + mHomeTab?.useLightStyle = mOffsetRatio < mOffsetCritical + mIsDisplayingLightContent = mOffsetRatio < mOffsetCritical + updateAppBarColorWhenScrollChanged(colorInBetween) + DisplayUtils.setLightStatusBar(requireActivity(), !mIsDisplayingLightContent) + mTabSelectedColor = + if (mOffsetRatio < mOffsetCritical) TAB_DEFAULT_COLOR_LIGHT else TAB_SELECTED_COLOR + mTabDefaultColor = + if (mOffsetRatio < mOffsetCritical) TAB_DEFAULT_COLOR_LIGHT else TAB_DEFAULT_COLOR + mBinding?.indicatorView?.updateIndicatorDrawable( + if (mOffsetRatio < mOffsetCritical) R.drawable.ic_home_tab_indicator_white.toDrawable() else + R.drawable.ic_home_tab_indicator_colorful.toDrawable() + ) + updateTabTextStyle(mLastSelectedPosition, 0f) + } + } + + private fun updateAppBarColorWhenScrollChanged(color: Int) { + if (color != Color.WHITE && mOffsetRatio >= 1f) { + mCurrentSelectBannerColor = color + mHomeTab?.primaryColor = mCurrentSelectBannerColor + } + updateAppBarStyle(color, color != Color.WHITE) + } + + fun changeAppBarColor(color: Int) { + mCurrentSelectBannerColor = color + if (mIsBannerShow) { + val colorInBetween = + ColorUtils.blendARGB(color, Color.WHITE, mOffsetRatio) + mHomeTab?.primaryColor = colorInBetween + if (mBinding?.viewPager?.currentItem == mHomeTabPosition) { + updateAppBarStyle(colorInBetween, colorInBetween != Color.WHITE) + } + } + } + private fun notifyChildFragmentLifecycle(currentSelectedPosition: Int) { tryCatchInRelease { // 补充 Viewpager Fragment 的生命周期, 先调用旧选中 fragment 的 onPause 再当前的 onResume // 避免部分被内嵌的 Fragment 不能正常运作 if (mFragmentList.size > mLastSelectedPosition) { val fragment: Fragment = mFragmentList[mLastSelectedPosition] + if (!fragment.isAdded) return@tryCatchInRelease + fragment.onPause() val childFragmentManager = fragment.childFragmentManager val fragments = childFragmentManager.fragments @@ -265,6 +379,8 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() { } if (mFragmentList.size > currentSelectedPosition) { val fragment: Fragment = mFragmentList[currentSelectedPosition] + if (!fragment.isAdded) return@tryCatchInRelease + fragment.onResume() val childFragmentManager = fragment.childFragmentManager val fragments = childFragmentManager.fragments @@ -310,7 +426,10 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() { }) "column" -> SubjectFragment().with(Bundle().apply { putString(EntranceUtils.KEY_ENTRANCE, "首页") - putParcelable(EntranceUtils.KEY_SUBJECT_DATA, SubjectData(tab.link, tab.text, false)) + putParcelable( + EntranceUtils.KEY_SUBJECT_DATA, + SubjectData(tab.link, tab.text, false) + ) }) "web" -> WebFragment().with(Bundle().apply { putString(EntranceUtils.KEY_URL, tab.link) @@ -322,7 +441,10 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() { } fragment.arguments?.putInt(EntranceUtils.KEY_TAB_COUNT, tabList.size) fragment.arguments?.putBoolean(EntranceUtils.KEY_IS_HOME, true) - fragment.arguments?.putParcelable(EntranceUtils.KEY_EXPOSURE_SOURCE, ExposureSource("首页顶部Tab栏", tab.name ?: "")) + fragment.arguments?.putParcelable( + EntranceUtils.KEY_EXPOSURE_SOURCE, + ExposureSource("首页顶部Tab栏", tab.name ?: "") + ) fragmentList.add(fragment) } return fragmentList diff --git a/app/src/main/java/com/gh/gamecenter/fragment/LoginFragment.java b/app/src/main/java/com/gh/gamecenter/fragment/LoginFragment.java index f619a39187..63bda256b7 100644 --- a/app/src/main/java/com/gh/gamecenter/fragment/LoginFragment.java +++ b/app/src/main/java/com/gh/gamecenter/fragment/LoginFragment.java @@ -302,7 +302,8 @@ LoginFragment extends NormalFragment implements LoginUtils.onCaptchaCallBackList DialogUtils.showQuickLoginPermissionDialog( requireContext(), () -> PermissionHelper.checkReadPhoneStatePermissionBeforeAction(requireContext(), this::startQuickLogin), - () -> {} + () -> { + } ); } } @@ -337,7 +338,7 @@ LoginFragment extends NormalFragment implements LoginUtils.onCaptchaCallBackList toast("手机号码不能为空"); return; } else if (!isAgreePolicy()) { - return; + return; } else if (TextUtils.isEmpty(code)) { toast("验证码不能为空"); return; @@ -417,8 +418,12 @@ LoginFragment extends NormalFragment implements LoginUtils.onCaptchaCallBackList } // 第三方登录方式登录后跳转绑定手机页面(https://gitlab.ghzs.com/pm/halo-app-issues/-/issues/1206) - if (UserManager.getInstance().getUserInfoEntity() != null - && TextUtils.isEmpty(UserManager.getInstance().getUserInfoEntity().getLoginMobile())) { + boolean isThirdPartyLogin = LoginTag.qq.name().equals(loginType) + || LoginTag.wechat.name().equals(loginType) + || LoginTag.weibo.name().equals(loginType) + || LoginTag.douyin.name().equals(loginType); + if (isThirdPartyLogin + && TextUtils.isEmpty(response.getData().getLoginMobile())) { startActivity(BindPhoneActivity.getLoginSuccessIntent(requireContext())); } } diff --git a/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java b/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java index 02aa569cd7..f3a5231989 100644 --- a/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java +++ b/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java @@ -35,6 +35,7 @@ import com.gh.common.util.DataUtils; import com.gh.common.util.DisplayUtils; import com.gh.common.util.EntranceUtils; import com.gh.common.util.ExtensionsKt; +import com.gh.common.util.FloatingBackViewManager; import com.gh.common.util.HomeBottomBarHelper; import com.gh.common.util.ImageUtils; import com.gh.common.util.IntegralLogHelper; @@ -51,6 +52,7 @@ import com.gh.gamecenter.forum.home.CommunityHomeFragment; import com.gh.gamecenter.game.GameFragment; import com.gh.gamecenter.message.MessageUnreadRepository; import com.gh.gamecenter.message.MessageUnreadViewModel; +import com.gh.gamecenter.personal.NewPersonalFragment; import com.gh.gamecenter.personal.PersonalFragment; import com.gh.gamecenter.video.detail.HomeVideoFragment; import com.halo.assistant.HaloApp; @@ -490,6 +492,11 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem DataUtils.onMtaEvent(getContext(), "顶级页面", "BottomBar", tabText); TrackerLogger.logHomeTabSelected(index, tabText); + if (index != INDEX_BBS) { + FloatingBackViewManager.disableBackView(); + FloatingBackViewManager.dismissBackView(requireActivity()); + } + SubjectRecommendEntity navBarEntity = mViewModel.getNavBar().getValue(); if (navBarEntity != null) { if (index == INDEX_GAME) { diff --git a/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperViewModel.kt b/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperViewModel.kt index 6ba8364183..4146dc225f 100644 --- a/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperViewModel.kt @@ -8,6 +8,7 @@ import androidx.lifecycle.MutableLiveData import com.gh.common.constant.Constants import com.gh.common.util.CheckLoginUtils import com.gh.common.util.HomeBottomBarHelper +import com.gh.common.util.PackageUtils import com.gh.gamecenter.BuildConfig import com.gh.gamecenter.entity.ConcernEntity import com.gh.gamecenter.entity.SimpleGameEntity @@ -44,23 +45,23 @@ class MainWrapperViewModel(application: Application) : AndroidViewModel(applicat @SuppressLint("CheckResult") private fun getHomeNavBar() { mSensitiveApi.getHomeNavBar(HaloApp.getInstance().channel, BuildConfig.VERSION_NAME) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : BiResponse() { - override fun onSuccess(data: SubjectRecommendEntity) { - HomeBottomBarHelper.updateDefaultGameBarData(data) - navBar.postValue(data) - } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: SubjectRecommendEntity) { + HomeBottomBarHelper.updateDefaultGameBarData(data) + navBar.postValue(data) + } - override fun onFailure(exception: Exception) { - if (exception is HttpException && exception.code() == 404) { - navBar.postValue(null) - HomeBottomBarHelper.updateDefaultGameBarData(SubjectRecommendEntity()) - } else { - navBar.postValue(HomeBottomBarHelper.getDefaultGameBarData()) - } + override fun onFailure(exception: Exception) { + if (exception is HttpException && exception.code() == 404) { + navBar.postValue(null) + HomeBottomBarHelper.updateDefaultGameBarData(SubjectRecommendEntity()) + } else { + navBar.postValue(HomeBottomBarHelper.getDefaultGameBarData()) } - }) + } + }) } fun getDiscoveryData(immediately: Boolean) { @@ -69,14 +70,14 @@ class MainWrapperViewModel(application: Application) : AndroidViewModel(applicat if (currentTimeMills - mLastRequestDiscoveryTime > mIntervalRequestDiscoveryData || immediately) { mLastRequestDiscoveryTime = currentTimeMills mApi - .getZiXunConcern(UserManager.getInstance().userId, 1) - .subscribeOn(Schedulers.io()) - .subscribe(object : Response>() { - override fun onResponse(response: List?) { - super.onResponse(response) - concernData.postValue(response) - } - }) + .getZiXunConcern(UserManager.getInstance().userId, 1) + .subscribeOn(Schedulers.io()) + .subscribe(object : Response>() { + override fun onResponse(response: List?) { + super.onResponse(response) + concernData.postValue(response) + } + }) } } } @@ -86,22 +87,38 @@ class MainWrapperViewModel(application: Application) : AndroidViewModel(applicat */ @SuppressLint("CheckResult") fun requestOpeningData() { - val lastId = PreferenceManager.getDefaultSharedPreferences(getApplication()).getString(Constants.SP_LAST_OPENING_ID, "") - val lastTime = PreferenceManager.getDefaultSharedPreferences(getApplication()).getLong(Constants.SP_LAST_OPENING_TIME, 0) + val lastId = PreferenceManager.getDefaultSharedPreferences(getApplication()) + .getString(Constants.SP_LAST_OPENING_ID, "") + val lastTime = PreferenceManager.getDefaultSharedPreferences(getApplication()) + .getLong(Constants.SP_LAST_OPENING_TIME, 0) val openType = if (HaloApp.getInstance().isNewForThisVersion) "first" else "not_first_time" mSensitiveApi.getOpeningDialog(HaloApp.getInstance().channel, lastId, lastTime, openType) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : BiResponse() { - override fun onSuccess(data: WelcomeDialogEntity) { + .subscribeOn(Schedulers.io()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: WelcomeDialogEntity) { + // 类型为游戏时判断是否本地已安装该游戏,已安装不弹弹窗 + if (data.type == "game") { + if (data.packages == null) { + openingDialog.postValue(data) + } else { + for (packageName in data.packages!!) { + if (PackageUtils.isInstalled(getApplication(), packageName)) { + openingDialog.postValue(null) + return + } + } + openingDialog.postValue(data) + } + } else { openingDialog.postValue(data) } + } - override fun onFailure(exception: Exception) { - openingDialog.postValue(null) - } - }) + override fun onFailure(exception: Exception) { + openingDialog.postValue(null) + } + }) } @@ -109,17 +126,17 @@ class MainWrapperViewModel(application: Application) : AndroidViewModel(applicat fun requestReserveDialog() { if (CheckLoginUtils.isLogin()) { mApi.getReserveDialog(UserManager.getInstance().userId) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : BiResponse>() { - override fun onSuccess(data: List) { - reserveDialog.postValue(data) - } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse>() { + override fun onSuccess(data: List) { + reserveDialog.postValue(data) + } - override fun onFailure(exception: Exception) { - reserveDialog.postValue(null) - } - }) + override fun onFailure(exception: Exception) { + reserveDialog.postValue(null) + } + }) } } diff --git a/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java b/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java index 5dc569109f..3a2d973019 100644 --- a/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java +++ b/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java @@ -297,7 +297,7 @@ public class SearchToolbarFragment extends BaseLazyFragment implements View.OnCl IntegralLogHelper.INSTANCE.log("click_sign", mLocation); } - startActivity(EnergyCenterActivity.Companion.getIntent(requireContext(), true)); + startActivity(EnergyCenterActivity.Companion.getIntent(requireContext())); break; } } diff --git a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt index 7d9a5b2401..334f883f09 100644 --- a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt @@ -56,6 +56,11 @@ class GameHorizontalSlideAdapter(context: Context, holder.binding.game = gameEntity holder.binding.simpleGameContainer.game = gameEntity holder.binding.subject = mSubjectEntity + holder.binding.secondRemark.text = when { + gameEntity.assignRemark.secondLine.isNotEmpty() -> gameEntity.assignRemark.secondLine + "custom" == gameEntity.test?.gameTag && gameEntity.test?.text?.isNotEmpty() == true -> gameEntity.test?.text + else -> gameEntity.test?.type ?: "" + } holder.setRemarkView(mSubjectEntity, gameEntity) holder.itemView.setOnClickListener { val exposureEvent = exposureEventList?.get(position) diff --git a/app/src/main/java/com/gh/gamecenter/game/upload/GameUploadFragment.kt b/app/src/main/java/com/gh/gamecenter/game/upload/GameUploadFragment.kt index 134e36cfb7..82d60ece1e 100644 --- a/app/src/main/java/com/gh/gamecenter/game/upload/GameUploadFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/game/upload/GameUploadFragment.kt @@ -30,7 +30,6 @@ import com.gh.gamecenter.suggest.SuggestSelectGameAdapter import com.halo.assistant.HaloApp import com.lightgame.utils.Util_System_Keyboard import com.lightgame.utils.Utils -import com.zhihu.matisse.internal.utils.PathUtils import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.fragment_game_upload.* import okhttp3.MediaType @@ -456,7 +455,7 @@ class GameUploadFragment : NormalFragment() { } else if (requestCode == CHOOSE_LOCAL_APK) { val packageName = data.getStringExtra(EntranceUtils.KEY_PACKAGENAME) ?: "" val gamePath = data.getStringExtra(EntranceUtils.KEY_PATH) ?: "" - val version = PackageUtils.getVersionByPackage(packageName) + val version = PackageUtils.getVersionNameByPackageName(packageName) val length = File(gamePath).length() if (length > 5 * 1024 * 1024 * 1024) { ToastUtils.showToast(getString(R.string.apk_max_size_hint, 5)) diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt index 010955bf3f..46c05296a1 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt @@ -25,6 +25,7 @@ import com.ethanhua.skeleton.Skeleton import com.ethanhua.skeleton.ViewSkeletonScreen import com.gh.base.adapter.FragmentAdapter import com.gh.base.fragment.BaseFragment_TabLayout +import com.gh.common.constant.Config import com.gh.common.constant.Constants import com.gh.common.databind.BindingAdapters import com.gh.common.dialog.ReserveDialogFragment @@ -41,10 +42,7 @@ import com.gh.common.xapk.XapkInstaller import com.gh.common.xapk.XapkUnzipStatus import com.gh.download.DownloadManager import com.gh.download.server.BrowserInstallHelper -import com.gh.gamecenter.DownloadManagerActivity -import com.gh.gamecenter.R -import com.gh.gamecenter.SearchActivity -import com.gh.gamecenter.ShellActivity +import com.gh.gamecenter.* import com.gh.gamecenter.adapter.viewholder.DetailViewHolder import com.gh.gamecenter.entity.* import com.gh.gamecenter.eventbus.* @@ -78,6 +76,8 @@ import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack import com.shuyu.gsyvideoplayer.utils.OrientationUtils import com.shuyu.gsyvideoplayer.video.base.GSYVideoView import io.reactivex.disposables.Disposable +import kotlinx.android.synthetic.main.dialog_download.view.* +import kotlinx.android.synthetic.main.download_dialog_installed_item.* import kotlinx.android.synthetic.main.piece_game_detail_video.* import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe @@ -171,11 +171,20 @@ class GameDetailFragment : NormalFragment() { @BindView(R.id.gameBigEvent) lateinit var gameBigEvent: TextView - @BindView(R.id.concern_btn) - lateinit var mConcernBtn: TextView + @BindView(R.id.recommendAgeIv) + lateinit var recommendAgeIv: ImageView - @BindView(R.id.reserve_btn) - lateinit var mReserveBtn: TextView + @BindView(R.id.tv_concern) + lateinit var mConcernTv: TextView + + @BindView(R.id.iv_concern) + lateinit var mConcernIv: ImageView + + @BindView(R.id.tv_reserve) + lateinit var mReserveTv: TextView + + @BindView(R.id.iv_reserve) + lateinit var mReserveIv: ImageView @BindView(R.id.reserve_guide_container) lateinit var mReserveGuideContainer: View @@ -183,6 +192,12 @@ class GameDetailFragment : NormalFragment() { @BindView(R.id.closeIv) lateinit var mReserveGuideClose: View + @BindView(R.id.tv_switch) + lateinit var mSwitchTv: TextView + + @BindView(R.id.iv_switch) + lateinit var mSwitchIv: ImageView + @BindView(R.id.browser_install_hint_container) lateinit var mBrowserInstallContainer: View @@ -192,6 +207,15 @@ class GameDetailFragment : NormalFragment() { @BindView(R.id.browser_install_hint_tv) lateinit var mBrowserInstallHintTv: TextView + @BindView(R.id.install_hint_container) + lateinit var mInstallContainer: View + + @BindView(R.id.install_hint_close_iv) + lateinit var mInstallCloseIv: View + + @BindView(R.id.install_hint_tv) + lateinit var mInstallHintTv: TextView + @BindView(R.id.recommendView) lateinit var mRecommendView: View @@ -245,10 +269,18 @@ class GameDetailFragment : NormalFragment() { private val dataWatcher = object : DataWatcher() { override fun onDataChanged(downloadEntity: DownloadEntity) { + if (downloadEntity.gameId == mViewModel.gameId) { + if (downloadEntity.status == DownloadStatus.add || downloadEntity.status == DownloadStatus.done || downloadEntity.status == DownloadStatus.downloading || downloadEntity.status == DownloadStatus.pause || downloadEntity.status == DownloadStatus.redirected) { + showInstallHint() + SPUtils.setBoolean(Constants.SP_SHOULD_SHOW_GAME_DETAIL_INSTALL_GUIDE, true) + } + } if (mGameEntity != null && mGameEntity!!.getApk().size == 1) { val url = mGameEntity!!.getApk()[0].url if (downloadEntity.url == url) { - if ("pause" != DownloadManager.getInstance(context).getStatus(downloadEntity.url)?.status) { + if ("pause" != DownloadManager.getInstance(context) + .getStatus(downloadEntity.url)?.status + ) { mDownloadEntity = downloadEntity DetailDownloadUtils.detailInvalidate(detailViewHolder) } @@ -257,26 +289,43 @@ class GameDetailFragment : NormalFragment() { DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity) } } - val meta = downloadEntity.getMetaExtra(PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND) + val meta = + downloadEntity.getMetaExtra(PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND) if (downloadEntity.status == DownloadStatus.add) { if (downloadEntity.gameId == mViewModel.game?.id) { mRecommendView.postDelayed({ showRecommendView() }, 500) } if (meta.isNotEmpty() && mRecommendPopupEntity != null) { - LogUtils.uploadRecommendPopup("recommend_pop_download", mRecommendPopupEntity?.id, mViewModel.game?.id - ?: "", mViewModel.game?.name - ?: "", mRecommendPopupEntity?.popupDetail?.link?.type, - mRecommendPopupEntity?.popupDetail?.link?.text, downloadEntity.gameId, downloadEntity.name) + LogUtils.uploadRecommendPopup( + "recommend_pop_download", + mRecommendPopupEntity?.id, + mViewModel.game?.id + ?: "", + mViewModel.game?.name + ?: "", + mRecommendPopupEntity?.popupDetail?.link?.type, + mRecommendPopupEntity?.popupDetail?.link?.text, + downloadEntity.gameId, + downloadEntity.name + ) } } else if (downloadEntity.status == DownloadStatus.done) { if (downloadEntity.gameId == mViewModel.game?.id) { hideRecommendView() } if (meta.isNotEmpty() && mRecommendPopupEntity != null) { - LogUtils.uploadRecommendPopup("recommend_pop_download_complete", mRecommendPopupEntity?.id, mViewModel.game?.id - ?: "", mViewModel.game?.name - ?: "", mRecommendPopupEntity?.popupDetail?.link?.type, - mRecommendPopupEntity?.popupDetail?.link?.text, downloadEntity.gameId, downloadEntity.name) + LogUtils.uploadRecommendPopup( + "recommend_pop_download_complete", + mRecommendPopupEntity?.id, + mViewModel.game?.id + ?: "", + mViewModel.game?.name + ?: "", + mRecommendPopupEntity?.popupDetail?.link?.type, + mRecommendPopupEntity?.popupDetail?.link?.text, + downloadEntity.gameId, + downloadEntity.name + ) } } } @@ -288,14 +337,15 @@ class GameDetailFragment : NormalFragment() { private val detailViewHolder: DetailViewHolder get() = DetailViewHolder( - mCachedView, - mGameEntity, - mDownloadEntity, - false, - mEntrance, - "游戏详情", - mGameEntity!!.name, - mTraceEvent) + mCachedView, + mGameEntity, + mDownloadEntity, + false, + mEntrance, + "游戏详情", + mGameEntity!!.name, + mTraceEvent + ) override fun getLayoutId(): Int { return R.layout.fragment_gamedetail @@ -315,8 +365,12 @@ class GameDetailFragment : NormalFragment() { when (it.itemId) { R.id.menu_more -> { if (mGameEntity != null && mNewGameDetailEntity != null) { - GameDetailMoreDialog.showMoreDialog(requireActivity() as AppCompatActivity, mGameEntity, mNewGameDetailEntity?.shareCode - ?: "") + GameDetailMoreDialog.showMoreDialog( + requireActivity() as AppCompatActivity, + mGameEntity, + mNewGameDetailEntity?.shareCode + ?: "" + ) MtaHelper.onEvent("游戏详情_新", "更多按钮", mViewModel.game?.name ?: "") } } @@ -335,7 +389,8 @@ class GameDetailFragment : NormalFragment() { mDownloadMenuItem?.actionView?.setOnClickListener { MtaHelper.onEvent("游戏详情_新", "下载管理图标", mViewModel.game?.name ?: "") // MtaHelper.onEvent("下载管理", "下载管理入口", (requireActivity() as BaseActivity).activityNameInChinese) - val intent = DownloadManagerActivity.getDownloadMangerIntent(requireContext(), mEntrance) + val intent = + DownloadManagerActivity.getDownloadMangerIntent(requireContext(), mEntrance) startActivity(intent) } @@ -365,11 +420,15 @@ class GameDetailFragment : NormalFragment() { mDestinationTab = args.getInt(EntranceUtils.KEY_TARGET, -1) mIsOpenPlatformWindow = args.getBoolean(EntranceUtils.KEY_OPEN_PLATFORM_WINDOW) - mSkeleton = Skeleton.bind(mListSkeleton).shimmer(false).load(R.layout.fragment_gamedetail_skeleton).show() + mSkeleton = + Skeleton.bind(mListSkeleton).shimmer(false).load(R.layout.fragment_gamedetail_skeleton) + .show() - val factory = GameDetailViewModel.Factory(HaloApp.getInstance().application, - args.getString(EntranceUtils.KEY_GAMEID), - args.getParcelable(GameEntity.TAG)) + val factory = GameDetailViewModel.Factory( + HaloApp.getInstance().application, + args.getString(EntranceUtils.KEY_GAMEID), + args.getParcelable(GameEntity.TAG) + ) mViewModel = viewModelProviderFromParent(factory) mPackageViewModel = viewModelProvider(PackageViewModel.Factory()) mUserViewModel = viewModelProvider(UserViewModel.Factory(HaloApp.getInstance().application)) @@ -395,7 +454,12 @@ class GameDetailFragment : NormalFragment() { } if (mNewGameDetailEntity?.bbsTab != null && position == tabTitleList.size - 1) { - DirectUtils.directToLinkPage(requireContext(), mNewGameDetailEntity?.bbsTab!!, "游戏详情", "") + DirectUtils.directToLinkPage( + requireContext(), + mNewGameDetailEntity?.bbsTab!!, + "游戏详情", + "" + ) LogUtils.uploadAccessToBbs(mNewGameDetailEntity?.bbsTab?.link, "游戏详情") } else { mCurVpPosition = position @@ -468,12 +532,14 @@ class GameDetailFragment : NormalFragment() { // toolbar 消费 fitsSystemWindows 避免在 collapsingToolbar 下面出现多出来的 padding // [https://stackoverflow.com/questions/48137666/viewgroup-inside-collapsingtoolbarlayout-show-extra-bottom-padding-when-set-fits] ViewCompat.setOnApplyWindowInsetsListener(mAppBarLayout) { _, insets -> - (mToolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = insets.systemWindowInsetTop + (mToolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = + insets.systemWindowInsetTop insets.consumeSystemWindowInsets() } mToolbar.setNavigationOnClickListener { requireActivity().finish() } - mConcernBtn.visibility = View.VISIBLE + mConcernIv.visibility = View.VISIBLE + mConcernTv.visibility = View.VISIBLE } @Subscribe(threadMode = ThreadMode.MAIN) @@ -489,9 +555,11 @@ class GameDetailFragment : NormalFragment() { if (gameResource.status == Status.SUCCESS) { mViewModel.logHistory(gameResource.data!!) mGameEntity = gameResource.data + controlInstallHint() // 添加启动弹窗的相关信息 if (mEntrance.contains(EntranceUtils.ENTRANCE_WELCOME) - && mEntrance.countOccurrences("+") <= 1) { + && mEntrance.countOccurrences("+") <= 1 + ) { mGameEntity?.setWelcomeDialogInfoIfAvailable() } } else if (gameResource.status == Status.ERROR) { @@ -559,7 +627,12 @@ class GameDetailFragment : NormalFragment() { kv["状态"] = R.string.concern DataUtils.onEvent(context, "游戏关注", mGameEntity!!.name, kv) MtaHelper.onEvent("游戏详情_新", "关注", mGameEntity!!.name) - DataCollectionUtils.uploadConcern(context, mGameEntity!!.name, mGameEntity!!.id, "关注") + DataCollectionUtils.uploadConcern( + context, + mGameEntity!!.name, + mGameEntity!!.id, + "关注" + ) // GdtHelper.logAction(ActionType.ADD_TO_WISHLIST, GdtHelper.CONTENT_TYPE, "GAME", GdtHelper.CONTENT_ID, mGameEntity!!.id) updateConcernMenuIcon(isConcerned = true) @@ -573,7 +646,12 @@ class GameDetailFragment : NormalFragment() { kv["状态"] = "取消关注" DataUtils.onEvent(context, "游戏关注", mGameEntity!!.name, kv) - DataCollectionUtils.uploadConcern(context, mGameEntity!!.name, mGameEntity!!.id, "取消关注") + DataCollectionUtils.uploadConcern( + context, + mGameEntity!!.name, + mGameEntity!!.id, + "取消关注" + ) MtaHelper.onEvent("游戏详情_新", "取消关注", mGameEntity!!.name) updateConcernMenuIcon(isConcerned = false) @@ -588,8 +666,10 @@ class GameDetailFragment : NormalFragment() { }) mViewModel.bigEventLiveData.observeNonNull(this) { - GameBigEventDialog.showGameBigEventDialog(requireContext(), mGameEntity?.name - ?: "", it, mEntrance) + GameBigEventDialog.showGameBigEventDialog( + requireContext(), mGameEntity?.name + ?: "", it, mEntrance + ) } mViewModel.recommendPopupLiveData.observe(this, Observer { initRecommendUI() @@ -610,16 +690,22 @@ class GameDetailFragment : NormalFragment() { val bundle = Bundle() bundle.putParcelable(GameEntity.TAG, mGameEntity) bundle.putString(EntranceUtils.KEY_ENTRANCE, mEntrance) - bundle.putBoolean(EntranceUtils.KEY_SCROLL_TO_LIBAO, arguments?.getBoolean(EntranceUtils.KEY_SCROLL_TO_LIBAO) - ?: false) - bundle.putBoolean(EntranceUtils.KEY_OPEN_VIDEO_STREAMING, arguments?.getBoolean(EntranceUtils.KEY_OPEN_VIDEO_STREAMING) - ?: false) + bundle.putBoolean( + EntranceUtils.KEY_SCROLL_TO_LIBAO, + arguments?.getBoolean(EntranceUtils.KEY_SCROLL_TO_LIBAO) + ?: false + ) + bundle.putBoolean( + EntranceUtils.KEY_OPEN_VIDEO_STREAMING, + arguments?.getBoolean(EntranceUtils.KEY_OPEN_VIDEO_STREAMING) + ?: false + ) fragmentsList.clear() tabTitleList.clear() val tag = "android:switcher:${mViewPager.id}:" val descFragment = childFragmentManager.findFragmentByTag("${tag}$INDEX_DESC") - ?: DescFragment() + ?: DescFragment() descFragment.arguments = bundle fragmentsList.add(descFragment) tabTitleList.add(getString(R.string.game_detail_desc)) @@ -627,7 +713,7 @@ class GameDetailFragment : NormalFragment() { data.zone?.let { if (it.style == "link") {//显示web页面 val webFragment = childFragmentManager.findFragmentByTag("${tag}${INDEX_TRENDES}") - ?: WebFragment() + ?: WebFragment() val webBundle = Bundle() webBundle.putString(EntranceUtils.KEY_URL, it.link) webBundle.putBoolean(WebFragment.KEY_OPEN_NATIVE_PAGE, true) @@ -635,7 +721,7 @@ class GameDetailFragment : NormalFragment() { fragmentsList.add(webFragment) } else { val fuliFragment = childFragmentManager.findFragmentByTag("${tag}${INDEX_TRENDES}") - ?: FuLiFragment() + ?: FuLiFragment() fuliFragment.arguments = bundle fragmentsList.add(fuliFragment) } @@ -644,7 +730,7 @@ class GameDetailFragment : NormalFragment() { if (data.showComment) { val ratingFragment = childFragmentManager.findFragmentByTag("${tag}${INDEX_RATING}") - ?: RatingFragment() + ?: RatingFragment() bundle.putBoolean(EntranceUtils.KEY_SKIP_GAME_COMMENT, mSkipGameComment) bundle.putBoolean(EntranceUtils.KEY_DIRECT_COMMENT, data.directComment) ratingFragment.arguments = bundle @@ -687,7 +773,11 @@ class GameDetailFragment : NormalFragment() { val dialog = retrieveAvailableDialog(detailEntity.detailDialogs) if (dialog != null) { val dayOfMonth = Calendar.getInstance().get(Calendar.DAY_OF_MONTH) - if ("EVERY_TIME_OPEN" == dialog.alert || SPUtils.getLong(SP_OPENED_DIALOG_TIME_PREFIX + mGameEntity?.id, 0) != dayOfMonth.toLong()) { + if ("EVERY_TIME_OPEN" == dialog.alert || SPUtils.getLong( + SP_OPENED_DIALOG_TIME_PREFIX + mGameEntity?.id, + 0 + ) != dayOfMonth.toLong() + ) { SPUtils.setLong(SP_OPENED_DIALOG_TIME_PREFIX + mGameEntity?.id, dayOfMonth.toLong()) doShowAlertDialog(dialog) } @@ -696,7 +786,7 @@ class GameDetailFragment : NormalFragment() { private fun retrieveAvailableDialog(detailDialogs: ArrayList): GameEntity.Dialog? { for (dialog in detailDialogs) { - val versionName = PackageUtils.getVersionName() + val versionName = PackageUtils.getGhVersionName() val noticeVersions = dialog.rule.noticeVersions if (noticeVersions.isEmpty() || noticeVersions.contains(versionName)) { if (dialog.rule.models.isEmpty() || dialog.rule.models.contains(Build.MODEL)) { @@ -708,19 +798,22 @@ class GameDetailFragment : NormalFragment() { } private fun doShowAlertDialog(dialog: GameEntity.Dialog) { - DialogUtils.showDialogWithHtmlContent(requireContext(), - dialog.title, - dialog.content, - dialog.confirmButton.text, - dialog.closeButtonText, - { - dialog.confirmButton.text = dialog.confirmButton.linkText - DirectUtils.directToLinkPage( - requireContext(), - dialog.confirmButton, - mEntrance, - "") - }, null) + DialogUtils.showDialogWithHtmlContent( + requireContext(), + dialog.title, + dialog.content, + dialog.confirmButton.text, + dialog.closeButtonText, + { + dialog.confirmButton.text = dialog.confirmButton.linkText + DirectUtils.directToLinkPage( + requireContext(), + dialog.confirmButton, + mEntrance, + "" + ) + }, null + ) } private fun loadErrorControl(exception: HttpException?) { @@ -733,7 +826,8 @@ class GameDetailFragment : NormalFragment() { mLoading.visibility = View.GONE mNoConnection.visibility = View.GONE mNoneDataView.visibility = View.VISIBLE - mConcernBtn.visibility = View.GONE + mConcernIv.visibility = View.GONE + mConcernTv.visibility = View.GONE toast("内容可能已被删除") } else { mLoading.visibility = View.GONE @@ -767,22 +861,44 @@ class GameDetailFragment : NormalFragment() { override fun onMoreClickListener() { if (!isVisible) return MtaHelper.onEvent("游戏详情_新", "标签展开", mViewModel.game?.name ?: "") - GameTagsDialog.showGameTagsDialog(requireActivity(), mNewGameDetailEntity?.tagStyle!!, mGameEntity?.id - ?: "", mGameEntity?.name ?: "") + GameTagsDialog.showGameTagsDialog( + requireActivity(), mNewGameDetailEntity?.tagStyle!!, mGameEntity?.id + ?: "", mGameEntity?.name ?: "" + ) } override fun onItemClickListener(tag: TagStyleEntity) { - NewLogUtils.logGameDetailTagClick(mGameEntity?.id ?: "", mGameEntity?.name - ?: "", tag.id, tag.name) + NewLogUtils.logGameDetailTagClick( + mGameEntity?.id ?: "", mGameEntity?.name + ?: "", tag.id, tag.name + ) MtaHelper.onEvent("游戏详情_新", "点击标签", mViewModel.game?.name ?: "") - requireContext().startActivity(TagsActivity.getIntent(requireContext(), - tag.name, tag.name, mEntrance, "游戏介绍")) + requireContext().startActivity( + TagsActivity.getIntent( + requireContext(), + tag.name, tag.name, mEntrance, "游戏介绍" + ) + ) + } + } + val recommendAge = mNewGameDetailEntity?.recommendAge + recommendAgeIv.goneIf(recommendAge.isNullOrEmpty()) + if (!recommendAge.isNullOrEmpty()) { + val recommendAgeRes = when (recommendAge) { + "8+" -> R.drawable.ic_recommend_age8 + "12+" -> R.drawable.ic_recommend_age12 + "16+" -> R.drawable.ic_recommend_age16 + else -> -1 + } + if (recommendAgeRes > 0) { + recommendAgeIv.setImageDrawable(recommendAgeRes.toDrawable()) } } ratingScoreContainer.goneIf(!mNewGameDetailEntity!!.showComment) if (mGameEntity?.commentCount ?: 0 > 3) { ratingScoreAverage.textSize = 18f - ratingScoreAverage.text = if (mGameEntity?.star == 10F) "10" else mGameEntity?.star.toString() + ratingScoreAverage.text = + if (mGameEntity?.star == 10F) "10" else mGameEntity?.star.toString() } else { ratingScoreAverage.textSize = 8f ratingScoreAverage.text = "评分过少" @@ -796,8 +912,17 @@ class GameDetailFragment : NormalFragment() { gameDetailRankTv.text = "${ranking.columnName}第${ranking.no}名" gameDetailRankTv.isSelected = true gameDetailRankLl.setOnClickListener { - MtaHelper.onEvent("游戏详情_新", "点击榜单", "${mViewModel.game?.name}+${ranking.columnName}") - DirectUtils.directToColumnCollection(requireContext(), ranking.collectionId, entrance = mEntrance, columnName = ranking.columnName) + MtaHelper.onEvent( + "游戏详情_新", + "点击榜单", + "${mViewModel.game?.name}+${ranking.columnName}" + ) + DirectUtils.directToColumnCollection( + requireContext(), + ranking.collectionId, + entrance = mEntrance, + columnName = ranking.columnName + ) } } @@ -807,20 +932,60 @@ class GameDetailFragment : NormalFragment() { mNewGameDetailEntity?.event?.let { gameBigEvent.visibility = View.VISIBLE if (it.highLight) { - gameBigEvent.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_2A85FB)) - gameBigEvent.background = ContextCompat.getDrawable(requireContext(), R.drawable.bg_game_big_event_light) - gameBigEvent.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(requireContext(), R.drawable.ic_game_detail_big_event), null, - ContextCompat.getDrawable(requireContext(), R.drawable.ic_game_detail_big_event_arrow), null) - var eventStr = "${TimeUtils.getFormatTime(it.time, "MM-dd")}${TimeUtils.getDayString(it.time)}:${it.content}" - if (eventStr.contains("\n")) eventStr = eventStr.substring(0, eventStr.indexOf("\n")) + gameBigEvent.setTextColor( + ContextCompat.getColor( + requireContext(), + R.color.text_2A85FB + ) + ) + gameBigEvent.background = + ContextCompat.getDrawable(requireContext(), R.drawable.bg_game_big_event_light) + gameBigEvent.setCompoundDrawablesWithIntrinsicBounds( + ContextCompat.getDrawable( + requireContext(), + R.drawable.ic_game_detail_big_event + ), null, + ContextCompat.getDrawable( + requireContext(), + R.drawable.ic_game_detail_big_event_arrow + ), null + ) + var eventStr = "${ + TimeUtils.getFormatTime( + it.time, + "MM-dd" + ) + }${TimeUtils.getDayString(it.time)}:${it.content}" + if (eventStr.contains("\n")) eventStr = + eventStr.substring(0, eventStr.indexOf("\n")) gameBigEvent.text = eventStr } else { - gameBigEvent.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_999999)) - gameBigEvent.background = ContextCompat.getDrawable(requireContext(), R.drawable.bg_game_big_event) - gameBigEvent.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(requireContext(), R.drawable.ic_game_detail_big_event_gray), null, - ContextCompat.getDrawable(requireContext(), R.drawable.ic_game_detail_big_event_arrow_gray), null) - var eventStr = if (TimeUtils.getBeforeDays(it.time) <= 15) "${TimeUtils.getFormatTime(it.time, "MM-dd")}${TimeUtils.getDayString(it.time)}:${it.content}" else it.content - if (eventStr.contains("\n")) eventStr = eventStr.substring(0, eventStr.indexOf("\n")) + gameBigEvent.setTextColor( + ContextCompat.getColor( + requireContext(), + R.color.text_999999 + ) + ) + gameBigEvent.background = + ContextCompat.getDrawable(requireContext(), R.drawable.bg_game_big_event) + gameBigEvent.setCompoundDrawablesWithIntrinsicBounds( + ContextCompat.getDrawable( + requireContext(), + R.drawable.ic_game_detail_big_event_gray + ), null, + ContextCompat.getDrawable( + requireContext(), + R.drawable.ic_game_detail_big_event_arrow_gray + ), null + ) + var eventStr = if (TimeUtils.getBeforeDays(it.time) <= 15) "${ + TimeUtils.getFormatTime( + it.time, + "MM-dd" + ) + }${TimeUtils.getDayString(it.time)}:${it.content}" else it.content + if (eventStr.contains("\n")) eventStr = + eventStr.substring(0, eventStr.indexOf("\n")) gameBigEvent.text = eventStr } gameBigEvent.setOnClickListener { @@ -832,20 +997,20 @@ class GameDetailFragment : NormalFragment() { private fun setUpTopVideo(topVideo: GameDetailEntity.Video) { GSYVideoOptionBuilder() - .setIsTouchWigetFull(false) - .setIsTouchWiget(false) - .setRotateViewAuto(false) - .setShowFullAnimation(false) - .setSeekRatio(1f) - .setUrl(topVideo.url) - .setCacheWithPlay(true) - .setVideoAllCallBack(object : GSYSampleCallBack() { - override fun onQuitFullscreen(url: String?, vararg objects: Any) { - mOrientationUtils?.backToProtVideo() - mTopVideoView.uploadVideoStreamingPlaying("退出全屏") - } - }) - .build(mTopVideoView) + .setIsTouchWigetFull(false) + .setIsTouchWiget(false) + .setRotateViewAuto(false) + .setShowFullAnimation(false) + .setSeekRatio(1f) + .setUrl(topVideo.url) + .setCacheWithPlay(true) + .setVideoAllCallBack(object : GSYSampleCallBack() { + override fun onQuitFullscreen(url: String?, vararg objects: Any) { + mOrientationUtils?.backToProtVideo() + mTopVideoView.uploadVideoStreamingPlaying("退出全屏") + } + }) + .build(mTopVideoView) mTopVideoView.gameName = mGameEntity?.name ?: "" mTopVideoView.viewModel = mViewModel @@ -853,8 +1018,11 @@ class GameDetailFragment : NormalFragment() { mTopVideoView.updateThumb(topVideo.poster) //val trafficVideo = PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SettingsFragment.TRAFFIC_VIDEO_SP_KEY, false) - val videoOption = SPUtils.getString(Constants.SP_HOME_OR_DETAIL_VIDEO_OPTION, VideoSettingFragment.VIDEO_OPTION_WIFI) - ?: VideoSettingFragment.VIDEO_OPTION_WIFI + val videoOption = SPUtils.getString( + Constants.SP_HOME_OR_DETAIL_VIDEO_OPTION, + VideoSettingFragment.VIDEO_OPTION_WIFI + ) + ?: VideoSettingFragment.VIDEO_OPTION_WIFI when (videoOption) { VideoSettingFragment.VIDEO_OPTION_ALL -> { mTopVideoView.startPlayLogic(isAutoPlay = true) @@ -880,7 +1048,8 @@ class GameDetailFragment : NormalFragment() { } mTopVideoView.fullscreenButton.setOnClickListener { - val horizontalVideoView = mTopVideoView.startWindowFullscreen(requireContext(), true, true) as? TopVideoView + val horizontalVideoView = + mTopVideoView.startWindowFullscreen(requireContext(), true, true) as? TopVideoView if (horizontalVideoView == null) { toastInInternalRelease("全屏失败,请向技术人员提供具体的操作步骤") return@setOnClickListener @@ -900,10 +1069,24 @@ class GameDetailFragment : NormalFragment() { } private fun updateToolbarStyle(isToolbarWhite: Boolean) { - mTitleTv.setTextColor(ContextCompat.getColor(requireContext(), if (isToolbarWhite) R.color.black else R.color.white)) + mTitleTv.setTextColor( + ContextCompat.getColor( + requireContext(), + if (isToolbarWhite) R.color.black else R.color.white + ) + ) mToolbar.setNavigationIcon(if (isToolbarWhite) R.drawable.ic_bar_back else R.drawable.ic_bar_back_light) - mToolbar.setBackgroundColor(ContextCompat.getColor(requireContext(), if (isToolbarWhite) R.color.white else R.color.transparent)) - DisplayUtils.setStatusBarColor(requireActivity(), if (isToolbarWhite) R.color.white else R.color.transparent, true) + mToolbar.setBackgroundColor( + ContextCompat.getColor( + requireContext(), + if (isToolbarWhite) R.color.white else R.color.transparent + ) + ) + DisplayUtils.setStatusBarColor( + requireActivity(), + if (isToolbarWhite) R.color.white else R.color.transparent, + true + ) updateConcernMenuIcon(mNewGameDetailEntity?.me?.isGameConcerned ?: false) mMoreMenuItem?.setIcon(if (isToolbarWhite) R.drawable.ic_menu_gamedetail_more else R.drawable.ic_menu_gamedetail_more_light) mSearchMenuItem?.setIcon(if (isToolbarWhite) R.drawable.ic_menu_gamedetail_search else R.drawable.ic_menu_gamedetail_search_light) @@ -927,7 +1110,8 @@ class GameDetailFragment : NormalFragment() { } else if (SKIP_FULI == reuse.type) { mViewPager.currentItem = INDEX_TRENDES } else if (SKIP_RATING == reuse.type) { - mViewPager.currentItem = if (mNewGameDetailEntity?.zone == null) INDEX_RATING_FOR_NO_TRENDES else INDEX_RATING + mViewPager.currentItem = + if (mNewGameDetailEntity?.zone == null) INDEX_RATING_FOR_NO_TRENDES else INDEX_RATING } else if ("hideKaifuHint" == reuse.type) { mIsShowKaifuHint = false mKaifuHint.visibility = View.GONE @@ -972,7 +1156,18 @@ class GameDetailFragment : NormalFragment() { } } - @OnClick(R.id.reuse_no_connection, R.id.gamedetail_kaifu_hint, R.id.concern_btn, R.id.reserve_btn, R.id.closeIv, R.id.recommendCloseIv) + @OnClick( + R.id.reuse_no_connection, + R.id.gamedetail_kaifu_hint, + R.id.iv_concern, + R.id.tv_concern, + R.id.iv_reserve, + R.id.tv_reserve, + R.id.iv_switch, + R.id.tv_switch, + R.id.closeIv, + R.id.recommendCloseIv + ) override fun onClick(v: View) { when (v.id) { R.id.reuse_no_connection -> { @@ -986,57 +1181,85 @@ class GameDetailFragment : NormalFragment() { mAppBarLayout.setExpanded(false, true) mIsScrollToKaiFu = true } - R.id.concern_btn -> { + R.id.iv_concern, R.id.tv_concern -> { ifLogin("游戏详情-[关注]") { if (mNewGameDetailEntity != null && mNewGameDetailEntity!!.me.isGameConcerned) { - DialogUtils.showCancelDialog(requireContext(), { mViewModel.concernCommand(false) }, null) + DialogUtils.showCancelDialog( + requireContext(), + { mViewModel.concernCommand(false) }, + null + ) } else { mViewModel.concernCommand(true) } } } - R.id.reserve_btn -> { + R.id.iv_reserve, R.id.tv_reserve -> { if (mGameEntity != null && SimulatorGameManager.isSimulatorGame(mGameEntity!!)) { startActivity(SimulatorGameActivity.getIntent(requireContext())) return } CheckLoginUtils.checkLogin(requireContext(), "游戏详情") { if (!ReservationRepository.thisGameHasBeenReserved(mGameEntity?.id ?: "")) { - val dialogFragment = ReserveDialogFragment.getInstance(mGameEntity!!, object : ReserveDialogFragment.SuccessCallback { - override fun onSuccess() { - LogUtils.logReservation(mGameEntity, mTraceEvent) - DetailDownloadUtils.detailInitDownload(detailViewHolder, false) - showReserveBtn(isShowReserveBtn()) - } - }) + val dialogFragment = ReserveDialogFragment.getInstance( + mGameEntity!!, + object : ReserveDialogFragment.SuccessCallback { + override fun onSuccess() { + LogUtils.logReservation(mGameEntity, mTraceEvent) + DetailDownloadUtils.detailInitDownload(detailViewHolder, false) + showReserveBtn(isShowReserveBtn()) + } + }) dialogFragment.show(childFragmentManager, "reserve") } else { if ("download" == mGameEntity?.reserveStatus) { - ReservationHelper.showDeleteReservationDialog(requireContext(), object : EmptyCallback { - override fun onCallback() { - ReservationHelper.deleteReservation(mGameEntity!!, object : EmptyCallback { - override fun onCallback() { - DetailDownloadUtils.detailInitDownload(detailViewHolder, false) - showReserveBtn(isShowReserveBtn()) - } - }) - } - }) + ReservationHelper.showDeleteReservationDialog( + requireContext(), + object : EmptyCallback { + override fun onCallback() { + ReservationHelper.deleteReservation( + mGameEntity!!, + object : EmptyCallback { + override fun onCallback() { + DetailDownloadUtils.detailInitDownload( + detailViewHolder, + false + ) + showReserveBtn(isShowReserveBtn()) + } + }) + } + }) } else { - ReservationHelper.showCancelReservationDialog(requireContext(), object : EmptyCallback { - override fun onCallback() { - ReservationHelper.cancelReservation(mGameEntity!!, object : EmptyCallback { - override fun onCallback() { - DetailDownloadUtils.detailInitDownload(detailViewHolder, false) - showReserveBtn(isShowReserveBtn()) - } - }) - } - }) + ReservationHelper.showCancelReservationDialog( + requireContext(), + object : EmptyCallback { + override fun onCallback() { + ReservationHelper.cancelReservation( + mGameEntity!!, + object : EmptyCallback { + override fun onCallback() { + DetailDownloadUtils.detailInitDownload( + detailViewHolder, + false + ) + showReserveBtn(isShowReserveBtn()) + } + }) + } + }) } } } } + R.id.iv_switch, R.id.tv_switch -> { + val intent = ShellActivity.getIntent( + requireContext(), + ShellActivity.Type.SWITCH_INSTALL_METHOD, + null + ) + requireActivity().startActivity(intent) + } R.id.closeIv -> { showReserveGuide(false) } @@ -1048,11 +1271,11 @@ class GameDetailFragment : NormalFragment() { private fun updateConcernMenuIcon(isConcerned: Boolean) { if (isConcerned) { - mConcernBtn.text = "已关注" - mConcernBtn.setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(requireContext(), R.drawable.ic_gamedetail_concerned), null, null) + mConcernTv.text = "已关注" + mConcernIv.background = R.drawable.ic_gamedetail_concerned.toDrawable() } else { - mConcernBtn.text = "关注" - mConcernBtn.setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(requireContext(), R.drawable.ic_gamedetail_concern), null, null) + mConcernTv.text = "关注" + mConcernIv.background = R.drawable.ic_gamedetail_concern.toDrawable() } } @@ -1064,7 +1287,8 @@ class GameDetailFragment : NormalFragment() { } private fun updateDownloadCountHint(updateList: List?) { - val count = DownloadManager.getInstance(requireContext()).getDownloadOrUpdateCount(updateList) + val count = + DownloadManager.getInstance(requireContext()).getDownloadOrUpdateCount(updateList) val params = mDownloadCountHint?.layoutParams if (TextUtils.isEmpty(count)) { params?.width = DisplayUtils.dip2px(6f) @@ -1083,10 +1307,15 @@ class GameDetailFragment : NormalFragment() { if (isShowReserveBtn()) { showReserveBtn(true) val isFirstIn = SPUtils.getBoolean(Constants.SP_GAME_DETAIL_RESERVE_GUIDE, true) + val gameGuidePopupEntity = Config.getGameGuidePopupEntity() if (isFirstIn && mGameEntity?.downloadOffStatus == null) { showReserveGuide(true) SPUtils.setBoolean(Constants.SP_GAME_DETAIL_RESERVE_GUIDE, false) } + if (gameGuidePopupEntity != null) { + showReserveGuide(false) + SPUtils.setBoolean(Constants.SP_GAME_DETAIL_RESERVE_GUIDE, false) + } } else { showReserveBtn(false) } @@ -1094,23 +1323,26 @@ class GameDetailFragment : NormalFragment() { private fun showReserveBtn(isShow: Boolean = false) { if (mGameEntity != null && SimulatorGameManager.isSimulatorGame(mGameEntity!!)) { - mReserveBtn.visibility = View.VISIBLE - mReserveBtn.text = "管理" - mReserveBtn.setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(requireContext(), R.drawable.ic_gamedetail_simulator_manage), null, null) + mReserveIv.visibility = View.VISIBLE + mReserveTv.visibility = View.VISIBLE + mReserveTv.text = "管理" + mReserveIv.background = R.drawable.ic_gamedetail_simulator_manage.toDrawable() return } if (isShow) { - mReserveBtn.visibility = View.VISIBLE + mReserveIv.visibility = View.VISIBLE + mReserveTv.visibility = View.VISIBLE if (ReservationRepository.thisGameHasBeenReserved(mGameEntity?.id ?: "")) { - mReserveBtn.text = "已预约" - mReserveBtn.setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(requireContext(), R.drawable.ic_gamedetail_reserved), null, null) + mReserveTv.text = "已预约" + mReserveIv.background = R.drawable.ic_gamedetail_reserved.toDrawable() } else { - mReserveBtn.text = "预约" - mReserveBtn.setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(requireContext(), R.drawable.ic_gamedetail_reserve), null, null) + mReserveTv.text = "预约" + mReserveIv.background = R.drawable.ic_gamedetail_reserve.toDrawable() } } else { - mReserveBtn.visibility = View.GONE + mReserveIv.visibility = View.GONE + mReserveTv.visibility = View.GONE } } @@ -1121,7 +1353,9 @@ class GameDetailFragment : NormalFragment() { private fun isShowReserveBtn(): Boolean { if (mGameEntity == null) return false if (mNewGameDetailEntity == null) return false - if (mGameEntity!!.getApk().isEmpty() || mGameEntity!!.downloadOffStatus != null || !mNewGameDetailEntity!!.appointmentSwitchStatus) return false + if (mGameEntity!!.getApk() + .isEmpty() || mGameEntity!!.downloadOffStatus != null || !mNewGameDetailEntity!!.appointmentSwitchStatus + ) return false return true } @@ -1158,7 +1392,8 @@ class GameDetailFragment : NormalFragment() { private fun handleTabTouchEvent(title: String) { if (title == mTabClickEvent.second - && System.currentTimeMillis() - mTabClickEvent.first < 300) { + && System.currentTimeMillis() - mTabClickEvent.first < 300 + ) { val fragment = fragmentsList[mViewPager.currentItem] if (fragment is IScrollable) { fragment.scrollToTop() @@ -1177,7 +1412,11 @@ class GameDetailFragment : NormalFragment() { if (BrowserInstallHelper.shouldShowGameDetailUseBrowserToInstallHint()) { mBrowserInstallContainer.visibility = View.VISIBLE mBrowserInstallContainer.setOnClickListener { - val intent = ShellActivity.getIntent(requireContext(), ShellActivity.Type.SWITCH_INSTALL_METHOD, null) + val intent = ShellActivity.getIntent( + requireContext(), + ShellActivity.Type.SWITCH_INSTALL_METHOD, + null + ) requireActivity().startActivity(intent) BrowserInstallHelper.logOrdinaryBrowserEvent(BrowserInstallHelper.Type.SWITCH_INSTALL_GUIDE_ACCESS) } @@ -1186,36 +1425,95 @@ class GameDetailFragment : NormalFragment() { var closeHintText = "" if (manufacturer == "OPPO" || manufacturer == "VIVO") { - hintText = "${manufacturer}手机如何解决安装需要密码" - closeHintText = "关闭后将不再显示免密安装引导,您可以前往“ 我的光环-设置-切换安装方式”进行设置,或在“ 我的光环-帮助与反馈”查看相关问题" + hintText = + if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) "当前安装方式为[浏览器安装],点击切换安装方式" else "${manufacturer}手机如何解决安装需要密码" + closeHintText = + "关闭后“切换安装方式”入口将显示在左下角,您也可以前往“我的光环-设置-切换安装方式”进行设置,或在“ 我的光环-帮助与反馈”查看相关问题" } else { - hintText = "手机如何解决无法安装问题" - closeHintText = "关闭后将不再显示切换安装方式引导,您可以前往“ 我的光环-设置-切换安装方式”进行设置" + hintText = + if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) "当前安装方式为[浏览器安装],点击切换安装方式" else "手机如何解决无法安装问题" + closeHintText = "关闭后“切换安装方式”入口将显示在左下角,您也可以前往“我的光环-设置-切换安装方式”进行设置" } mBrowserInstallHintTv.text = hintText mBrowserInstallCloseIv.setOnClickListener { DialogHelper.showDialog( - requireContext(), - "温馨提示", - closeHintText, - "确定", - "取消", - { - mBrowserInstallContainer.visibility = View.GONE - BrowserInstallHelper.hideGameDetailUseBrowserToInstallHint() - BrowserInstallHelper.logOrdinaryBrowserEvent(BrowserInstallHelper.Type.SWITCH_INSTALL_GUIDE_QUIT) - } + requireContext(), + "温馨提示", + closeHintText, + "确定", + "取消", + { + mBrowserInstallContainer.visibility = View.GONE + SPUtils.setBoolean(Constants.SP_SWITCH_INSTALL_VISIBLE, true) + mSwitchIv.visibility = View.VISIBLE + mSwitchTv.visibility = View.VISIBLE + BrowserInstallHelper.hideGameDetailUseBrowserToInstallHint() + BrowserInstallHelper.logOrdinaryBrowserEvent(BrowserInstallHelper.Type.SWITCH_INSTALL_GUIDE_QUIT) + } ) } } else { mBrowserInstallContainer.visibility = View.GONE } + if (SPUtils.getBoolean(Constants.SP_SWITCH_INSTALL_VISIBLE, false)) { + mSwitchIv.visibility = View.VISIBLE + mSwitchTv.visibility = View.VISIBLE + } else { + mSwitchIv.visibility = View.GONE + mSwitchTv.visibility = View.GONE + } } + private fun controlInstallHint() { + if (mGameEntity != null) { + val status = GameUtils.getDownloadBtnText( + requireContext(), + mGameEntity, + PluginLocation.only_game + ) + val isLaunch = (status == getString(R.string.launch) || status == getString(R.string.open)) + if (SPUtils.getBoolean(Constants.SP_SHOULD_SHOW_GAME_DETAIL_INSTALL_GUIDE, false) && !mGameEntity!!.isReservable) { + if (mGameEntity!!.downloadOffText?.isEmpty() == true && !isLaunch) { + showInstallHint() + } else { + hideInstallHint() + } + } + } + } + + private fun showInstallHint() { + val gameGuidePopupEntity = Config.getGameGuidePopupEntity() + if (SPUtils.getBoolean(Constants.SP_GAME_DETAIL_INSTALL_GUIDE, true) && gameGuidePopupEntity != null) { + mInstallHintTv.text = gameGuidePopupEntity.content + mInstallContainer.visibility = View.VISIBLE + NewLogUtils.logGuidePopShow(gameGuidePopupEntity.id) + mInstallContainer.setDebouncedClickListener { + DirectUtils.directToLinkPage(requireContext(), gameGuidePopupEntity.jump, mEntrance, "游戏详情") + NewLogUtils.logGuidePopLinkClick( + gameGuidePopupEntity.id, + gameGuidePopupEntity.jump.type, + gameGuidePopupEntity.jump.linkText + ) + } + mInstallCloseIv.setDebouncedClickListener { + hideInstallHint() + SPUtils.setBoolean(Constants.SP_GAME_DETAIL_INSTALL_GUIDE, false) + NewLogUtils.logGuidePopClose(gameGuidePopupEntity.id) + } + } + } + + private fun hideInstallHint() { + mInstallContainer.visibility = View.GONE + } + + private fun initRecommendUI() { val recommendPopupList = mViewModel.recommendPopupLiveData.value - mRecommendPopupEntity = RecommendPopupHelper.getRecommendPopup(mViewModel.game, recommendPopupList) + mRecommendPopupEntity = + RecommendPopupHelper.getRecommendPopup(mViewModel.game, recommendPopupList) ?: return val popupDetail = mRecommendPopupEntity!!.popupDetail mRecommendText.text = popupDetail.text @@ -1243,10 +1541,19 @@ class GameDetailFragment : NormalFragment() { mRecommendLinkTv.text = popupDetail.link?.title mRecommendLinkTv.setOnClickListener { popupDetail.link?.let { - PageSwitchDataHelper.pushCurrentPageData(hashMapOf(Pair(PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND, ""))) + PageSwitchDataHelper.pushCurrentPageData( + hashMapOf( + Pair( + PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND, + "" + ) + ) + ) DirectUtils.directToLinkPage(requireContext(), it, mEntrance, "游戏详情") - LogUtils.uploadRecommendPopup("recommend_pop_link_click", mRecommendPopupEntity?.id, mViewModel.game?.id - ?: "", mViewModel.game?.name ?: "", it.type, it.text, "", "") + LogUtils.uploadRecommendPopup( + "recommend_pop_link_click", mRecommendPopupEntity?.id, mViewModel.game?.id + ?: "", mViewModel.game?.name ?: "", it.type, it.text, "", "" + ) } } } @@ -1263,12 +1570,15 @@ class GameDetailFragment : NormalFragment() { mIsRecommendViewShow = true RecommendPopupHelper.saveRecord(mRecommendPopupEntity!!) if (mRecommendPopupEntity!!.popupDetail.duration > 0) { - mRecommendDisposable = countDownTimer(mRecommendPopupEntity!!.popupDetail.duration) { finish, _ -> - if (finish) hideRecommendView() - } + mRecommendDisposable = + countDownTimer(mRecommendPopupEntity!!.popupDetail.duration) { finish, _ -> + if (finish) hideRecommendView() + } } - LogUtils.uploadRecommendPopup("recommend_pop_show", mRecommendPopupEntity?.id, mViewModel.game?.id - ?: "", mViewModel.game?.name ?: "", "", "", "", "") + LogUtils.uploadRecommendPopup( + "recommend_pop_show", mRecommendPopupEntity?.id, mViewModel.game?.id + ?: "", mViewModel.game?.name ?: "", "", "", "", "" + ) } } } @@ -1282,8 +1592,10 @@ class GameDetailFragment : NormalFragment() { mRecommendDisposable?.dispose() mRecommendDisposable = null if (isManuallyClose) { - LogUtils.uploadRecommendPopup("recommend_pop_close", mRecommendPopupEntity?.id, mViewModel.game?.id - ?: "", mViewModel.game?.name ?: "", "", "", "", "") + LogUtils.uploadRecommendPopup( + "recommend_pop_close", mRecommendPopupEntity?.id, mViewModel.game?.id + ?: "", mViewModel.game?.name ?: "", "", "", "", "" + ) } } } @@ -1299,7 +1611,9 @@ class GameDetailFragment : NormalFragment() { override fun onBackPressed(): Boolean { mOrientationUtils?.backToProtVideo() - if (mViewPager.currentItem == INDEX_TRENDES && fragmentsList[INDEX_TRENDES] is WebFragment) { + if (mViewPager.currentItem == INDEX_TRENDES + && fragmentsList[INDEX_TRENDES] is WebFragment + && fragmentsList[INDEX_TRENDES].isAdded) { return (fragmentsList[INDEX_TRENDES] as WebFragment).onBackPressed() } @@ -1325,6 +1639,7 @@ class GameDetailFragment : NormalFragment() { showBrowserInstallHintIfNeeded() DownloadManager.getInstance(context).addObserver(dataWatcher) + controlInstallHint() } override fun onPause() { @@ -1334,7 +1649,10 @@ class GameDetailFragment : NormalFragment() { val currentPosition = mTopVideoView.getCurrentPosition() val topVideo = mNewGameDetailEntity?.topVideo if (topVideo != null) { - ScrollCalculatorHelper.savePlaySchedule(MD5Utils.getContentMD5(topVideo.url), currentPosition) + ScrollCalculatorHelper.savePlaySchedule( + MD5Utils.getContentMD5(topVideo.url), + currentPosition + ) } } hideRecommendView() diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescCommentsAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescCommentsAdapter.kt index f7591f8d96..eb60629c24 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescCommentsAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescCommentsAdapter.kt @@ -161,9 +161,11 @@ class DescCommentsAdapter(context: Context, "投诉" -> { MtaHelper.onEvent("游戏详情_新", "玩家评论_投诉", mViewModel.game?.name) mContext.ifLogin(BaseActivity.mergeEntranceAndPath(mEntrance, path)) { - OptionDialogHelper.showOptionDialog(mContext, Constants.REPORT_LIST.toList(), callback = { reportType -> - SimpleRequestHelper.reportGameComment(mViewModel.game!!.id, commentData.id, reportType) - }) + DialogUtils.showReportReasonDialog(mContext, + Constants.REPORT_LIST.toList() as java.util.ArrayList + ) { reason, desc -> + SimpleRequestHelper.reportGameComment(mViewModel.game?.id ?: "", commentData.id, if (reason != "其他原因") reason else desc) + } } } } diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescFragment.kt index 6ae11f61a4..f2b13d79dc 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescFragment.kt @@ -198,14 +198,14 @@ class DescFragment : BaseFragment(), IScrollable { MtaHelper.onEvent("游戏详情_新", "游戏礼包", "${mViewModel.game?.name}+${liBao.name}") startActivityForResult(intent, 100) } - R.id.receiveTv -> { + /*R.id.receiveTv -> { val liBao = data as LibaoEntity if (liBao.status == "ling") { MtaHelper.onEvent("游戏详情_新", "游戏礼包[领取]", "${mViewModel.game?.name}+${liBao.name}") } val intent = LibaoDetailActivity.getIntent(context, liBao, true, "游戏详情") startActivityForResult(intent, 100) - } + }*/ } } diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescViewModel.kt index 04d7acda44..4e96ef1f34 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescViewModel.kt @@ -182,7 +182,7 @@ class DescViewModel(application: Application, fun sendSuggestion() { val params = hashMapOf() params["from"] = "" - params["ghversion"] = PackageUtils.getVersionName() + params["ghversion"] = PackageUtils.getGhVersionName() params["channel"] = HaloApp.getInstance().channel params["type"] = Build.MODEL params["sdk"] = android.os.Build.VERSION.SDK_INT.toString() diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/GameDetailInfoItemAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/GameDetailInfoItemAdapter.kt index 8d402e37d5..a460a49528 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/GameDetailInfoItemAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/GameDetailInfoItemAdapter.kt @@ -37,6 +37,9 @@ class GameDetailInfoItemAdapter(val context: Context, val gameInfo: GameInfo, pr if (gameInfo.updateTime != 0L) { datas.add(GameInfoItemData(title = "更新时间", info = TimeUtils.getFormatTime(gameInfo.updateTime))) } + if (gameInfo.recommendAge.isNotEmpty()) { + datas.add(GameInfoItemData(title = "适龄等级", info = gameInfo.recommendAge)) + } if (!gameInfo.permissions.isNullOrEmpty()) { datas.add(GameInfoItemData(title = "权限及用途", info = "查看")) } diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/GameLibaoAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/GameLibaoAdapter.kt index cf9606a3d9..eba5ffc191 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/GameLibaoAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/GameLibaoAdapter.kt @@ -56,6 +56,7 @@ class GameLibaoAdapter(val context: Context, val libaos: ArrayList, holder.binding.libaoSchedulePb.visibility = View.GONE holder.binding.remainingTv.visibility = View.GONE holder.binding.libaoCodeTv.visibility = View.VISIBLE + holder.binding.copyLibaoCodeIv.visibility = View.GONE if (!UserManager.getInstance().isLoggedIn) { holder.binding.libaoCodeTv.text = "礼包码:-" @@ -69,7 +70,8 @@ class GameLibaoAdapter(val context: Context, val libaos: ArrayList, val code = libaoEntity.me?.userDataLibaoList?.get(size - 1)?.code ?: "" val text = "礼包码:$code" holder.binding.libaoCodeTv.text = SpanBuilder(text).color(4, text.length, R.color.theme_font).build() - holder.binding.libaoCodeTv.setOnClickListener { + holder.binding.copyLibaoCodeIv.visibility = View.VISIBLE + holder.binding.copyLibaoCodeIv.setOnClickListener { code.copyTextAndToast("$code 复制成功") } } @@ -103,7 +105,8 @@ class GameLibaoAdapter(val context: Context, val libaos: ArrayList, val code = libaoEntity.me?.userDataLibaoList?.get(size - 1)?.code ?: "" val text = "礼包码:$code" holder.binding.libaoCodeTv.text = SpanBuilder(text).color(4, text.length, R.color.theme_font).build() - holder.binding.libaoCodeTv.setOnClickListener { + holder.binding.copyLibaoCodeIv.visibility = View.VISIBLE + holder.binding.copyLibaoCodeIv.setOnClickListener { code.copyTextAndToast("$code 复制成功") } } @@ -118,13 +121,16 @@ class GameLibaoAdapter(val context: Context, val libaos: ArrayList, } - LibaoUtils.setLiBaoBtnStatusRound(holder.binding.receiveTv, libaoEntity,true, context) +// LibaoUtils.setLiBaoBtnStatusRound(holder.binding.receiveTv, libaoEntity,true, context) + LibaoUtils.initLibaoBtn(context, holder.binding.receiveTv, libaoEntity, false, null, true, "游戏详情"){ + notifyItemChanged(position) + } holder.itemView.setOnClickListener { listListener?.onListClick(it, position, libaoEntity) } - holder.binding.receiveTv.setOnClickListener { - listListener?.onListClick(it, position, libaoEntity) - } +// holder.binding.receiveTv.setOnClickListener { +// listListener?.onListClick(it, position, libaoEntity) +// } } is MoreViewHolder -> { holder.binding.arrowIv.rotation = if (mIsExpand) 180f else 0f diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/InviteCodeDialog.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/InviteCodeDialog.kt index 3e0912d04f..5b976c143e 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/InviteCodeDialog.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/InviteCodeDialog.kt @@ -7,19 +7,20 @@ import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.FragmentTransaction import com.gh.common.dialog.BaseDraggableDialogFragment import com.gh.common.util.EnergyTaskHelper +import com.gh.common.util.ToastUtils import com.gh.gamecenter.databinding.DialogInviteCodeBinding import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.retrofit.BiResponse import com.gh.gamecenter.retrofit.RetrofitManager import com.gh.gamecenter.security.BindPhoneActivity import com.halo.assistant.HaloApp -import com.lightgame.utils.Utils import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import okhttp3.MediaType import okhttp3.RequestBody import okhttp3.ResponseBody import org.json.JSONObject +import retrofit2.HttpException class InviteCodeDialog : BaseDraggableDialogFragment() { @@ -87,7 +88,21 @@ class InviteCodeDialog : BaseDraggableDialogFragment() { override fun onFailure(exception: Exception) { super.onFailure(exception) - Utils.toast(HaloApp.getInstance().application, "邀请码错误") + if (exception is HttpException) { + try { + val responseBody = exception.response().errorBody() + val string = responseBody!!.string() + val content = JSONObject(string) + when (content.optInt("code")) { + 403091 -> ToastUtils.showToast("你已经是老用户了") + + else -> ToastUtils.showToast("填写邀请码错误") + } + } catch (e: Exception) { + e.printStackTrace() + ToastUtils.showToast("填写邀请码错误") + } + } } }) } diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/entity/DetailEntity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/entity/DetailEntity.kt index 9032c53c4a..8503757698 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/entity/DetailEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/entity/DetailEntity.kt @@ -138,7 +138,9 @@ data class GameInfo( var manufacturer: String = "", var permissions: List? = null, @SerializedName("privacy_policy_url") - var privacyPolicyUrl: String? = null + var privacyPolicyUrl: String? = null, + @SerializedName("recommend_age") + var recommendAge: String = "",//适龄等级 ) : Parcelable @Keep diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/entity/NewGameDetailEntity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/entity/NewGameDetailEntity.kt index d67f9e86c6..4aad5a795f 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/entity/NewGameDetailEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/entity/NewGameDetailEntity.kt @@ -33,6 +33,8 @@ data class NewGameDetailEntity( var zone: ZoneEntity? = null, @SerializedName("appointment_switch_status") var appointmentSwitchStatus: Boolean = false, + @SerializedName("recommend_age") + var recommendAge: String = "",//适龄等级 @SerializedName("mirror_status") var mirrorStatus: String? = "", diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/history/HistoryApkListAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/history/HistoryApkListAdapter.kt index 465a50f7f4..593b731292 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/history/HistoryApkListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/history/HistoryApkListAdapter.kt @@ -176,7 +176,7 @@ class HistoryApkListAdapter(context: Context, } if (btnText == "安装" || btnText == "下载") { if (PackageUtils.isInstalled(mContext, apkEntity.packageName)) { - val installedVersion = PackageUtils.getVersionByPackage(apkEntity.packageName) + val installedVersion = PackageUtils.getVersionNameByPackageName(apkEntity.packageName) if (Version(installedVersion).isHigherThan(Version(apkEntity.version))) { return true } diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingCommentItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingCommentItemViewHolder.kt index 2ae652db37..94a79b17e1 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingCommentItemViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingCommentItemViewHolder.kt @@ -37,6 +37,7 @@ import com.squareup.picasso.Picasso import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers +import java.util.* import java.util.regex.Pattern class RatingCommentItemViewHolder(val binding: RatingCommentItemBinding) : BaseRecyclerViewHolder(binding.root) { @@ -86,7 +87,7 @@ class RatingCommentItemViewHolder(val binding: RatingCommentItemBinding) : BaseR if (commentData.user.badge != null) { sdvUserBadge.visibility = View.VISIBLE - tvBadgeName.visibility = View.VISIBLE +// tvBadgeName.visibility = View.VISIBLE ImageUtils.display(sdvUserBadge, commentData.user.badge.icon) tvBadgeName.text = commentData.user.badge.name } else { @@ -209,9 +210,11 @@ class RatingCommentItemViewHolder(val binding: RatingCommentItemBinding) : BaseR if (path == "游戏详情:评分") MtaHelper.onEvent("游戏详情_新", "评论Tab_投诉", game?.name) if (path == "折叠评论") MtaHelper.onEvent("折叠评论", "更多-投诉", game?.name) context.ifLogin(BaseActivity.mergeEntranceAndPath(entrance, path)) { - OptionDialogHelper.showOptionDialog(context, Constants.REPORT_LIST.toList(), callback = { reportType -> - SimpleRequestHelper.reportGameComment(game!!.id, commentData.id, reportType) - }) + DialogUtils.showReportReasonDialog(context, + Constants.REPORT_LIST.toList() as ArrayList + ) { reason, desc -> + SimpleRequestHelper.reportGameComment(game?.id ?: "", commentData.id, if (reason != "其他原因") reason else desc) + } } } } @@ -262,6 +265,11 @@ class RatingCommentItemViewHolder(val binding: RatingCommentItemBinding) : BaseR audit.text = auditText audit.movementMethod = LinkMovementMethod() } + + comment.post { + comment.visibility = View.INVISIBLE + vote.visibility = View.INVISIBLE + } } } } diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingFragment.kt index eb17ef368f..7b2d730556 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingFragment.kt @@ -29,7 +29,7 @@ import com.gh.gamecenter.entity.Star import com.gh.gamecenter.eventbus.EBReuse import com.gh.gamecenter.eventbus.EBTypeChange import com.gh.gamecenter.gamedetail.GameDetailFragment -import com.gh.gamecenter.personal.PersonalFragment.LOGIN_TAG +import com.gh.gamecenter.personal.PersonalFragment import com.halo.assistant.HaloApp import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe @@ -170,7 +170,7 @@ class RatingFragment : ListFragment(), IScrollab @Subscribe(threadMode = ThreadMode.MAIN) fun onEventMainThread(changed: EBReuse) { - if (LOGIN_TAG == changed.type) { // 登入 + if (PersonalFragment.LOGIN_TAG == changed.type) { // 登入 onLoadRefresh() } } diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyAdapter.kt index d42fe4cd59..4aed265c42 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyAdapter.kt @@ -51,10 +51,12 @@ import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers -class RatingReplyAdapter(context: Context, - val entrance: String, - val viewModel: RatingReplyViewModel, - val replyCallback: (RatingReplyEntity?) -> Unit) : ListAdapter(context), IExposable { +class RatingReplyAdapter( + context: Context, + val entrance: String, + val viewModel: RatingReplyViewModel, + val replyCallback: (RatingReplyEntity?) -> Unit +) : ListAdapter(context), IExposable { private val ITEM_COMMENT = 211 private val ITEM_SECTION_TITLE = 212 @@ -64,7 +66,8 @@ class RatingReplyAdapter(context: Context, override fun setListData(updateData: MutableList?) { if (mEntityList.size > 0 && mEntityList[mEntityList.size - 1].reply == null - && updateData != null && updateData.size > 0 && updateData[updateData.size - 1].reply != null) { + && updateData != null && updateData.size > 0 && updateData[updateData.size - 1].reply != null + ) { mEntityList = ArrayList(updateData) notifyDataSetChanged() } else { @@ -149,12 +152,19 @@ class RatingReplyAdapter(context: Context, holder.binding.game = game holder.itemView.setOnClickListener { - GameDetailActivity.startGameDetailActivity(mContext, game, BaseActivity.mergeEntranceAndPath(entrance, path), mExposureEvent) + GameDetailActivity.startGameDetailActivity( + mContext, + game, + BaseActivity.mergeEntranceAndPath(entrance, path), + mExposureEvent + ) } holder.binding.gameDownload.run { - DownloadItemUtils.setOnClickListener(mContext, this, - game, 0, this@RatingReplyAdapter, - entrance, BaseActivity.mergeEntranceAndPath(entrance, path), mExposureEvent) + DownloadItemUtils.setOnClickListener( + mContext, this, + game, 0, this@RatingReplyAdapter, + entrance, BaseActivity.mergeEntranceAndPath(entrance, path), mExposureEvent + ) // 显示预约 if (game.isReservable) { @@ -202,13 +212,22 @@ class RatingReplyAdapter(context: Context, isClickable = false } } else if (game.getApk().size == 1) { - GameUtils.setDownloadBtnStatus(mContext, game, this, PluginLocation.only_game) - val downloadEntity = DownloadManager.getInstance(mContext).getDownloadEntityByUrl(game.getApk()[0].url) + GameUtils.setDownloadBtnStatus( + mContext, + game, + this, + PluginLocation.only_game + ) + val downloadEntity = DownloadManager.getInstance(mContext) + .getDownloadEntityByUrl(game.getApk()[0].url) if (downloadEntity != null) { if (downloadEntity.status == DownloadStatus.done) { setText(R.string.install) setTextColor(Color.WHITE) - if (downloadEntity.isPluggable && PackagesManager.isInstalled(downloadEntity.packageName)) { + if (downloadEntity.isPluggable && PackagesManager.isInstalled( + downloadEntity.packageName + ) + ) { setBackgroundResource(R.drawable.game_item_btn_plugin_style) } else { setBackgroundResource(R.drawable.game_item_btn_download_style) @@ -220,11 +239,21 @@ class RatingReplyAdapter(context: Context, setText(R.string.downloading) } setBackgroundResource(R.drawable.game_item_btn_downloading_style) - setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style)) + setTextColor( + ContextCompat.getColorStateList( + context, + R.color.text_downloading_style + ) + ) } } } else { - GameUtils.setDownloadBtnStatus(mContext, game, this, PluginLocation.only_game) + GameUtils.setDownloadBtnStatus( + mContext, + game, + this, + PluginLocation.only_game + ) } } } @@ -236,7 +265,10 @@ class RatingReplyAdapter(context: Context, root.setPadding(20F.dip2px(), 0, 0, 0) content.setExpandMaxLines(Int.MAX_VALUE) content.setOnLongClickListener(View.OnLongClickListener { - commentData.content.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "").copyTextAndToast() + commentData.content.replace( + RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), + "" + ).copyTextAndToast() return@OnLongClickListener true }) comment.setOnClickListener { @@ -271,29 +303,75 @@ class RatingReplyAdapter(context: Context, val replyEntity = mEntityList[position].reply!! holder.binding.run { data = replyEntity - content.setTextWithHighlightedTextWrappedInsideWrapper(text = data?.content - ?: "", copyClickedText = true) + content.setTextWithHighlightedTextWrappedInsideWrapper( + text = data?.content + ?: "", copyClickedText = true + ) val parent = replyEntity.parent - userIcon.display(replyEntity.user.border, replyEntity.user.icon, replyEntity.user.auth?.icon) + userIcon.display( + replyEntity.user.border, + replyEntity.user.icon, + replyEntity.user.auth?.icon + ) if (parent != null) { val replyName: String val replyNameSpannable: SpannableStringBuilder if (replyEntity.user.badge != null && replyEntity.parent.user.badge == null) { replyName = "${replyEntity.user.name} 回复 ${parent.user.name}" - replyNameSpannable = SpanBuilder(replyName).color(mContext, replyEntity.user.name!!.length + 4, replyEntity.user.name!!.length + 6, R.color.text_9a9a9a).build() - setBadgeSpan(replyEntity.user, replyNameSpannable, replyEntity.user.name!!.length + 1, replyEntity.user.name!!.length + 2) + replyNameSpannable = SpanBuilder(replyName).color( + mContext, + replyEntity.user.name!!.length + 4, + replyEntity.user.name!!.length + 6, + R.color.text_9a9a9a + ).build() + setBadgeSpan( + replyEntity.user, + replyNameSpannable, + replyEntity.user.name!!.length + 1, + replyEntity.user.name!!.length + 2 + ) } else if (replyEntity.user.badge == null && replyEntity.parent.user.badge != null) { replyName = "${replyEntity.user.name} 回复 ${parent.user.name} " - replyNameSpannable = SpanBuilder(replyName).color(mContext, replyEntity.user.name!!.length + 1, replyEntity.user.name!!.length + 4, R.color.text_9a9a9a).build() - setBadgeSpan(parent.user, replyNameSpannable, replyEntity.user.name!!.length + parent.user.name!!.length + 5, replyEntity.user.name!!.length + parent.user.name!!.length + 6) + replyNameSpannable = SpanBuilder(replyName).color( + mContext, + replyEntity.user.name!!.length + 1, + replyEntity.user.name!!.length + 4, + R.color.text_9a9a9a + ).build() + setBadgeSpan( + parent.user, + replyNameSpannable, + replyEntity.user.name!!.length + parent.user.name!!.length + 5, + replyEntity.user.name!!.length + parent.user.name!!.length + 6 + ) } else if (replyEntity.user.badge != null && replyEntity.parent.user.badge != null) { replyName = "${replyEntity.user.name} 回复 ${parent.user.name} " - replyNameSpannable = SpanBuilder(replyName).color(mContext, replyEntity.user.name!!.length + 4, replyEntity.user.name!!.length + 6, R.color.text_9a9a9a).build() - setBadgeSpan(replyEntity.user, replyNameSpannable, replyEntity.user.name!!.length + 1, replyEntity.user.name!!.length + 2) - setBadgeSpan(parent.user, replyNameSpannable, replyEntity.user.name!!.length + parent.user.name!!.length + 8, replyEntity.user.name!!.length + parent.user.name!!.length + 9) + replyNameSpannable = SpanBuilder(replyName).color( + mContext, + replyEntity.user.name!!.length + 4, + replyEntity.user.name!!.length + 6, + R.color.text_9a9a9a + ).build() + setBadgeSpan( + replyEntity.user, + replyNameSpannable, + replyEntity.user.name!!.length + 1, + replyEntity.user.name!!.length + 2 + ) + setBadgeSpan( + parent.user, + replyNameSpannable, + replyEntity.user.name!!.length + parent.user.name!!.length + 8, + replyEntity.user.name!!.length + parent.user.name!!.length + 9 + ) } else { replyName = "${replyEntity.user.name} 回复 ${parent.user.name}" - replyNameSpannable = SpanBuilder(replyName).color(mContext, replyEntity.user.name!!.length + 1, replyEntity.user.name!!.length + 4, R.color.text_9a9a9a).build() + replyNameSpannable = SpanBuilder(replyName).color( + mContext, + replyEntity.user.name!!.length + 1, + replyEntity.user.name!!.length + 4, + R.color.text_9a9a9a + ).build() userName.text = replyNameSpannable } sdvUserBadge.visibility = View.GONE @@ -302,18 +380,29 @@ class RatingReplyAdapter(context: Context, userName.text = replyEntity.user.name if (replyEntity.user.badge != null) { sdvUserBadge.visibility = View.VISIBLE - tvBadgeName.visibility = View.VISIBLE +// tvBadgeName.visibility = View.VISIBLE ImageUtils.display(sdvUserBadge, replyEntity.user.badge.icon) - tvBadgeName.text = replyEntity.user.badge.name +// tvBadgeName.text = replyEntity.user.badge.name } else { sdvUserBadge.visibility = View.GONE tvBadgeName.visibility = View.GONE } } sdvUserBadge.setOnClickListener { - MtaHelper.onEvent("进入徽章墙_用户记录", "游戏评论详情", "${replyEntity.user.name}(${replyEntity.user.id})") - MtaHelper.onEvent("徽章中心", "进入徽章中心", "游戏评论详情") - DirectUtils.directToBadgeWall(mContext, replyEntity.user.id, replyEntity.user.name, replyEntity.user.icon) + DialogUtils.showViewBadgeDialog(mContext, replyEntity.user.badge) { + MtaHelper.onEvent( + "进入徽章墙_用户记录", + "游戏评论详情", + "${replyEntity.user.name}(${replyEntity.user.id})" + ) + MtaHelper.onEvent("徽章中心", "进入徽章中心", "游戏评论详情") + DirectUtils.directToBadgeWall( + mContext, + replyEntity.user.id, + replyEntity.user.name, + replyEntity.user.icon + ) + } } tvBadgeName.setOnClickListener { sdvUserBadge.performClick() } @@ -327,7 +416,8 @@ class RatingReplyAdapter(context: Context, }) } else { viewModel.voteReply(replyEntity.id, false, callback = { - vote.text = if (replyEntity.vote == 0) "" else (replyEntity.vote).toString() + vote.text = + if (replyEntity.vote == 0) "" else (replyEntity.vote).toString() vote.isChecked = false }) } @@ -354,52 +444,97 @@ class RatingReplyAdapter(context: Context, isChildLongClick = false return@setOnClickListener } - OptionDialogHelper.showOptionDialog(mContext, dialogTypeList, callback = { type -> - when (type) { - "复制" -> { - replyEntity.content.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "").copyTextAndToast() - } - "投诉" -> { - mContext.ifLogin("游戏详情-评分-评论详情- 投诉评论") { - OptionDialogHelper.showOptionDialog(mContext, Constants.REPORT_LIST.toList(), callback = { reportType -> - SimpleRequestHelper.reportGameCommentReply( + OptionDialogHelper.showOptionDialog( + mContext, + dialogTypeList, + callback = { type -> + when (type) { + "复制" -> { + replyEntity.content.replace( + RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), + "" + ).copyTextAndToast() + } + "投诉" -> { + mContext.ifLogin("游戏详情-评分-评论详情- 投诉评论") { + DialogUtils.showReportReasonDialog( + mContext, + Constants.REPORT_LIST.toList() as java.util.ArrayList + ) { reason, desc -> + SimpleRequestHelper.reportGameCommentReply( mEntityList[0].game!!.id, mEntityList[1].comment!!.id, - replyEntity.id, reportType) - }) + replyEntity.id, + if (reason != "其他原因") reason else desc + ) + } + } + } + "回复" -> { + replyCallback.invoke(replyEntity) } } - "回复" -> { - replyCallback.invoke(replyEntity) - } - } - }) + }) } content.setOnLongClickListener(View.OnLongClickListener { isChildLongClick = true - replyEntity.content.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "").copyTextAndToast() + replyEntity.content.replace( + RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), + "" + ).copyTextAndToast() return@OnLongClickListener true }) userIcon.setOnClickListener { - DirectUtils.directToHomeActivity(mContext, replyEntity.user.id, entrance, path) + DirectUtils.directToHomeActivity( + mContext, + replyEntity.user.id, + entrance, + path + ) } userName.setOnClickListener { - DirectUtils.directToHomeActivity(mContext, replyEntity.user.id, entrance, path) + DirectUtils.directToHomeActivity( + mContext, + replyEntity.user.id, + entrance, + path + ) } } } is ListSectionItemViewHolder -> { val title = "全部回复 ${mEntityList[position].replyCount}" - holder.sectionTitle.text = SpanBuilder(title).color(5, title.length, "#80333333").build() + holder.sectionTitle.text = + SpanBuilder(title).color(5, title.length, "#80333333").build() holder.sortPositive.setOnClickListener { - holder.sortNegative.setTextColor(ContextCompat.getColor(mContext, R.color.title)) - holder.sortPositive.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font)) + holder.sortNegative.setTextColor( + ContextCompat.getColor( + mContext, + R.color.title + ) + ) + holder.sortPositive.setTextColor( + ContextCompat.getColor( + mContext, + R.color.theme_font + ) + ) viewModel.sortList(RatingReplyViewModel.SORT_POSITIVE) } holder.sortNegative.setOnClickListener { - holder.sortNegative.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font)) - holder.sortPositive.setTextColor(ContextCompat.getColor(mContext, R.color.title)) + holder.sortNegative.setTextColor( + ContextCompat.getColor( + mContext, + R.color.theme_font + ) + ) + holder.sortPositive.setTextColor( + ContextCompat.getColor( + mContext, + R.color.title + ) + ) viewModel.sortList(RatingReplyViewModel.SORT_NEGATION) } } @@ -440,34 +575,44 @@ class RatingReplyAdapter(context: Context, } @SuppressLint("CheckResult") - private fun RatingReplyItemBinding.setBadgeSpan(user: UserEntity, replyNameSpannable: SpannableStringBuilder, startIndex: Int, endIndex: Int) { + private fun RatingReplyItemBinding.setBadgeSpan( + user: UserEntity, + replyNameSpannable: SpannableStringBuilder, + startIndex: Int, + endIndex: Int + ) { Single.just(user.badge?.icon) - .map { - Picasso.with(mContext).load(Uri.parse(it)).priority(Picasso.Priority.HIGH).get() - }.subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ - val bitmapDrawable = BitmapDrawable(mContext.resources, it) - bitmapDrawable.setBounds(0, 0, 16F.dip2px(), 16F.dip2px()) - replyNameSpannable.setSpan(CenterImageSpan(bitmapDrawable), startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) - replyNameSpannable.setSpan(object : ClickableSpan() { - override fun updateDrawState(ds: TextPaint) { - super.updateDrawState(ds) - ds.isUnderlineText = false - } + .map { + Picasso.with(mContext).load(Uri.parse(it)).priority(Picasso.Priority.HIGH).get() + }.subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + val bitmapDrawable = BitmapDrawable(mContext.resources, it) + bitmapDrawable.setBounds(0, 0, 16F.dip2px(), 16F.dip2px()) + replyNameSpannable.setSpan( + CenterImageSpan(bitmapDrawable), + startIndex, + endIndex, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ) + replyNameSpannable.setSpan(object : ClickableSpan() { + override fun updateDrawState(ds: TextPaint) { + super.updateDrawState(ds) + ds.isUnderlineText = false + } - override fun onClick(widget: View) { - MtaHelper.onEvent("进入徽章墙_用户记录", "游戏评论详情", "${user.name}(${user.id})") - MtaHelper.onEvent("徽章中心", "进入徽章中心", "游戏评论详情") - DirectUtils.directToBadgeWall(mContext, user.id, user.name, user.icon) - } + override fun onClick(widget: View) { + MtaHelper.onEvent("进入徽章墙_用户记录", "游戏评论详情", "${user.name}(${user.id})") + MtaHelper.onEvent("徽章中心", "进入徽章中心", "游戏评论详情") + DirectUtils.directToBadgeWall(mContext, user.id, user.name, user.icon) + } - }, startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) - userName.movementMethod = CustomLinkMovementMethod.getInstance() - userName.text = replyNameSpannable - }, { - it.printStackTrace() - }) + }, startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + userName.movementMethod = CustomLinkMovementMethod.getInstance() + userName.text = replyNameSpannable + }, { + it.printStackTrace() + }) } fun handleSyncData(requestCode: Int, intent: Intent?) { @@ -495,6 +640,9 @@ class RatingReplyAdapter(context: Context, return null } - class RatingReplyHeadItemViewHolder(val binding: RatingReplyHeadItemBinding) : BaseRecyclerViewHolder(binding.root) - class RatingReplyItemViewHolder(val binding: RatingReplyItemBinding) : BaseRecyclerViewHolder(binding.root) + class RatingReplyHeadItemViewHolder(val binding: RatingReplyHeadItemBinding) : + BaseRecyclerViewHolder(binding.root) + + class RatingReplyItemViewHolder(val binding: RatingReplyItemBinding) : + BaseRecyclerViewHolder(binding.root) } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt index ae9df24998..81b73d9ae2 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt @@ -362,14 +362,14 @@ class RatingEditActivity : ToolBarActivity(), KeyboardHeightObserver { val apk = mGame?.getApk() if (!apk.isNullOrEmpty()) apk[0].version else "" } else { - PackageUtils.getVersionByPackage(mInstallPackageName) + PackageUtils.getVersionNameByPackageName(mInstallPackageName) } val jsonObject = JSONObject() jsonObject.put("star", rating) jsonObject.put("content", content) jsonObject.put("show_device", mBinding.deviceBox.isChecked) jsonObject.put("device", DeviceUtils.getLoginDevice(this)) - jsonObject.put("gh_version", PackageUtils.getVersionName()) + jsonObject.put("gh_version", PackageUtils.getGhVersionName()) jsonObject.put("game_version", gameVersion) jsonObject.put("source", if (mFromAmway) "anliwall" else "game_detail") jsonObject.put("plugin_version", PackageUtils.getMetaData(this, mInstallPackageName, "gh_version")) diff --git a/app/src/main/java/com/gh/gamecenter/help/QaFeedbackViewModel.kt b/app/src/main/java/com/gh/gamecenter/help/QaFeedbackViewModel.kt index c148968b89..57106bb3e2 100644 --- a/app/src/main/java/com/gh/gamecenter/help/QaFeedbackViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/help/QaFeedbackViewModel.kt @@ -26,7 +26,7 @@ class QaFeedbackViewModel(application: Application, private val contentId: Strin fun qaSuggestions(message: String) { val map = hashMapOf() map["message"] = message - map["ghversion"] = PackageUtils.getVersionName() + map["ghversion"] = PackageUtils.getGhVersionName() map["channel"] = HaloApp.getInstance().channel map["type"] = Build.MODEL map["sdk"] = Build.VERSION.SDK_INT.toString() diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeFragment.kt b/app/src/main/java/com/gh/gamecenter/home/HomeFragment.kt index c1f7987273..87aef93ac2 100644 --- a/app/src/main/java/com/gh/gamecenter/home/HomeFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/home/HomeFragment.kt @@ -13,7 +13,7 @@ import com.gh.common.TimeElapsedHelper import com.gh.common.constant.Constants import com.gh.common.exposure.ExposureListener import com.gh.common.util.* -import com.gh.common.view.FixLinearLayoutManager +import com.gh.common.view.OffsetLinearLayoutManager import com.gh.common.xapk.XapkInstaller import com.gh.common.xapk.XapkUnzipStatus import com.gh.download.DownloadManager @@ -24,6 +24,7 @@ import com.gh.gamecenter.eventbus.EBDownloadStatus import com.gh.gamecenter.eventbus.EBPackage import com.gh.gamecenter.eventbus.EBReuse import com.gh.gamecenter.eventbus.EBUISwitch +import com.gh.gamecenter.fragment.HomeSearchToolWrapperFragment import com.gh.gamecenter.fragment.MainWrapperFragment import com.gh.gamecenter.game.gallery.GameGallerySlideViewHolder import com.gh.gamecenter.home.slide.HomeSlideListAdapter @@ -47,7 +48,7 @@ class HomeFragment : BaseFragment() { private lateinit var mElapsedHelper: TimeElapsedHelper private lateinit var mExposureListener: ExposureListener private lateinit var mScrollCalculatorHelper: ScrollCalculatorHelper - private lateinit var mAutomaticLayoutManager: LinearLayoutManager + private lateinit var mAutomaticLayoutManager: OffsetLinearLayoutManager private val dataWatcher = object : DataWatcher() { override fun onDataChanged(downloadEntity: DownloadEntity) { @@ -76,7 +77,10 @@ class HomeFragment : BaseFragment() { if (it == LoadStatus.INIT_LOADED) { AppExecutor.uiExecutor.executeWithDelay(Runnable { scroll() - mScrollCalculatorHelper.onScrollStateChanged(mBinding.gameList, RecyclerView.SCROLL_STATE_IDLE) + mScrollCalculatorHelper.onScrollStateChanged( + mBinding.gameList, + RecyclerView.SCROLL_STATE_IDLE + ) }, 100) } }) @@ -88,11 +92,20 @@ class HomeFragment : BaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) mBinding = FragmentGameBinding.bind(view) - mBinding.gameRefresh.setColorSchemeColors(ContextCompat.getColor(requireContext(), R.color.theme)) + mBinding.gameRefresh.setColorSchemeColors( + ContextCompat.getColor( + requireContext(), + R.color.theme + ) + ) mBinding.loadStatus = LoadStatus.LIST_LOADED - mAutomaticLayoutManager = FixLinearLayoutManager(requireContext()) + mAutomaticLayoutManager = OffsetLinearLayoutManager(requireContext()) mLayoutManager = mAutomaticLayoutManager - mListAdapter = HomeFragmentAdapter(requireContext(), mViewModel, mLayoutManager) + mListAdapter = HomeFragmentAdapter(requireContext(), mViewModel, mLayoutManager) { + if (parentFragment is HomeSearchToolWrapperFragment) { + (parentFragment as HomeSearchToolWrapperFragment).changeAppBarColor(it) + } + } mExposureListener = ExposureListener(this, mListAdapter) (mBinding.gameList.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false mBinding.gameList.layoutManager = mLayoutManager @@ -103,11 +116,19 @@ class HomeFragment : BaseFragment() { super.onScrollStateChanged(recyclerView, newState) mScrollCalculatorHelper.onScrollStateChanged(mBinding.gameList, newState) if (mLayoutManager.findLastVisibleItemPosition() == mListAdapter.itemCount - 1 - && RecyclerView.SCROLL_STATE_IDLE == newState) mViewModel.getHomeContent(false) + && RecyclerView.SCROLL_STATE_IDLE == newState + ) mViewModel.getHomeContent(false) } override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) + if (parentFragment is HomeSearchToolWrapperFragment) { + val bannerViewHeight = mAutomaticLayoutManager.heightMap[0] ?: 0 + (parentFragment as HomeSearchToolWrapperFragment).onScrollChanged( + bannerViewHeight, + mBinding.gameList.computeVerticalScrollOffset() + ) + } scroll() } }) @@ -128,7 +149,11 @@ class HomeFragment : BaseFragment() { private fun scroll() { val firstVisibleItem = mAutomaticLayoutManager.findFirstVisibleItemPosition() val lastVisibleItem = mAutomaticLayoutManager.findLastVisibleItemPosition() - mScrollCalculatorHelper.onScroll(mViewModel.itemDataList.value, firstVisibleItem, lastVisibleItem) + mScrollCalculatorHelper.onScroll( + mViewModel.itemDataList.value, + firstVisibleItem, + lastVisibleItem + ) } override fun onPause() { @@ -158,24 +183,31 @@ class HomeFragment : BaseFragment() { mScrollCalculatorHelper.currentPlayer?.resetDetailMask() mScrollCalculatorHelper.currentPlayer?.onVideoPause() val currentPosition = mScrollCalculatorHelper.currentPlayer?.getCurrentPosition() ?: 0L - val topVideo = mViewModel.itemDataList.value?.safelyGetInRelease(mScrollCalculatorHelper.currentPosition)?.attachGame?.linkGame?.topVideo + val topVideo = + mViewModel.itemDataList.value?.safelyGetInRelease(mScrollCalculatorHelper.currentPosition)?.attachGame?.linkGame?.topVideo if (topVideo != null) { - ScrollCalculatorHelper.savePlaySchedule(MD5Utils.getContentMD5(topVideo.url), currentPosition) + ScrollCalculatorHelper.savePlaySchedule( + MD5Utils.getContentMD5(topVideo.url), + currentPosition + ) } } } private fun resumeVideo() { if (mScrollCalculatorHelper.currentPlayer != null) { - val topVideo = mViewModel.itemDataList.value?.safelyGetInRelease(mScrollCalculatorHelper.currentPosition)?.attachGame?.linkGame?.topVideo + val topVideo = + mViewModel.itemDataList.value?.safelyGetInRelease(mScrollCalculatorHelper.currentPosition)?.attachGame?.linkGame?.topVideo if (topVideo != null) { - val position = ScrollCalculatorHelper.getPlaySchedule(MD5Utils.getContentMD5(topVideo.url)) + val position = + ScrollCalculatorHelper.getPlaySchedule(MD5Utils.getContentMD5(topVideo.url)) //这里必须要延迟操作,否则会白屏 mBaseHandler.postDelayed({ if (position != 0L) { mScrollCalculatorHelper.currentPlayer?.seekTo(position) mScrollCalculatorHelper.currentPlayer?.onVideoResume(false) - val topVideoVoiceStatus = SPUtils.getBoolean(Constants.SP_VIDEO_PLAY_MUTE, true) + val topVideoVoiceStatus = + SPUtils.getBoolean(Constants.SP_VIDEO_PLAY_MUTE, true) if (topVideoVoiceStatus) { mScrollCalculatorHelper.currentPlayer?.mute() } else { @@ -203,9 +235,11 @@ class HomeFragment : BaseFragment() { if (resumeScroll) adapter.startScroll() else adapter.stopScroll() } - val firstPosition = (mBinding.gameList.layoutManager as? LinearLayoutManager)?.findFirstVisibleItemPosition() + val firstPosition = + (mBinding.gameList.layoutManager as? LinearLayoutManager)?.findFirstVisibleItemPosition() ?: 0 - val lastPosition = (mBinding.gameList.layoutManager as? LinearLayoutManager)?.findLastVisibleItemPosition() + val lastPosition = + (mBinding.gameList.layoutManager as? LinearLayoutManager)?.findLastVisibleItemPosition() ?: 0 for (i in firstPosition..lastPosition) { @@ -243,8 +277,9 @@ class HomeFragment : BaseFragment() { @Subscribe(threadMode = ThreadMode.MAIN) fun onEventMainThread(busNine: EBUISwitch) { if (::mLayoutManager.isInitialized - && MainWrapperFragment.EB_MAIN_SCROLL_TOP == busNine.from - && MainWrapperFragment.INDEX_HOME == busNine.position) { + && MainWrapperFragment.EB_MAIN_SCROLL_TOP == busNine.from + && MainWrapperFragment.INDEX_HOME == busNine.position + ) { mBinding.gameList.stopScroll() mLayoutManager.scrollToPosition(0) mScrollCalculatorHelper.currentPlayer?.release() diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt b/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt index 0a802e66cb..70b6b183e7 100644 --- a/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt @@ -34,12 +34,22 @@ import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder import com.shuyu.gsyvideoplayer.video.base.GSYVideoView import java.util.* -class HomeFragmentAdapter(context: Context, - val viewModel: HomeViewModel, - val layoutManager: LinearLayoutManager) : DiffUtilAdapter(context), IExposable { +class HomeFragmentAdapter( + context: Context, + val viewModel: HomeViewModel, + val layoutManager: LinearLayoutManager, + val callback: (colorStr: Int) -> Unit +) : DiffUtilAdapter(context), IExposable { private var mLoadStatus: LoadStatus? = null - private val mLegacyHomeFragmentAdapterAssistant by lazy { LegacyHomeFragmentAdapterAssistant(mContext, this, mLayoutInflater, mBasicExposureSource) } + private val mLegacyHomeFragmentAdapterAssistant by lazy { + LegacyHomeFragmentAdapterAssistant( + mContext, + this, + mLayoutInflater, + mBasicExposureSource + ) + } private val mBasicExposureSource by lazy { listOf(ExposureSource("新首页", "")) } @@ -95,7 +105,7 @@ class HomeFragmentAdapter(context: Context, return when (viewType) { SLIDE_ITEM -> { view = mLayoutInflater.inflate(R.layout.home_slide_list, parent, false) - HomeSlideListViewHolder(HomeSlideListBinding.bind(view)) + HomeSlideListViewHolder(HomeSlideListBinding.bind(view), callback) } RECOMMENDS_ITEM -> { view = mLayoutInflater.inflate(R.layout.home_recommend_item, parent, false) @@ -122,7 +132,10 @@ class HomeFragmentAdapter(context: Context, ReuseViewHolder(view) } // 原游戏板块样式 - else -> return mLegacyHomeFragmentAdapterAssistant.createLegacyViewHolder(parent, viewType) + else -> return mLegacyHomeFragmentAdapterAssistant.createLegacyViewHolder( + parent, + viewType + ) } } @@ -146,7 +159,11 @@ class HomeFragmentAdapter(context: Context, is ReuseViewHolder -> bindUnknown(holder) is HomeDividerViewHolder -> holder.bindView(mDataList[position].lineDivider ?: 1F) - else -> mLegacyHomeFragmentAdapterAssistant.bindLegacyViewHolder(holder, mDataList[position], position) + else -> mLegacyHomeFragmentAdapterAssistant.bindLegacyViewHolder( + holder, + mDataList[position], + position + ) } } @@ -163,21 +180,38 @@ class HomeFragmentAdapter(context: Context, val exposureList = arrayListOf() for (amway in amwayList) { val event = ExposureEvent.createEventWithSourceConcat( - gameEntity = amway.game.toGameEntity(), - basicSource = mBasicExposureSource, - source = listOf(ExposureSource("安利墙", ""))) + gameEntity = amway.game.toGameEntity(), + basicSource = mBasicExposureSource, + source = listOf(ExposureSource("安利墙", "")) + ) exposureList.add(event) } homeItemData.exposureEventList = exposureList val clickClosure: (View, Int, AmwayCommentEntity) -> Unit = { v, itemPosition, amway -> - MtaHelper.onEvent("首页_新", "点击", "内容" + homeItemData.blockPosition + "_安利墙" + (itemPosition + 1) + "_" + amway.game.name) + MtaHelper.onEvent( + "首页_新", + "点击", + "内容" + homeItemData.blockPosition + "_安利墙" + (itemPosition + 1) + "_" + amway.game.name + ) val path = "(首页安利墙)" if (v.id == R.id.rating_block) { - val intent = RatingReplyActivity.getIntent(mContext, amway.game.id, amway.comment.id, false, path, "") + val intent = RatingReplyActivity.getIntent( + mContext, + amway.game.id, + amway.comment.id, + false, + path, + "" + ) mContext.startActivity(intent) } else { - GameDetailActivity.startGameDetailActivity(mContext, amway.game.id, path, homeItemData.exposureEventList?.safelyGetInRelease(itemPosition)) + GameDetailActivity.startGameDetailActivity( + mContext, + amway.game.id, + path, + homeItemData.exposureEventList?.safelyGetInRelease(itemPosition) + ) } } @@ -192,30 +226,35 @@ class HomeFragmentAdapter(context: Context, holder.bindGame(game) homeItemData.exposureEvent = ExposureEvent.createEventWithSourceConcat( - gameEntity = game, - basicSource = mBasicExposureSource, - source = listOf(ExposureSource("游戏", ""))) + gameEntity = game, + basicSource = mBasicExposureSource, + source = listOf(ExposureSource("游戏", "")) + ) holder.binding.gameBrief.text = homeItemData.attachGame?.recommendText holder.binding.gameImage.visibleIf(!(homeItemData.attachGame?.displayContent == "video" && homeItemData.attachGame?.linkGame?.topVideo != null)) holder.binding.autoVideoView.goneIf(homeItemData.attachGame?.displayContent != "video" || homeItemData.attachGame?.linkGame?.topVideo == null) if (!holder.binding.autoVideoView.isInPlayingState - && homeItemData.attachGame?.displayContent == "video" - && homeItemData.attachGame?.linkGame?.topVideo != null) { + && homeItemData.attachGame?.displayContent == "video" + && homeItemData.attachGame?.linkGame?.topVideo != null + ) { val topVideo = homeItemData.attachGame?.linkGame?.topVideo val homeSetting = homeItemData.attachGame?.linkGame?.homeSetting GSYVideoOptionBuilder() - .setIsTouchWiget(false) - .setUrl(topVideo?.url ?: "") - .setRotateViewAuto(false) - .setCacheWithPlay(true) - .setRotateWithSystem(false) - .setReleaseWhenLossAudio(true) - .setLooping(false) - .setShowFullAnimation(false) - .build(holder.binding.autoVideoView) + .setIsTouchWiget(false) + .setUrl(topVideo?.url ?: "") + .setRotateViewAuto(false) + .setCacheWithPlay(true) + .setRotateWithSystem(false) + .setReleaseWhenLossAudio(true) + .setLooping(false) + .setShowFullAnimation(false) + .build(holder.binding.autoVideoView) holder.binding.autoVideoView.updateThumb(topVideo?.poster ?: "") - holder.binding.autoVideoView.setData(homeItemData.attachGame?.linkGame, homeSetting?.placeholderColor) + holder.binding.autoVideoView.setData( + homeItemData.attachGame?.linkGame, + homeSetting?.placeholderColor + ) holder.binding.autoVideoView.detailBtn?.setOnClickListener { holder.itemView.performClick() holder.binding.autoVideoView.uploadVideoStreamingPlaying("点击遮罩", true) @@ -225,35 +264,63 @@ class HomeFragmentAdapter(context: Context, holder.binding.gameImage.setOnClickListener { if (homeItemData.attachGame?.linkType == "video") { - MtaHelper.onEvent("首页_新", "点击", "内容" + homeItemData.blockPosition + "_" + game.name + "_视频详情") - DirectUtils.directToVideoDetail(mContext, - homeItemData.attachGame?.linkId!!, - VideoDetailContainerViewModel.Location.VIDEO_CHOICENESS.value, - entrance = "(首页-游戏[" + game.name + "])", - path = "新首页-内容管理") + MtaHelper.onEvent( + "首页_新", + "点击", + "内容" + homeItemData.blockPosition + "_" + game.name + "_视频详情" + ) + DirectUtils.directToVideoDetail( + mContext, + homeItemData.attachGame?.linkId!!, + VideoDetailContainerViewModel.Location.VIDEO_CHOICENESS.value, + entrance = "(首页-游戏[" + game.name + "])", + path = "新首页-内容管理" + ) } else { - MtaHelper.onEvent("首页_新", "点击", "内容" + homeItemData.blockPosition + "_" + game.name + "_游戏详情") - GameDetailActivity.startGameDetailActivity(mContext, game.id, "(首页-游戏[" + game.name + "])", homeItemData.exposureEvent) + MtaHelper.onEvent( + "首页_新", + "点击", + "内容" + homeItemData.blockPosition + "_" + game.name + "_游戏详情" + ) + GameDetailActivity.startGameDetailActivity( + mContext, + game.id, + "(首页-游戏[" + game.name + "])", + homeItemData.exposureEvent + ) } } holder.itemView.setOnClickListener { MtaHelper.onEvent("首页_新", "点击", "内容" + homeItemData.blockPosition + "_" + game.name) - GameDetailActivity.startGameDetailActivity(mContext, game.id, "(首页-游戏[" + game.name + "])", homeItemData.exposureEvent) + GameDetailActivity.startGameDetailActivity( + mContext, + game.id, + "(首页-游戏[" + game.name + "])", + homeItemData.exposureEvent + ) if (holder.binding.autoVideoView.isInPlayingState) { - holder.binding.autoVideoView.uploadVideoStreamingPlaying("游戏详情-播放点击", holder.binding.autoVideoView.detailBtn?.visibility == View.VISIBLE) + holder.binding.autoVideoView.uploadVideoStreamingPlaying( + "游戏详情-播放点击", + holder.binding.autoVideoView.detailBtn?.visibility == View.VISIBLE + ) } else { if (holder.binding.autoVideoView.currentState == GSYVideoView.CURRENT_STATE_AUTO_COMPLETE) { - holder.binding.autoVideoView.uploadVideoStreamingPlaying("游戏详情-完播点击", holder.binding.autoVideoView.detailBtn?.visibility == View.VISIBLE) + holder.binding.autoVideoView.uploadVideoStreamingPlaying( + "游戏详情-完播点击", + holder.binding.autoVideoView.detailBtn?.visibility == View.VISIBLE + ) } } } } private fun bindFooterView(holder: FooterViewHolder) { - holder.initFooterViewHolder(mLoadStatus == LoadStatus.LIST_LOADING, - mLoadStatus == LoadStatus.LIST_FAILED, - mLoadStatus == LoadStatus.LIST_OVER, - R.string.load_over_with_click_hint) { + holder.initFooterViewHolder( + mLoadStatus == LoadStatus.LIST_LOADING, + mLoadStatus == LoadStatus.LIST_FAILED, + mLoadStatus == LoadStatus.LIST_OVER, + R.string.load_over_with_click_hint + ) { if (mLoadStatus == LoadStatus.LIST_OVER) { layoutManager.scrollToPosition(0) } else if (mLoadStatus == LoadStatus.LIST_FAILED) { @@ -271,8 +338,9 @@ class HomeFragmentAdapter(context: Context, entryMap[download.platform] = download } if (getItemViewType(gameAndPosition.position) == ItemViewType.VERTICAL_SLIDE_ITEM || - getItemViewType(gameAndPosition.position) == ItemViewType.GAME_PLUGIN || - getItemViewType(gameAndPosition.position) == SLIDE_ITEM) { + getItemViewType(gameAndPosition.position) == ItemViewType.GAME_PLUGIN || + getItemViewType(gameAndPosition.position) == SLIDE_ITEM + ) { val view = layoutManager.findViewByPosition(gameAndPosition.position) val recyclerView = view?.findViewById(R.id.recycler_view) when (val adapter = recyclerView?.adapter) { @@ -298,8 +366,9 @@ class HomeFragmentAdapter(context: Context, fun notifyChildItem(position: Int) { if (getItemViewType(position) == ItemViewType.VERTICAL_SLIDE_ITEM || - getItemViewType(position) == ItemViewType.GAME_PLUGIN || - getItemViewType(position) == SLIDE_ITEM) { + getItemViewType(position) == ItemViewType.GAME_PLUGIN || + getItemViewType(position) == SLIDE_ITEM + ) { val view = layoutManager.findViewByPosition(position) val recyclerView = view?.findViewById(R.id.recycler_view) recyclerView?.adapter?.notifyDataSetChanged() @@ -341,7 +410,12 @@ class HomeFragmentAdapter(context: Context, } // 原游戏板块样式 - mLegacyHomeFragmentAdapterAssistant.getLegacyGameEntityByPackage(positionList, itemData, packageName, position) + mLegacyHomeFragmentAdapterAssistant.getLegacyGameEntityByPackage( + positionList, + itemData, + packageName, + position + ) } } return positionList @@ -355,7 +429,8 @@ class HomeFragmentAdapter(context: Context, return mDataList[pos].exposureEventList } - class HomeDividerViewHolder(var binding: HomeDividerItemBinding) : RecyclerView.ViewHolder(binding.root) { + class HomeDividerViewHolder(var binding: HomeDividerItemBinding) : + RecyclerView.ViewHolder(binding.root) { fun bindView(height: Float) { val lp = binding.container.layoutParams lp.height = height.dip2px() diff --git a/app/src/main/java/com/gh/gamecenter/home/slide/HomeSlideListViewHolder.kt b/app/src/main/java/com/gh/gamecenter/home/slide/HomeSlideListViewHolder.kt index f15576ad32..0ee49dc962 100644 --- a/app/src/main/java/com/gh/gamecenter/home/slide/HomeSlideListViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/home/slide/HomeSlideListViewHolder.kt @@ -1,21 +1,32 @@ package com.gh.gamecenter.home.slide import android.annotation.SuppressLint +import android.graphics.Color +import android.graphics.drawable.GradientDrawable import android.view.MotionEvent +import androidx.core.graphics.ColorUtils import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.PagerSnapHelper import androidx.recyclerview.widget.RecyclerView +import androidx.viewpager2.widget.ViewPager2 import com.gh.base.BaseRecyclerViewHolder import com.gh.common.exposure.ExposureSource import com.gh.common.util.MtaHelper +import com.gh.common.util.hexStringToIntColor import com.gh.common.util.throwExceptionInDebug +import com.gh.common.view.DrawableView import com.gh.common.view.FixLinearLayoutManager +import com.gh.common.view.ScrollEventListener import com.gh.common.view.TouchSlopRecyclerView import com.gh.gamecenter.databinding.HomeSlideListBinding import com.gh.gamecenter.home.HomeItemData import kotlin.math.abs -class HomeSlideListViewHolder(val binding: HomeSlideListBinding) : BaseRecyclerViewHolder(binding.root) { +class HomeSlideListViewHolder( + val binding: HomeSlideListBinding, + val callback: (colorStr: Int) -> Unit +) : + BaseRecyclerViewHolder(binding.root) { private var mLastX: Int = 0 private var mLastY: Int = 0 @@ -39,7 +50,14 @@ class HomeSlideListViewHolder(val binding: HomeSlideListBinding) : BaseRecyclerV val snapHelper = PagerSnapHelper() val layoutManager = FixLinearLayoutManager(context, RecyclerView.HORIZONTAL, false) - adapter = HomeSlideListAdapter(context, itemData, layoutManager, snapHelper, binding.recyclerView, basicExposureSource) + adapter = HomeSlideListAdapter( + context, + itemData, + layoutManager, + snapHelper, + binding.recyclerView, + basicExposureSource + ) (binding.recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false binding.recyclerView.layoutManager = layoutManager binding.recyclerView.adapter = adapter @@ -47,7 +65,8 @@ class HomeSlideListViewHolder(val binding: HomeSlideListBinding) : BaseRecyclerV binding.recyclerView.isNestedScrollingEnabled = false binding.recyclerView.scrollToPosition(adapter.getActualFirstPositionInCenter()) snapHelper.attachToRecyclerView(binding.recyclerView) - binding.recyclerView.addOnItemTouchListener(object : RecyclerView.SimpleOnItemTouchListener() { + binding.recyclerView.addOnItemTouchListener(object : + RecyclerView.SimpleOnItemTouchListener() { override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean { val x = e.x.toInt() val y = e.y.toInt() @@ -58,7 +77,9 @@ class HomeSlideListViewHolder(val binding: HomeSlideListBinding) : BaseRecyclerV mLastY = e.y.toInt() rv.parent.parent.requestDisallowInterceptTouchEvent(true) } - MotionEvent.ACTION_UP -> rv.parent.parent.requestDisallowInterceptTouchEvent(false) + MotionEvent.ACTION_UP -> rv.parent.parent.requestDisallowInterceptTouchEvent( + false + ) MotionEvent.ACTION_MOVE -> { val deltaX: Int = x - mLastX val deltaY: Int = y - mLastY @@ -67,7 +88,8 @@ class HomeSlideListViewHolder(val binding: HomeSlideListBinding) : BaseRecyclerV } } - val isStop = e.action == MotionEvent.ACTION_DOWN || e.action == MotionEvent.ACTION_MOVE + val isStop = + e.action == MotionEvent.ACTION_DOWN || e.action == MotionEvent.ACTION_MOVE if (isStop) adapter.stopScroll() else adapter.startScroll() val touchSlopRecyclerView = binding.recyclerView.parent.parent @@ -77,35 +99,68 @@ class HomeSlideListViewHolder(val binding: HomeSlideListBinding) : BaseRecyclerV return false } }) + updateImmersiveColor(slideList[0].placeholderColor.hexStringToIntColor()) - binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { - var lastStatePosition = -1 - var lastScrollState = RecyclerView.SCROLL_STATE_IDLE + binding.recyclerView.addOnScrollListener(ScrollEventListener(binding.recyclerView).apply { + setOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + var lastStatePosition = -1 + var lastScrollState = RecyclerView.SCROLL_STATE_IDLE - override fun onScrollStateChanged(recyclerView: RecyclerView, scrollState: Int) { - // MTA 统计 - if (scrollState == RecyclerView.SCROLL_STATE_IDLE) { - val view = snapHelper.findSnapView(layoutManager) - var curPosition = 0 - if (view != null) { - curPosition = adapter.getActualPosition(layoutManager.getPosition(view)) + override fun onPageScrollStateChanged(state: Int) { + super.onPageScrollStateChanged(state) + + if (scrollState == RecyclerView.SCROLL_STATE_IDLE) { + val view = snapHelper.findSnapView(layoutManager) + var curPosition = 0 + if (view != null) { + curPosition = adapter.getActualPosition(layoutManager.getPosition(view)) + } + if (lastScrollState == RecyclerView.SCROLL_STATE_DRAGGING && curPosition != lastStatePosition) { + MtaHelper.onEvent( + "首页_新", + "轮播_滑动", + if (curPosition > lastStatePosition) "左滑" else "右滑" + ) + } + lastStatePosition = curPosition + lastScrollState = scrollState + updateImmersiveColor(slideList[curPosition].placeholderColor.hexStringToIntColor()) + } else if (scrollState == RecyclerView.SCROLL_STATE_DRAGGING) { + lastScrollState = scrollState } - if (lastScrollState == RecyclerView.SCROLL_STATE_DRAGGING && curPosition != lastStatePosition) { - MtaHelper.onEvent("首页_新", "轮播_滑动", if (curPosition > lastStatePosition) "左滑" else "右滑") - } - lastStatePosition = curPosition - lastScrollState = scrollState - } else if (scrollState == RecyclerView.SCROLL_STATE_DRAGGING) { - lastScrollState = scrollState } - } - override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - updateZoomAnimation() - } + override fun onPageScrolled( + position: Int, + positionOffset: Float, + positionOffsetPixels: Int + ) { + val currentPosition = adapter.getActualPosition(position) + val nextPosition = adapter.getActualPosition(position + 1) + + val currentColor = + slideList[currentPosition].placeholderColor.hexStringToIntColor() + val nextColor = slideList[nextPosition].placeholderColor.hexStringToIntColor() + + val colorInBetween = + ColorUtils.blendARGB(currentColor, nextColor, positionOffset) + + updateZoomAnimation() + updateImmersiveColor(colorInBetween) + } + }) }) } + private fun updateImmersiveColor(color: Int) { + callback.invoke(color) + val gradientDrawable = DrawableView.getGradientDrawable( + color, + Color.WHITE, GradientDrawable.Orientation.TOP_BOTTOM, 0f + ) + binding.placeholderView.background = gradientDrawable + } + // 缩放控制 fun updateZoomAnimation() { val childCount = binding.recyclerView.childCount diff --git a/app/src/main/java/com/gh/gamecenter/libao/Libao2Fragment.java b/app/src/main/java/com/gh/gamecenter/libao/Libao2Fragment.java index 35245e40ab..e18179d75b 100644 --- a/app/src/main/java/com/gh/gamecenter/libao/Libao2Fragment.java +++ b/app/src/main/java/com/gh/gamecenter/libao/Libao2Fragment.java @@ -220,7 +220,7 @@ public class Libao2Fragment extends BaseFragment implements SwipeRefreshLayout.O default: LibaoEntity libaoEntity = (LibaoEntity) data; adapter.setSkipPosition(position); - intent = LibaoDetailActivity.getIntent(getContext(), libaoEntity, view.getId() == R.id.libao_btn_status, mEntrance + "+(礼包中心:关注)"); + intent = LibaoDetailActivity.getIntent(getContext(), libaoEntity, false, mEntrance + "+(礼包中心:关注)"); startActivityForResult(intent, LIBAO_CONCERN_REQUEST); break; } diff --git a/app/src/main/java/com/gh/gamecenter/libao/Libao2FragmentAdapter.java b/app/src/main/java/com/gh/gamecenter/libao/Libao2FragmentAdapter.java index ee7bdb0d40..db0ac554a4 100644 --- a/app/src/main/java/com/gh/gamecenter/libao/Libao2FragmentAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/libao/Libao2FragmentAdapter.java @@ -226,8 +226,13 @@ class Libao2FragmentAdapter extends BaseRecyclerAdapter { holder.libaoDes.setText(content); if (libaoEntity.getStatus() != null) { -// LibaoUtils.initLibaoBtn(mContext, holder.libaoBtnStatus, libaoEntity, false, null, true,mEntrance + "+(礼包中心:关注)"); - LibaoUtils.setLiBaoBtnStatusRound(holder.libaoBtnStatus, libaoEntity, true, mContext); + LibaoUtils.initLibaoBtn(mContext, holder.libaoBtnStatus, libaoEntity, false, null, true, mEntrance + "+(礼包中心:关注)", new LibaoUtils.OnLibaoStatusChangeListener() { + @Override + public void onLibaoStatusChange() { + notifyItemChanged(position); + } + }); +// LibaoUtils.setLiBaoBtnStatusRound(holder.libaoBtnStatus, libaoEntity, true, mContext); } } diff --git a/app/src/main/java/com/gh/gamecenter/libao/LibaoNewAdapter.kt b/app/src/main/java/com/gh/gamecenter/libao/LibaoNewAdapter.kt index cd8836dba8..18b8de5730 100644 --- a/app/src/main/java/com/gh/gamecenter/libao/LibaoNewAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/libao/LibaoNewAdapter.kt @@ -201,9 +201,11 @@ class LibaoNewAdapter(context: Context, callBackListener: OnRequestCallBackListe holder.libaoDes.text = content if (libaoEntity.status != null) { -// LibaoUtils.initLibaoBtn(mContext, holder.libaoBtnStatus, libaoEntity, false, null, true, -// mEntrance + "+(礼包中心:最新)") - LibaoUtils.setLiBaoBtnStatusRound(holder.libaoBtnStatus, libaoEntity, true, mContext) + LibaoUtils.initLibaoBtn(mContext, holder.libaoBtnStatus, libaoEntity, false, null, true, + mEntrance + "+(礼包中心:最新)"){ + notifyItemChanged(position) + } +// LibaoUtils.setLiBaoBtnStatusRound(holder.libaoBtnStatus, libaoEntity, true, mContext) } } diff --git a/app/src/main/java/com/gh/gamecenter/libao/LibaoNewFragment.java b/app/src/main/java/com/gh/gamecenter/libao/LibaoNewFragment.java index 9001473575..07738f8474 100644 --- a/app/src/main/java/com/gh/gamecenter/libao/LibaoNewFragment.java +++ b/app/src/main/java/com/gh/gamecenter/libao/LibaoNewFragment.java @@ -283,7 +283,7 @@ public class LibaoNewFragment extends BaseFragment implements SwipeRefreshLayout super.onListClick(view, position, data); LibaoEntity libaoEntity = (LibaoEntity) data; mAdapter.setSkipPosition(position); - Intent intent = LibaoDetailActivity.getIntent(getContext(), libaoEntity, view.getId() == R.id.libao_btn_status, mEntrance + "+(礼包中心:最新)"); + Intent intent = LibaoDetailActivity.getIntent(getContext(), libaoEntity, false, mEntrance + "+(礼包中心:最新)"); startActivityForResult(intent, LIBAO_NEW_REQUEST); } } diff --git a/app/src/main/java/com/gh/gamecenter/libao/LibaoSearchAdapter.kt b/app/src/main/java/com/gh/gamecenter/libao/LibaoSearchAdapter.kt index 4791a4489b..22b3a013fe 100644 --- a/app/src/main/java/com/gh/gamecenter/libao/LibaoSearchAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/libao/LibaoSearchAdapter.kt @@ -216,7 +216,9 @@ class LibaoSearchAdapter(fragment: LibaoSearchFragment, if (libaoEntity.status != null) { LibaoUtils.initLibaoBtn(mContext, holder.libaoBtnStatus, libaoEntity, false, null,false, - mEntrance + "+(礼包中心:最新)") + mEntrance + "+(礼包中心:最新)"){ + notifyItemChanged(position) + } } holder.libaoBtnStatus.isClickable = false } diff --git a/app/src/main/java/com/gh/gamecenter/manager/DataCollectionManager.java b/app/src/main/java/com/gh/gamecenter/manager/DataCollectionManager.java index 7d6bba7624..924aac3127 100644 --- a/app/src/main/java/com/gh/gamecenter/manager/DataCollectionManager.java +++ b/app/src/main/java/com/gh/gamecenter/manager/DataCollectionManager.java @@ -52,7 +52,7 @@ public class DataCollectionManager { * 实时上传 */ private void realTimeUpload(final String type, Map map) { - String version = PackageUtils.getVersionName(); + String version = PackageUtils.getGhVersionName(); String user = Installation.getUUID(mContext); String channel = HaloApp.getInstance().getChannel(); map.put("version", version); @@ -123,7 +123,7 @@ public class DataCollectionManager { return; } isUploading = true; - String version = PackageUtils.getVersionName(); + String version = PackageUtils.getGhVersionName(); String user = Installation.getUUID(mContext); String channel = HaloApp.getInstance().getChannel(); for (DataCollectionInfo dataCollectionInfo : list) { diff --git a/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java b/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java index 08fb7bd43a..f914863adc 100644 --- a/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java +++ b/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java @@ -209,11 +209,11 @@ public class UpdateManager { loadingDialog = DialogUtils.showWaitDialog(mContext, "检查更新中..."); } String channel = HaloApp.getInstance().getChannel(); - RetrofitManager.getInstance(mContext).getApi().getUpdate(PackageUtils.getVersionName(), PackageUtils.getVersionCode(), channel) + RetrofitManager.getInstance(mContext).getApi().getUpdate(PackageUtils.getGhVersionName(), PackageUtils.getGhVersionCode(), channel) .map(appEntity -> { boolean isShowUpdateDialog = false; - if (appEntity.getVersionCode() > PackageUtils.getVersionCode()) { + if (appEntity.getVersionCode() > PackageUtils.getGhVersionCode()) { // 助手有更新 UpdateManager.this.appEntity = appEntity; @@ -554,11 +554,11 @@ public class UpdateManager { } private String getUpdateOnceOnlySpKey() { - return "UPDATE_ONCE_ONLY_KEY" + PackageUtils.getVersionCode(); + return "UPDATE_ONCE_ONLY_KEY" + PackageUtils.getGhVersionCode(); } private String getUpdateOnceOnlySecondSpKey() { - return "UPDATE_ONCE_ONLY_SECOND_KEY" + PackageUtils.getVersionCode(); + return "UPDATE_ONCE_ONLY_SECOND_KEY" + PackageUtils.getGhVersionCode(); } } diff --git a/app/src/main/java/com/gh/gamecenter/mygame/MyFollowedGameAdapter.kt b/app/src/main/java/com/gh/gamecenter/mygame/MyFollowedGameAdapter.kt index 0081ebf127..567f86c876 100644 --- a/app/src/main/java/com/gh/gamecenter/mygame/MyFollowedGameAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/mygame/MyFollowedGameAdapter.kt @@ -62,7 +62,6 @@ class MyFollowedGameAdapter(context: Context, var mViewModel: MyFollowedGameView holder.run { binding.run { gameItemIncluded.game = gameEntity - gameItemIncluded.hideSize = true moreBtn.visibility = View.GONE initServerType(gameEntity) initShortcut(gameEntity, mEntrance, path,newPath) diff --git a/app/src/main/java/com/gh/gamecenter/mygame/MyFollowedGameViewModel.kt b/app/src/main/java/com/gh/gamecenter/mygame/MyFollowedGameViewModel.kt index 64f74940ee..434f672f56 100644 --- a/app/src/main/java/com/gh/gamecenter/mygame/MyFollowedGameViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/mygame/MyFollowedGameViewModel.kt @@ -29,6 +29,7 @@ class MyFollowedGameViewModel(application: Application) override fun mergeResultLiveData() { mResultLiveData.addSource(mListLiveData) { + it.forEach { game -> game.hideSizeInsideDes = true } mResultLiveData.postValue(it) } } diff --git a/app/src/main/java/com/gh/gamecenter/mygame/MyReservationAdapter.kt b/app/src/main/java/com/gh/gamecenter/mygame/MyReservationAdapter.kt index 80b50b9de5..bbc62d301e 100644 --- a/app/src/main/java/com/gh/gamecenter/mygame/MyReservationAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/mygame/MyReservationAdapter.kt @@ -15,7 +15,6 @@ import com.gh.gamecenter.R import com.gh.gamecenter.adapter.viewholder.FooterViewHolder import com.gh.gamecenter.adapter.viewholder.GameViewHolder import com.gh.gamecenter.baselist.ListAdapter -import com.gh.gamecenter.baselist.LoadType import com.gh.gamecenter.databinding.ItemFollowedGameBinding import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.eventbus.EBDownloadStatus @@ -58,7 +57,6 @@ class MyReservationAdapter(context: Context, var mViewModel: MyReservationViewMo val newPath = "预约Tab_新" holder.binding.gameItemIncluded.game = gameEntity - holder.binding.gameItemIncluded.hideSize = true holder.initServerType(gameEntity) holder.initShortcut(gameEntity, mEntrance, path, newPath) holder.binding.executePendingBindings() diff --git a/app/src/main/java/com/gh/gamecenter/mygame/MyReservationViewModel.kt b/app/src/main/java/com/gh/gamecenter/mygame/MyReservationViewModel.kt index ba53e4273c..9d2ab213cb 100644 --- a/app/src/main/java/com/gh/gamecenter/mygame/MyReservationViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/mygame/MyReservationViewModel.kt @@ -4,7 +4,6 @@ import android.annotation.SuppressLint import android.app.Application import com.gh.common.repository.ReservationRepository import com.gh.common.runOnUiThread -import com.gh.common.util.MtaHelper import com.gh.common.util.createRequestBody import com.gh.download.DownloadManager import com.gh.gamecenter.baselist.ListViewModel @@ -37,6 +36,7 @@ class MyReservationViewModel(application: Application) : ListViewModel + gameEntity.hideSizeInsideDes = true addGamePositionAndPackage(gameEntity, index) } mResultLiveData.postValue(it) diff --git a/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameAdapter.kt b/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameAdapter.kt index f042f245c2..1acd25a705 100644 --- a/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameAdapter.kt @@ -30,7 +30,6 @@ import com.gh.gamecenter.adapter.viewholder.FooterViewHolder import com.gh.gamecenter.adapter.viewholder.GameViewHolder import com.gh.gamecenter.adapter.viewholder.ReuseViewHolder import com.gh.gamecenter.baselist.ListAdapter -import com.gh.gamecenter.baselist.LoadType import com.gh.gamecenter.databinding.ItemPlayedGameBinding import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.eventbus.EBDownloadStatus @@ -102,7 +101,6 @@ open class PlayedGameAdapter(context: Context, if (mIsMyPlayedGame) { holder.initDownloadButtonOffset() } - holder.binding.gameItemIncluded.hideSize = true holder.binding.gameItemIncluded.game = gameEntity holder.binding.executePendingBindings() diff --git a/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameViewModel.kt b/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameViewModel.kt index 02bf110a82..c3193b6dac 100644 --- a/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameViewModel.kt @@ -28,7 +28,10 @@ class PlayedGameViewModel(application: Application, var userId: String) } override fun mergeResultLiveData() { - mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) } + mResultLiveData.addSource(mListLiveData) { + it.forEach { game -> game.hideSizeInsideDes = true } + mResultLiveData.postValue(it) + } } @SuppressLint("CheckResult") diff --git a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt index 85d7f81493..1a3e64e588 100644 --- a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt +++ b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt @@ -1,7 +1,6 @@ package com.gh.gamecenter.packagehelper import android.annotation.SuppressLint -import android.preference.PreferenceManager import android.text.TextUtils import androidx.lifecycle.MutableLiveData import com.gh.common.exposure.meta.MetaUtil @@ -48,7 +47,6 @@ object PackageRepository { private val mApplication = HaloApp.getInstance().application private val mApi = RetrofitManager.getInstance(mApplication).api private val mSensitiveApi = RetrofitManager.getInstance(mApplication).sensitiveApi - private val mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mApplication) private const val LAST_UPLOAD_APPLIST_TIME = "last_upload_applist_time" @@ -59,6 +57,7 @@ object PackageRepository { val gameInstalled = Collections.synchronizedList(ArrayList()) val gameUpdate = ArrayList() + val currentVersionList = ArrayList() // 当前版本游戏的列表 init { initData() @@ -83,7 +82,7 @@ object PackageRepository { mInstalledPkgList.addAll(list) notifyInstallPkgData() - loadInstalledGameDigestAndNotifyData(list) + loadInstalledGameDigestAndNotifyData(list, true) loadGhzsUpdate() } } @@ -92,12 +91,12 @@ object PackageRepository { * 把助手更新数据添加到下载管理(为了不改变原有的更新逻辑只能在这里多请求一次接口) */ private fun loadGhzsUpdate() { - mApi.getUpdate(PackageUtils.getVersionName(), PackageUtils.getVersionCode(), HaloApp.getInstance().channel) + mApi.getUpdate(PackageUtils.getGhVersionName(), PackageUtils.getGhVersionCode(), HaloApp.getInstance().channel) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Response() { override fun onResponse(appEntity: AppEntity?) { - if (appEntity != null && appEntity.versionCode > PackageUtils.getVersionCode()) { + if (appEntity != null && appEntity.versionCode > PackageUtils.getGhVersionCode()) { val gameUpdateEntity = GameUpdateEntity() gameUpdateEntity.name = "光环助手V" + appEntity.version!! gameUpdateEntity.packageName = HaloApp.getInstance().application.packageName @@ -207,6 +206,7 @@ object PackageRepository { gameInstalled.add(GameInstall.transformGameInstall(game, pkgName)) val isCanPluggable = checkGamePlugin(game, pkgName) val isCanUpdate = checkGameUpdate(game) + addCurrentlyInstalledVersionIfValid(game) if (!isNotifyUpdate && isCanUpdate || isCanPluggable) { isNotifyUpdate = true } @@ -239,6 +239,39 @@ object PackageRepository { return false } + /** + * 添加当前版本的信息如果满足条件的话 + */ + private fun addCurrentlyInstalledVersionIfValid(game: GameEntity) { + for (apk in game.getApk()) { + if (apk.version == PackageUtils.getVersionNameByPackageName(apk.packageName) + && (TextUtils.isEmpty(apk.signature) + || apk.signature == PackageUtils.getApkSignatureByPackageName(mApplication, apk.packageName))) { + currentVersionList.add(GameUpdateEntity().apply { + id = game.id + name = game.name + icon = game.icon + packageName = apk.packageName + size = apk.size + version = apk.version + ghVersion = apk.ghVersion + url = apk.url + platform = apk.getPlatform() + etag = apk.etag + brief = game.brief + tag = game.getTag() + tagStyle = game.tagStyle + indexPlugin = game.indexPlugin + pluginDesc = game.pluginDesc + format = apk.format + signature = apk.signature ?: "" + currentVersion = PackageUtils.getVersionNameByPackageName(apk.packageName) + category = game.category + }) + } + } + } + /** * 检查游戏插件化 * @param game @@ -251,6 +284,11 @@ object PackageRepository { for (apk in apkList) { if (apk.packageName == installedPkgName && !TextUtils.isEmpty(apk.ghVersion) && !PackageUtils.isSignedByGh(HaloApp.getInstance().application, apk.packageName)) { + // 使用了镜像的游戏无需插件化 + if (game.shouldUseMirrorInfo()) { + return false + } + // 如果该包是合集且安装了合集内任意一个光环的游戏包都不显示插件化 game.collection.forEach { collection -> if (collection.packages.contains(apk.packageName)) { diff --git a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageViewModel.kt b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageViewModel.kt index 83ed7fcc30..d6a37c8fbe 100644 --- a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageViewModel.kt @@ -6,7 +6,9 @@ import androidx.lifecycle.* import com.gh.gamecenter.entity.GameInstall import com.gh.gamecenter.entity.GameUpdateEntity import com.halo.assistant.HaloApp -import java.util.HashMap +import java.util.* +import kotlin.collections.ArrayList +import kotlin.collections.set class PackageViewModel(application: Application, @@ -30,10 +32,33 @@ class PackageViewModel(application: Application, } } + /** + * 获取可更新列表的 LiveData(不过滤同包名) + */ fun getGameUpdateLiveData(): MutableLiveData> { return mRepository.gameUpdateLiveData } + /** + * 获取可更新列表的 LiveData(数据包括当前版本,供下载管理-更新显示我的版本用) + */ + fun getGameUpdateIncludeCurrentVersion(): MutableLiveData> { + val mediatorLiveData = MediatorLiveData>() + mediatorLiveData.addSource(mRepository.gameUpdateLiveData) { + val decoratedList = ArrayList(it) + + if (decoratedList.isNotEmpty()) { + for (currentVersion in mRepository.currentVersionList) { + decoratedList.add(currentVersion) + } + } + + mediatorLiveData.postValue(decoratedList) + } + + return mediatorLiveData + } + fun getGameInstalledLiveData(): MutableLiveData> { return mRepository.gameInstalledLiveData } diff --git a/app/src/main/java/com/gh/gamecenter/personal/NewPersonalFragment.java b/app/src/main/java/com/gh/gamecenter/personal/NewPersonalFragment.java deleted file mode 100644 index c799703a24..0000000000 --- a/app/src/main/java/com/gh/gamecenter/personal/NewPersonalFragment.java +++ /dev/null @@ -1,788 +0,0 @@ -package com.gh.gamecenter.personal; - -import android.annotation.SuppressLint; -import android.content.Intent; -import android.os.Build; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewStub; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import androidx.annotation.Nullable; -import androidx.appcompat.widget.Toolbar; -import androidx.core.content.ContextCompat; -import androidx.lifecycle.ViewModelProviders; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; - -import com.facebook.drawee.view.SimpleDraweeView; -import com.gh.base.fragment.BaseLazyFragment; -import com.gh.common.databind.BindingAdapters; -import com.gh.common.notifier.Notifier; -import com.gh.common.util.CheckLoginUtils; -import com.gh.common.util.DataUtils; -import com.gh.common.util.DialogUtils; -import com.gh.common.util.DirectUtils; -import com.gh.common.util.DisplayUtils; -import com.gh.common.util.EntranceUtils; -import com.gh.common.util.ImageUtils; -import com.gh.common.util.IntegralLogHelper; -import com.gh.common.util.LogUtils; -import com.gh.common.util.LoginHelper; -import com.gh.common.util.MtaHelper; -import com.gh.common.util.NetworkUtils; -import com.gh.common.util.PackageUtils; -import com.gh.common.util.SPUtils; -import com.gh.common.util.StringUtils; -import com.gh.common.util.TimeUtils; -import com.gh.common.util.ToastUtils; -import com.gh.common.view.AvatarBorderView; -import com.gh.common.view.SpacingItemDecoration; -import com.gh.gamecenter.GameDetailActivity; -import com.gh.gamecenter.MainActivity; -import com.gh.gamecenter.MessageActivity; -import com.gh.gamecenter.NewsDetailActivity; -import com.gh.gamecenter.R; -import com.gh.gamecenter.entity.AppEntity; -import com.gh.gamecenter.entity.Badge; -import com.gh.gamecenter.entity.BadgeEntity; -import com.gh.gamecenter.entity.FunctionalGroupEntity; -import com.gh.gamecenter.entity.FunctionalLinkEntity; -import com.gh.gamecenter.entity.FunctionalMessageType; -import com.gh.gamecenter.entity.LinkEntity; -import com.gh.gamecenter.entity.LoginTokenEntity; -import com.gh.gamecenter.entity.MessageUnreadEntity; -import com.gh.gamecenter.entity.SignEntity; -import com.gh.gamecenter.entity.UserInfoEntity; -import com.gh.gamecenter.eventbus.EBConcernChanged; -import com.gh.gamecenter.eventbus.EBNetworkState; -import com.gh.gamecenter.eventbus.EBReuse; -import com.gh.gamecenter.eventbus.EBSkip; -import com.gh.gamecenter.fragment.MainWrapperFragment; -import com.gh.gamecenter.energy.EnergyCenterActivity; -import com.gh.gamecenter.energy.EnergyHouseActivity; -import com.gh.gamecenter.manager.UserManager; -import com.gh.gamecenter.message.MessageUnreadRepository; -import com.gh.gamecenter.message.MessageUnreadViewModel; -import com.gh.gamecenter.personalhome.UserHomeViewModel; -import com.gh.gamecenter.qa.answer.detail.SimpleAnswerDetailActivity; -import com.gh.gamecenter.retrofit.BiResponse; -import com.gh.gamecenter.retrofit.Response; -import com.gh.gamecenter.retrofit.RetrofitManager; -import com.gh.gamecenter.room.AppDatabase; -import com.gh.gamecenter.subject.SubjectActivity; -import com.gh.gamecenter.user.UserViewModel; -import com.google.android.material.appbar.AppBarLayout; -import com.halo.assistant.HaloApp; -import com.lightgame.utils.Utils; -import com.tencent.connect.common.Constants; - -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; -import org.jetbrains.annotations.NotNull; -import org.json.JSONObject; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Locale; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import okhttp3.MediaType; -import okhttp3.RequestBody; -import okhttp3.ResponseBody; - -public class NewPersonalFragment extends BaseLazyFragment { - - @BindView(R.id.list_refresh) - SwipeRefreshLayout mListRefresh; - @BindView(R.id.appbar) - AppBarLayout appbar; - @BindView(R.id.toolbar) - Toolbar toolbar; - @BindView(R.id.personal_msg) - ImageView mPersonalMsg; - @BindView(R.id.login_message_hint) - TextView mLoginMessageHint; - @BindView(R.id.personal_user_icon) - AvatarBorderView mUserIcon; - @BindView(R.id.personal_user_small_icon) - SimpleDraweeView mUserIconSmall; - // @BindView(R.id.personal_user_badge) -// SimpleDraweeView mUserBadge; - @BindView(R.id.personal_login) - View mPersonalLogin; - @BindView(R.id.personal_home) - TextView mPersonalHome; - @BindView(R.id.personal_user_name) - TextView mPersonalUserName; - @BindView(R.id.personal_user_name_small) - TextView mPersonalUserNameSmall; - @BindView(R.id.personal_badge) - RelativeLayout mPersonalBadge; - @BindView(R.id.personal_badge_icon) - SimpleDraweeView mPersonalBadgeIcon; - @BindView(R.id.personalMyBadgeIcon) - ImageView mPersonalMyBadgeIcon; - @BindView(R.id.personal_badge_count_tv) - TextView mPersonalBadgeCountTv; - @BindView(R.id.personal_badge_tv) - ImageView mPersonalBadgeTv; - @BindView(R.id.personal_badge_tips) - View mPersonalBadgeTips; - @BindView(R.id.personal_func) - RecyclerView mFuncRecyclerView; - @BindView(R.id.personal_new_fans_tips) - View personalNewFansTips; - @BindView(R.id.personal_energy_tv) - TextView mPersonalEnergyTv; - @BindView(R.id.personal_energy) - View mPersonalEnergy; - @BindView(R.id.personal_receive_energy) - View mPersonalReceiveEnergy; - - public final static String LOGIN_TAG = "login_tag"; //登入标识 - public final static String LOGOUT_TAG = "logout_tag"; // 登出标识 - private final static String MESSAGE_READ_OVER = "MESSAGE_READ_OVER"; - private final static String SP_BADGE_RECORD_SEVEN_DAY = "badgeRecordSevenDay"; - private final static int REQUEST_MESSAGE = 199; - - private UserInfoEntity mUserInfoEntity; - - private AppDatabase mDatabase; - - private UserViewModel mUserViewModel; - private MessageUnreadViewModel mUnreadViewModel; - private UserHomeViewModel mUserHomeViewModel; - private PersonalViewModel mPersonalViewModel; - - private NewPersonalFunctionGroupAdapter mPersonalFuncGroupAdapter; - - private boolean mIsLogging = false; - private int mEnergy = 0; - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (requestCode == Constants.REQUEST_LOGIN) { // QQ Login callback - LoginHelper.onQQLoginCallback(requestCode, resultCode, data); - } else if (requestCode == 32973) {// 32973 WeiBo requestCode - LoginHelper.onWeiboLoginCallback(requestCode, resultCode, data); - } else if (requestCode == REQUEST_MESSAGE) { - if (mUnreadViewModel != null) mUnreadViewModel.retry(); - } - } - - @Override - protected int getLayoutId() { - return R.layout.fragment_new_personal_stub; - } - - @Override - protected boolean useButterKnife() { - return false; - } - - @SuppressLint("CheckResult") - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mDatabase = AppDatabase.getInstance(getContext()); - final UserViewModel.Factory factory = new UserViewModel.Factory(getActivity().getApplication()); - mUserViewModel = ViewModelProviders.of(this, factory).get(UserViewModel.class); - mUserHomeViewModel = ViewModelProviders.of(this, new UserHomeViewModel.Factory(HaloApp.getInstance().getApplication(), - UserManager.getInstance().getUserId())).get(UserHomeViewModel.class); - mUnreadViewModel = ViewModelProviders.of(this, - new MessageUnreadViewModel.Factory(HaloApp.getInstance().getApplication())).get(MessageUnreadViewModel.class); - mPersonalViewModel = ViewModelProviders.of(this).get(PersonalViewModel.class); - - observeNoneUIRelatedChanges(); - } - - @Override - public void onFragmentFirstVisible() { - super.onFragmentFirstVisible(); - - inflateRealView(); - observeUIRelatedChanges(); - } - - private void inflateRealView() { - try { - mCachedView = ((ViewStub) (mCachedView.findViewById(R.id.stub))).inflate(); - } catch (Exception e) { - e.printStackTrace(); - } - - ButterKnife.bind(this, mCachedView); - - mPersonalFuncGroupAdapter = new NewPersonalFunctionGroupAdapter(requireContext()); - mFuncRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); - mFuncRecyclerView.setAdapter(mPersonalFuncGroupAdapter); - mFuncRecyclerView.addItemDecoration(new SpacingItemDecoration(true, false, false, false, 0, DisplayUtils.dip2px(32F), 0, 0)); - - int statusBarHeight = Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT ? 0 : DisplayUtils.getStatusBarHeight(getResources()); - ViewGroup.LayoutParams params = toolbar.getLayoutParams(); - params.height = DisplayUtils.dip2px(50) + statusBarHeight; - toolbar.setLayoutParams(params); - - appbar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> { - int absOffset = Math.abs(verticalOffset); - int invisibleOffset = DisplayUtils.dip2px(56F + 48F - 50F) - DisplayUtils.getStatusBarHeight(getResources()); - if (absOffset <= invisibleOffset) { - mUserIconSmall.setVisibility(View.GONE); - mPersonalUserNameSmall.setVisibility(View.GONE); - toolbar.setBackground(null); - } else { - mUserIconSmall.setVisibility(View.VISIBLE); - mPersonalUserNameSmall.setVisibility(View.VISIBLE); - toolbar.setBackgroundResource(R.drawable.bg_personal_top); - } - mListRefresh.setEnabled(absOffset <= 2); - }); - mListRefresh.setColorSchemeColors(ContextCompat.getColor(requireContext(), R.color.theme)); - mListRefresh.setProgressViewOffset(false, 0, DisplayUtils.dip2px(80) + DisplayUtils.getStatusBarHeight(requireContext().getResources())); - mListRefresh.setOnRefreshListener(() -> { - mPersonalViewModel.getHaloAddons(); - if (CheckLoginUtils.isLogin()) { - mUnreadViewModel.retry(); - MessageUnreadRepository.INSTANCE.loadMessageUnreadTotal(false); - mUserHomeViewModel.getBadgeList(); - mUserHomeViewModel.availableBadges(); - } - mBaseHandler.postDelayed(() -> { - mListRefresh.setRefreshing(false); - }, 2000); - MtaHelper.onEvent("我的光环_新", "下拉刷新", "下拉刷新"); - }); - MessageUnreadRepository.INSTANCE.loadMessageUnreadTotal(true); - } - - private void observeNoneUIRelatedChanges() { - mPersonalViewModel.getHaloAddons(); - mUserViewModel.getLoginObsUserinfo().observe(this, userInfoEntity -> { - UserInfoEntity notifyUserInfo; - if (userInfoEntity != null) { - notifyUserInfo = userInfoEntity.getData(); - } else { - notifyUserInfo = null; - } - - if (notifyUserInfo != null && mUserInfoEntity == null) { // 单个用户,首次触发 - EventBus.getDefault().post(new EBConcernChanged()); - - LoginTokenEntity loginTokenEntity = UserManager.getInstance().getLoginTokenEntity(); - if (mIsLogging && loginTokenEntity != null) { - String loginType = loginTokenEntity.getLoginType(); - LogUtils.login("success", loginType, getLoginEntranceByType(loginType)); - mIsLogging = false; - } - } - - mUserInfoEntity = notifyUserInfo; - if (notifyUserInfo == null) { - mUnreadViewModel.clean(); - EventBus.getDefault().post(new EBConcernChanged()); - } - }); - - mPersonalViewModel.getHaloAddData().observe(this, datas -> { - if (!datas.isEmpty()) { - MessageUnreadRepository.INSTANCE.loadMessageUnreadTotal(false); - } - }); - - mUnreadViewModel.getLiveData().observe(this - , messageUnread -> { - if (messageUnread != null && messageUnread.getTotal() > 0) { - // 第一次开启应用时检查消息中心看有没有未读消息确定需不需要弹 Notifier 通知 - showNotifier(messageUnread); - } - }); - } - - @SuppressLint("CheckResult") - private void observeUIRelatedChanges() { - mUserViewModel.getLoginObsUserinfo().observe(this, userInfoEntity -> { - if (userInfoEntity != null && userInfoEntity.getData() != null) { - changeLoginState(true); - } else { - changeLoginState(false); - } - }); - - mUserHomeViewModel.getBadges().observe(this, badgeEntities -> { - mPersonalBadgeIcon.setImageURI(""); - - if (badgeEntities.isEmpty()) { - mPersonalBadgeTv.setVisibility(View.GONE); - mPersonalBadgeCountTv.setVisibility(View.GONE); - mPersonalMyBadgeIcon.setVisibility(View.VISIBLE); - } else { - mPersonalBadgeTv.setVisibility(View.VISIBLE); - mPersonalBadgeCountTv.setVisibility(View.VISIBLE); - mPersonalMyBadgeIcon.setVisibility(View.GONE); - mPersonalBadgeCountTv.setText(badgeEntities.size() + ""); - - for (BadgeEntity badgeEntity : badgeEntities) { - if (badgeEntity.getWear()) { - ImageUtils.display(mPersonalBadgeIcon, badgeEntity.getIcon()); - - mPersonalBadgeIcon.setOnClickListener(v -> DialogUtils.showViewBadgeDialog(requireContext(), new Badge(badgeEntity.getName(), badgeEntity.getIcon(), badgeEntity.getActions()), - () -> DirectUtils.directToBadgeWall(requireContext(), mUserInfoEntity.getUserId(), mUserInfoEntity.getName(), mUserInfoEntity.getIcon()))); - - break; - } - } - } - }); - mUserHomeViewModel.getAvailableBadgeCount().observe(this, count -> mPersonalBadgeTips.setVisibility(count > 0 ? View.VISIBLE : View.GONE)); - - mUserHomeViewModel.getAvailableBadge().observe(this, badge -> { - // 徽章领取弹窗每隔7天弹出一次,所以要判断现在是否是上一次弹出的第7天或者之后 - if (badge != null && System.currentTimeMillis() >= SPUtils.getLong(SP_BADGE_RECORD_SEVEN_DAY)) { - // 徽章领取弹窗每隔7天弹出一次,所以本次弹出后就记录7天后的时间戳 - SPUtils.setLong(SP_BADGE_RECORD_SEVEN_DAY, TimeUtils.getStartTimeOfDay(System.currentTimeMillis() + 86400000 * 6)); - - DialogUtils.showReceiveBadgeDialog(requireContext(), badge, - () -> RetrofitManager.getInstance(requireContext()).getApi() - .applyOrReceiveBadge(badge.getId()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new BiResponse() { - @Override - public void onSuccess(ResponseBody data) { - if ("self".equals(badge.getReceive().getType())) { - ToastUtils.INSTANCE.showToast("领取成功"); - } else { - ToastUtils.INSTANCE.showToast("申请成功"); - } - // 跳转到徽章详情 - DirectUtils.directToBadgeDetail(requireContext(), mUserInfoEntity.getUserId(), badge.getId()); - } - - @Override - public void onFailure(@NotNull Exception exception) { - super.onFailure(exception); - if ("self".equals(badge.getReceive().getType())) { - ToastUtils.INSTANCE.showToast("领取失败"); - } else { - ToastUtils.INSTANCE.showToast("申请失败"); - } - } - })); - } - }); - - mUserHomeViewModel.getEnergy().observe(this, energy -> { - mEnergy = energy; - if (energy > 9999) { - mPersonalEnergyTv.setText("9999+"); - } else { - mPersonalEnergyTv.setText(energy + ""); - } - }); - - mUserHomeViewModel.getSignStatus().observe(this, entity -> { - if (entity.getTodaySignIn()) { - mPersonalEnergy.setVisibility(View.VISIBLE); - mPersonalReceiveEnergy.setVisibility(View.GONE); - } else { - mPersonalEnergy.setVisibility(View.GONE); - mPersonalReceiveEnergy.setVisibility(View.VISIBLE); - } - }); - - mPersonalViewModel.getHaloAddData().observe(this, datas -> { - if (!datas.isEmpty()) { - mPersonalFuncGroupAdapter.setListData(datas); - checkUpdate(); - } - }); - - mUnreadViewModel.getLiveData().observe(this - , messageUnread -> { - if (messageUnread != null && messageUnread.getTotal() > 0) { - personalNewFansTips.setVisibility(messageUnread.getFans() > 0 ? View.VISIBLE : View.GONE); - mPersonalHome.setText(messageUnread.getFans() > 0 ? ((messageUnread.getFans() < 100 ? messageUnread.getFans() : "99+") + "位新粉丝") : "个人主页"); - int count = messageUnread.getTotal() - messageUnread.getFans(); - mLoginMessageHint.setVisibility(count > 0 ? View.VISIBLE : View.GONE); - BindingAdapters.setMessageUnread(mLoginMessageHint, count); - } else { - mLoginMessageHint.setVisibility(View.GONE); - mPersonalHome.setText("个人主页"); - personalNewFansTips.setVisibility(View.GONE); - EventBus.getDefault().post(new EBReuse(MESSAGE_READ_OVER)); - } - }); - mUnreadViewModel.getZixunConcernLiveData().observe(this, hasConcern -> { - notifyItemChange("游戏动态", hasConcern ? FunctionalMessageType.NEW_MESSAGE : null); - }); - mUnreadViewModel.getAddonsUnreadLiveData().observe(this, entity -> { - notifyItemChange("我的收藏", entity.getFavorite() > 0 ? FunctionalMessageType.NEW_MESSAGE : null); - }); - } - - @Override - public void onFragmentResume() { - super.onFragmentResume(); - - if (NetworkUtils.isNetworkConnected(requireContext())) { - mUnreadViewModel.retry(); - mUserHomeViewModel.getBadgeList(); - mUserHomeViewModel.availableBadges(); - if (CheckLoginUtils.isLogin()) { - mUserHomeViewModel.getUserEnergy(); - mUserHomeViewModel.getSignInfo(); - } - } -// int currentItem = ((MainWrapperFragment) getParentFragment()).getCurrentItem(); -// if (currentItem == INDEX_PERSONAL) { - DisplayUtils.setLightStatusBar(requireActivity(), false); -// } - } - - private void showNotifier(MessageUnreadEntity messageUnread) { - if (mUnreadViewModel.isFirstTimeInit()) { - mUnreadViewModel.flagFirstTimeInit(false); - - if (messageUnread.getMeta() != null && messageUnread.getMeta().getUser() != null) { - if (messageUnread.getMeta() != null) { - String displayText = StringUtils.shrinkStringWithDot(messageUnread.getMeta().getUser().getName(), 8); - String suffixText; - if ("follow_question".equals(messageUnread.getMeta().getType())) { - suffixText = "回答了你关注的问题"; - } else { - suffixText = "回答了你的问题"; - } - displayText += suffixText; - - String content = messageUnread.getMeta().getAnswerId() + displayText; - - if (Notifier.shouldShowNotifier(content)) { - Notifier.create(getActivity()) - .setText(displayText) - .setDuration(5000) - .setIcon(messageUnread.getMeta().getUser().getIcon()) - .setOnClickListener(view -> { - Bundle bundle = new Bundle(); - bundle.putString(EntranceUtils.KEY_ANSWER_ID, messageUnread.getMeta().getAnswerId()); - bundle.putString(EntranceUtils.KEY_ENTRANCE, EntranceUtils.ENTRANCE_UMENG); - bundle.putString(EntranceUtils.KEY_TO, SimpleAnswerDetailActivity.class.getName()); - EntranceUtils.jumpActivity(getActivity(), bundle); - - MtaHelper.onEvent("消息弹窗", suffixText, "Does not contains any parameter."); - - // 标记已读 - JSONObject jsonObject = new JSONObject(); - try { - jsonObject.put("type", messageUnread.getMeta().getType()); - RequestBody body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString()); - RetrofitManager.getInstance(requireContext()).getApi() - .postMessageRead(UserManager.getInstance().getUserId(), messageUnread.getMeta().getMessageId(), body) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Response() { - @Override - public void onResponse(@Nullable ResponseBody response) { - super.onResponse(response); - MessageUnreadRepository.INSTANCE.loadMessageUnreadData(); - } - }); - } catch (Exception e) { - e.printStackTrace(); - } - - Notifier.hide(); - }) - .show(true, 500L); - Notifier.tagNotifierAsShowed(content); - } - } - } - } - } - - @OnClick({R.id.toolbar, R.id.collapsingToolbar, R.id.iv_arrow, R.id.personal_info, R.id.personal_login, R.id.personal_user_small_icon, R.id.personal_user_icon, R.id.personal_msg, - R.id.personal_user_name_small, R.id.personal_user_name, R.id.personal_badge, R.id.personal_home, - R.id.personal_receive_energy, R.id.personal_energy, R.id.personal_energy_center, R.id.personal_energy_house, R.id.personal_energy_record}) - public void onViewClicked(View view) { - switch (view.getId()) { - case R.id.collapsingToolbar: - case R.id.toolbar: - case R.id.personal_info: - if (mUserInfoEntity == null) { - CheckLoginUtils.checkLogin(getContext(), "我的光环-手机登录", null); - } - break; - case R.id.personal_login: - MtaHelper.onEvent("我的光环_新", "立即登录", "点击登录"); - CheckLoginUtils.checkLogin(getContext(), "我的光环-立即登录", null); - break; - case R.id.personal_msg: - if (CheckLoginUtils.isLogin()) { - MtaHelper.onEvent("我的光环", "消息"); - MtaHelper.onEvent("我的光环_新", "消息中心", "点击消息中心"); - startActivityForResult(MessageActivity.getIntent(getContext(), "(我的光环)+(消息中心)"), REQUEST_MESSAGE); - } else { - MtaHelper.onEvent("我的光环_新", "功能入口-跳转登录", "消息中心"); - CheckLoginUtils.checkLogin(getContext(), "我的光环-消息", () -> { - }); - } - break; - case R.id.personal_user_small_icon: - case R.id.personal_user_icon: - if (mUserInfoEntity != null) { - MtaHelper.onEvent("我的光环", "个人中心"); - MtaHelper.onEvent("我的光环_新", "头像", "点击头像"); - DirectUtils.directToHomeActivity(requireContext(), UserManager.getInstance().getUserId(), "", "我的光环"); - } else { - MtaHelper.onEvent("我的光环", "手机登录"); - CheckLoginUtils.checkLogin(getContext(), "我的光环-手机登录", null); - } - break; - case R.id.personal_user_name_small: - case R.id.personal_user_name: - if (mUserInfoEntity != null) { - MtaHelper.onEvent("我的光环", "个人中心"); - MtaHelper.onEvent("我的光环_新", "昵称", "点击昵称"); - DirectUtils.directToHomeActivity(requireContext(), UserManager.getInstance().getUserId(), "", "我的光环"); - } else { - MtaHelper.onEvent("我的光环", "手机登录"); - CheckLoginUtils.checkLogin(getContext(), "我的光环-手机登录", null); - } - break; - case R.id.iv_arrow: - case R.id.personal_home: - if (mUserInfoEntity != null) { - MtaHelper.onEvent("我的光环", "个人主页"); - MtaHelper.onEvent("我的光环_新", "个人主页", "进入个人主页"); - DirectUtils.directToHomeActivity(requireContext(), UserManager.getInstance().getUserId(), "", "我的光环"); - } else { - CheckLoginUtils.checkLogin(getContext(), "我的光环-个人主页", null); - } - break; - case R.id.personal_badge: - MtaHelper.onEvent("我的光环_新", "徽章中心", "进入徽章中心"); - DirectUtils.directToBadgeWall(requireContext(), mUserInfoEntity.getUserId(), mUserInfoEntity.getName(), mUserInfoEntity.getIcon()); - break; - case R.id.personal_receive_energy: - IntegralLogHelper.INSTANCE.log("click_energy", "我的光环"); - if (mUserInfoEntity != null) { - MtaHelper.onEvent("我的光环_新", "领光能", "点击领光能"); - startActivity(EnergyCenterActivity.Companion.getIntent(requireContext(), true)); - } else { - CheckLoginUtils.checkLogin(getContext(), "我的光环-领光能", null); - } - break; - case R.id.personal_energy: - IntegralLogHelper.INSTANCE.log("click_sign", "我的光环"); - if (mUserInfoEntity != null) { - MtaHelper.onEvent("我的光环_新", "光能值", "点击光能值"); - DialogUtils.showEnergyDialog(requireContext(), mUserInfoEntity.getName(), mEnergy); - } else { - CheckLoginUtils.checkLogin(getContext(), "我的光环-光能值", null); - } - break; - case R.id.personal_energy_center: - MtaHelper.onEvent("我的光环_新", "光能中心", "进入光能中心"); - IntegralLogHelper.INSTANCE.log("click_energy_center", "我的光环", "我的光环-光能中心"); - IntegralLogHelper.INSTANCE.log("view_energy_center", "光能中心"); - requireContext().startActivity(EnergyCenterActivity.Companion.getIntent(requireContext())); - break; - case R.id.personal_energy_house: - MtaHelper.onEvent("我的光环_新", "光能屋", "进入光能屋"); - IntegralLogHelper.INSTANCE.log("click_energy_store", "我的光环", "我的光环-光能屋"); - IntegralLogHelper.INSTANCE.log("view_energy_store", "光能屋"); - requireContext().startActivity(EnergyHouseActivity.Companion.getIntent(requireContext())); - break; - case R.id.personal_energy_record: - IntegralLogHelper.INSTANCE.log("click_energy_record", "我的光环", "我的光环-光能明细"); - IntegralLogHelper.INSTANCE.log("view_energy_record", "光能明细"); - if (mUserInfoEntity != null) { - MtaHelper.onEvent("我的光环_新", "光能记录", "进入光能记录"); - DirectUtils.directToEnergyRecord(requireContext()); - } else { - CheckLoginUtils.checkLogin(getContext(), "我的光环-光能记录", null); - } - break; - default: - break; - } - } - - // 连接上网络事件 - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(EBNetworkState busNetworkState) { - if (busNetworkState.isNetworkConnected() - && UserManager.getInstance().isLoggedIn() - && (mUserInfoEntity == null || TextUtils.isEmpty(UserManager.getInstance().getToken()))) { - mUserViewModel.retryCheckLogin(); - } - if (busNetworkState.isNetworkConnected()) { - mPersonalViewModel.getHaloAddons(); - } - } - -// @Subscribe(threadMode = ThreadMode.MAIN) -// public void onEventMainThread(EBUISwitch busNine) { -// if (MainWrapperFragment.EB_MAIN_SCROLL_TOP.equals(busNine.getFrom()) -// && INDEX_PERSONAL == busNine.getPosition()) { -// //mScrollView.fullScroll(ScrollView.FOCUS_UP); -// } -// } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(EBReuse reuse) { - if (MESSAGE_READ_OVER.equals(reuse.getType())) { // 消息阅读完成 - if (mLoginMessageHint != null) { - mLoginMessageHint.setVisibility(View.GONE); - } - } - } - - private boolean isCanSign(long time) { - SimpleDateFormat formatDay = new SimpleDateFormat("dd", Locale.CHINA); - - long lastSignTime = time * 1000; - long curTime = Utils.getTime(getContext()) * 1000; - int lastSignDay = Integer.parseInt(formatDay.format(lastSignTime)); - int curDay = Integer.parseInt(formatDay.format(curTime)); - return lastSignDay != curDay || curTime - lastSignTime > 24 * 60 * 60 * 1000; - } - - private String getSignSkipText(String text) { - return TextUtils.isEmpty(text) ? "去首页看看" : text; - } - - private void signSkip(SignEntity signEntity) { - SignEntity.Data data = signEntity.getData(); - String entrance = "(我的光环)+(签到)"; - if (data == null || TextUtils.isEmpty(data.getType())) { - EventBus.getDefault().post(new EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_HOME)); - return; - } - switch (data.getType()) { - case "game": - DataUtils.onMtaEvent(getActivity(), "我的光环_签到跳转", "游戏", signEntity.getTitle()); - GameDetailActivity.startGameDetailActivity(getContext(), data.getLink(), entrance); - break; - case "news": - DataUtils.onMtaEvent(getActivity(), "我的光环_签到跳转", "文章", signEntity.getTitle()); - startActivity(NewsDetailActivity.getIntentById(getContext(), data.getLink(), entrance)); - break; - case "column": - DataUtils.onMtaEvent(getActivity(), "我的光环_签到跳转", "专题", signEntity.getTitle()); - SubjectActivity.startSubjectActivity(getContext(), data.getLink(), null, false, entrance); - break; - - default: - LinkEntity linkEntity = new LinkEntity(); - linkEntity.setType(data.getType()); - linkEntity.setLink(data.getLink()); - linkEntity.setText(data.getText()); - linkEntity.setCommunity(data.getCommunity()); - linkEntity.setDisplay(data.getDisplay()); - DirectUtils.directToLinkPage(requireContext(), linkEntity, entrance, ""); - break; - } - } - - private static String getLoginEntranceByType(String loginTag) { - String entrance = ""; - switch (loginTag) { - case "qq": - entrance = "我的光环-QQ"; - break; - case "wechat": - entrance = "我的光环-微信"; - break; - case "weibo": - entrance = "我的光环-新浪微博"; - break; - } - return entrance; - } - - private void changeLoginState(boolean isLogin) { - if (isLogin) { - if (mUserInfoEntity != null) { - mUserIcon.display(mUserInfoEntity.getIconBorder() == null ? "" : mUserInfoEntity.getIconBorder().getUrl(), - mUserInfoEntity.getIcon(), mUserInfoEntity.getAuth() == null ? "" : mUserInfoEntity.getAuth().getIcon()); - ImageUtils.displayIcon(mUserIconSmall, mUserInfoEntity.getIcon()); - mPersonalUserName.setVisibility(View.VISIBLE); - mPersonalBadge.setVisibility(View.VISIBLE); - mPersonalHome.setVisibility(View.VISIBLE); - mPersonalLogin.setVisibility(View.GONE); - mPersonalUserName.setText(mUserInfoEntity.getName()); - mPersonalUserNameSmall.setText(mUserInfoEntity.getName()); - } - mUserHomeViewModel.setUserId(UserManager.getInstance().getUserId()); - mUserHomeViewModel.getBadgeList(); - mUserHomeViewModel.availableBadges(); - mUserHomeViewModel.getUserEnergy(); - mUserHomeViewModel.getSignInfo(); - MessageUnreadRepository.INSTANCE.loadMessageUnreadTotal(true); - } else { - mPersonalReceiveEnergy.setVisibility(View.VISIBLE); - mPersonalEnergy.setVisibility(View.GONE); - mUserIcon.display("", "", ""); - mUserIconSmall.setImageURI(""); -// mPersonalBadgeTv.setText("我的徽章"); - mPersonalUserNameSmall.setText("立即登录"); - mPersonalUserName.setVisibility(View.GONE); - mPersonalHome.setVisibility(View.GONE); - mPersonalBadge.setVisibility(View.GONE); - mPersonalLogin.setVisibility(View.VISIBLE); - - if (mLoginMessageHint.getVisibility() == View.VISIBLE) { - mLoginMessageHint.setVisibility(View.GONE); - EventBus.getDefault().post(new EBReuse(MESSAGE_READ_OVER)); - } - } - } - - private void checkUpdate() { - String channel = HaloApp.getInstance().getChannel(); - RetrofitManager.getInstance(getContext()) - .getApi() - .getUpdate(PackageUtils.getVersionName(), PackageUtils.getVersionCode(), channel) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Response() { - @Override - public void onResponse(AppEntity response) { - super.onResponse(response); - if (response.getVersionCode() > PackageUtils.getVersionCode()) { - notifyItemChange("设置", FunctionalMessageType.NEW_VERSION); - } else { - notifyItemChange("设置", null); - } - } - }); - } - - private void notifyItemChange(String funcName, FunctionalMessageType msg) { - ArrayList mEntityList = mPersonalFuncGroupAdapter.getMEntityList(); - for (FunctionalGroupEntity mEntity : mEntityList) { - for (FunctionalLinkEntity linkEntity : mEntity.getAddons()) { - if (TextUtils.equals(linkEntity.getType(), funcName)) { - linkEntity.setMessage(msg); - break; - } - } - } - mPersonalFuncGroupAdapter.notifyDataSetChanged(); - } -} diff --git a/app/src/main/java/com/gh/gamecenter/personal/NewPersonalFragment.kt b/app/src/main/java/com/gh/gamecenter/personal/NewPersonalFragment.kt new file mode 100644 index 0000000000..3b46aa5b78 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/personal/NewPersonalFragment.kt @@ -0,0 +1,731 @@ +package com.gh.gamecenter.personal + +import android.annotation.SuppressLint +import android.content.Intent +import android.os.Build +import android.os.Bundle +import android.text.TextUtils +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.LinearLayoutManager +import com.gh.base.fragment.BaseLazyFragment +import com.gh.common.databind.BindingAdapters +import com.gh.common.notifier.Notifier.Companion.create +import com.gh.common.notifier.Notifier.Companion.hide +import com.gh.common.notifier.Notifier.Companion.shouldShowNotifier +import com.gh.common.notifier.Notifier.Companion.tagNotifierAsShowed +import com.gh.common.util.* +import com.gh.common.util.DirectUtils.directToBadgeDetail +import com.gh.common.util.DirectUtils.directToBadgeWall +import com.gh.common.util.DirectUtils.directToEnergyRecord +import com.gh.common.util.DirectUtils.directToHomeActivity +import com.gh.common.util.ImageUtils.display +import com.gh.common.util.ImageUtils.displayIcon +import com.gh.common.util.IntegralLogHelper.log +import com.gh.common.util.LoginHelper.onQQLoginCallback +import com.gh.common.util.LoginHelper.onWeiboLoginCallback +import com.gh.common.util.MtaHelper.onEvent +import com.gh.common.util.SPUtils.getLong +import com.gh.common.util.SPUtils.setLong +import com.gh.common.util.TimeUtils.getStartTimeOfDay +import com.gh.common.util.ToastUtils.showToast +import com.gh.common.view.SpacingItemDecoration +import com.gh.gamecenter.MessageActivity +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.FragmentNewPersonalBinding +import com.gh.gamecenter.databinding.FragmentNewPersonalStubBinding +import com.gh.gamecenter.energy.EnergyCenterActivity +import com.gh.gamecenter.energy.EnergyHouseActivity +import com.gh.gamecenter.entity.* +import com.gh.gamecenter.eventbus.EBConcernChanged +import com.gh.gamecenter.eventbus.EBNetworkState +import com.gh.gamecenter.eventbus.EBReuse +import com.gh.gamecenter.manager.UserManager +import com.gh.gamecenter.message.MessageUnreadRepository.loadMessageUnreadData +import com.gh.gamecenter.message.MessageUnreadRepository.loadMessageUnreadTotal +import com.gh.gamecenter.message.MessageUnreadViewModel +import com.gh.gamecenter.personalhome.UserHomeViewModel +import com.gh.gamecenter.qa.answer.detail.SimpleAnswerDetailActivity +import com.gh.gamecenter.room.AppDatabase +import com.gh.gamecenter.user.ApiResponse +import com.gh.gamecenter.user.UserViewModel +import com.google.android.material.appbar.AppBarLayout +import com.halo.assistant.HaloApp +import com.tencent.connect.common.Constants +import okhttp3.MediaType +import okhttp3.RequestBody +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import org.json.JSONObject +import java.util.* +import kotlin.math.abs + +class NewPersonalFragment : BaseLazyFragment() { + private var mUserInfoEntity: UserInfoEntity? = null + + private lateinit var mDatabase: AppDatabase + + private lateinit var mBinding: FragmentNewPersonalStubBinding + private lateinit var mStubBinding: FragmentNewPersonalBinding + private lateinit var mUserViewModel: UserViewModel + private lateinit var mUnreadViewModel: MessageUnreadViewModel + private lateinit var mUserHomeViewModel: UserHomeViewModel + private lateinit var mPersonalViewModel: PersonalViewModel + + private lateinit var mPersonalFuncGroupAdapter: NewPersonalFunctionGroupAdapter + + private var mIsLogging = false + private var mEnergy: Long = 0 + + override fun getInflatedLayout(): View { + mBinding = DataBindingUtil.inflate( + layoutInflater, + R.layout.fragment_new_personal_stub, + null, + false + ) + mBinding.stub.setOnInflateListener { _, inflateId -> + mStubBinding = FragmentNewPersonalBinding.bind(inflateId) + } + return mBinding.root + } + + override fun getLayoutId() = R.layout.fragment_new_personal_stub + + override fun useButterKnife() = false + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + Constants.REQUEST_LOGIN -> { + onQQLoginCallback(requestCode, resultCode, data) + } + 32973 -> { + onWeiboLoginCallback(requestCode, resultCode, data) + } + REQUEST_MESSAGE -> { + mUnreadViewModel.retry() + } + } + } + + override fun onClick(v: View?) { + super.onClick(v) + mStubBinding.run { + when (v) { + collapsingToolbar, + toolbar, + personalInfo -> { + if (mUserInfoEntity == null) { + CheckLoginUtils.checkLogin(context, "我的光环-手机登录", null) + } + } + personalLogin -> { + onEvent("我的光环_新", "立即登录", "点击登录") + CheckLoginUtils.checkLogin(context, "我的光环-立即登录", null) + } + personalMsg -> { + if (CheckLoginUtils.isLogin()) { + onEvent("我的光环", "消息") + onEvent("我的光环_新", "消息中心", "点击消息中心") + startActivityForResult( + MessageActivity.getIntent(context, "(我的光环)+(消息中心)"), + REQUEST_MESSAGE + ) + } else { + onEvent("我的光环_新", "功能入口-跳转登录", "消息中心") + CheckLoginUtils.checkLogin(context, "我的光环-消息") {} + } + } + personalUserSmallIcon, personalUserIcon -> { + if (mUserInfoEntity != null) { + onEvent("我的光环", "个人中心") + onEvent("我的光环_新", "头像", "点击头像") + directToHomeActivity( + requireContext(), + UserManager.getInstance().userId, + "", + "我的光环" + ) + } else { + onEvent("我的光环", "手机登录") + CheckLoginUtils.checkLogin(context, "我的光环-手机登录", null) + } + } + personalUserNameSmall, personalUserName -> { + if (mUserInfoEntity != null) { + onEvent("我的光环", "个人中心") + onEvent("我的光环_新", "昵称", "点击昵称") + directToHomeActivity( + requireContext(), + UserManager.getInstance().userId, + "", + "我的光环" + ) + } else { + onEvent("我的光环", "手机登录") + CheckLoginUtils.checkLogin(context, "我的光环-手机登录", null) + } + } + ivArrow, personalHome -> { + if (mUserInfoEntity != null) { + onEvent("我的光环", "个人主页") + onEvent("我的光环_新", "个人主页", "进入个人主页") + directToHomeActivity( + requireContext(), + UserManager.getInstance().userId, + "", + "我的光环" + ) + } else { + CheckLoginUtils.checkLogin(context, "我的光环-个人主页", null) + } + } + personalBadge -> { + onEvent("我的光环_新", "徽章中心", "进入徽章中心") + directToBadgeWall( + requireContext(), + mUserInfoEntity?.userId, + mUserInfoEntity?.name, + mUserInfoEntity?.icon + ) + } + personalReceiveEnergy -> { + log("click_energy", "我的光环") + if (mUserInfoEntity != null) { + onEvent("我的光环_新", "领光能", "点击领光能") + startActivity(EnergyCenterActivity.getIntent(requireContext())) + } else { + CheckLoginUtils.checkLogin(context, "我的光环-领光能", null) + } + } + personalEnergy -> { + log("click_sign", "我的光环") + if (mUserInfoEntity != null) { + onEvent("我的光环_新", "光能值", "点击光能值") + DialogUtils.showEnergyDialog( + requireContext(), + mUserInfoEntity?.name, + mEnergy + ) + } else { + CheckLoginUtils.checkLogin(context, "我的光环-光能值", null) + } + } + personalEnergyCenter -> { + onEvent("我的光环_新", "光能中心", "进入光能中心") + log("click_energy_center", "我的光环", "我的光环-光能中心") + log("view_energy_center", "光能中心") + requireContext().startActivity(EnergyCenterActivity.getIntent(requireContext())) + } + personalEnergyHouse -> { + onEvent("我的光环_新", "光能屋", "进入光能屋") + log("click_energy_store", "我的光环", "我的光环-光能屋") + log("view_energy_store", "光能屋") + requireContext().startActivity(EnergyHouseActivity.getIntent(requireContext())) + } + personalEnergyRecord -> { + log("click_energy_record", "我的光环", "我的光环-光能明细") + log("view_energy_record", "光能明细") + if (mUserInfoEntity != null) { + onEvent("我的光环_新", "光能记录", "进入光能记录") + directToEnergyRecord(requireContext()) + } else { + CheckLoginUtils.checkLogin(context, "我的光环-光能记录", null) + } + } + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + mDatabase = AppDatabase.getInstance(context) + val factory = UserViewModel.Factory(requireActivity().application) + mUserViewModel = ViewModelProvider(this, factory).get(UserViewModel::class.java) + mUserHomeViewModel = ViewModelProvider( + this, UserHomeViewModel.Factory( + HaloApp.getInstance().application, + UserManager.getInstance().userId + ) + ).get(UserHomeViewModel::class.java) + mUnreadViewModel = ViewModelProvider( + this, + MessageUnreadViewModel.Factory(HaloApp.getInstance().application) + ).get(MessageUnreadViewModel::class.java) + mPersonalViewModel = ViewModelProvider(this).get(PersonalViewModel::class.java) + + observeNoneUIRelatedChanges() + } + + override fun onFragmentFirstVisible() { + super.onFragmentFirstVisible() + inflateRealView() + observeUIRelatedChanges() + } + + override fun onFragmentResume() { + super.onFragmentResume() + + if (NetworkUtils.isNetworkConnected(requireContext())) { + mUnreadViewModel.retry() + mUserHomeViewModel.getBadgeList() + mUserHomeViewModel.availableBadges() + if (CheckLoginUtils.isLogin()) { + mUserHomeViewModel.getUserEnergy() + mUserHomeViewModel.getSignInfo() + } + } +// val currentItem = (parentFragment as MainWrapperFragment).currentItem +// if (currentItem == MainWrapperFragment.INDEX_PERSONAL) { + DisplayUtils.setLightStatusBar(requireActivity(), false) +// } + } + + @SuppressLint("CheckResult", "SetTextI18n") + private fun observeUIRelatedChanges() { + mPersonalViewModel.appEntity.observe(this, { + if (it.versionCode > PackageUtils.getGhVersionCode()) { + notifyItemChange("设置", FunctionalMessageType.NEW_VERSION) + } else { + notifyItemChange("设置", null) + } + }) + + mUserViewModel.loginObsUserinfo.observe( + this, + { userInfoEntity: ApiResponse? -> + if (userInfoEntity != null && userInfoEntity.data != null) { + changeLoginState(true) + } else { + changeLoginState(false) + } + }) + + mUserHomeViewModel.badges.observe(this, + { badgeEntities: List -> + mStubBinding.personalBadgeIcon.setImageURI("") + if (badgeEntities.isEmpty()) { + mStubBinding.personalBadgeTv.visibility = View.GONE + mStubBinding.personalBadgeCountTv.visibility = View.GONE + mStubBinding.personalMyBadgeIcon.visibility = View.VISIBLE + } else { + mStubBinding.personalBadgeTv.visibility = View.VISIBLE + mStubBinding.personalBadgeCountTv.visibility = View.VISIBLE + mStubBinding.personalMyBadgeIcon.visibility = View.GONE + mStubBinding.personalBadgeCountTv.text = badgeEntities.size.toString() + "" + for ((_, _, icon, name, _, wear, _, actions) in badgeEntities) { + if (wear) { + display( + mStubBinding.personalBadgeIcon, + icon + ) + mStubBinding.personalBadgeIcon.setOnClickListener { + DialogUtils.showViewBadgeDialog( + requireContext(), + Badge(name, icon, actions) + ) { + directToBadgeWall( + requireContext(), + mUserInfoEntity?.userId, + mUserInfoEntity?.name, + mUserInfoEntity?.icon + ) + } + } + break + } + } + } + }) + mUserHomeViewModel.availableBadgeCount.observe(this, + { count: Int -> + mStubBinding.personalBadgeTips.visibility = + if (count > 0) View.VISIBLE else View.GONE + }) + + mUserHomeViewModel.availableBadge.observe(this, + { badge: BadgeEntity? -> + // 徽章领取弹窗每隔7天弹出一次,所以要判断现在是否是上一次弹出的第7天或者之后 + if (badge != null && System.currentTimeMillis() >= getLong(SP_BADGE_RECORD_SEVEN_DAY)) { + // 徽章领取弹窗每隔7天弹出一次,所以本次弹出后就记录7天后的时间戳 + setLong( + SP_BADGE_RECORD_SEVEN_DAY, + getStartTimeOfDay(System.currentTimeMillis() + 86400000 * 6) + ) + DialogUtils.showReceiveBadgeDialog( + requireContext(), badge + ) { + mPersonalViewModel.applyOrReceiveBadge(badge.id, { + if ("self" == badge.receive?.type) { + showToast("领取成功") + } else { + showToast("申请成功") + } + // 跳转到徽章详情 + directToBadgeDetail( + requireContext(), + mUserInfoEntity?.userId, + badge.id + ) + }, { + if ("self" == badge.receive?.type) { + showToast("领取失败") + } else { + showToast("申请失败") + } + }) + } + } + }) + + mUserHomeViewModel.energy.observe(this, { energy: Long -> + mEnergy = energy + if (energy > 9999) { + mStubBinding.personalEnergyTv.text = "9999+" + } else { + mStubBinding.personalEnergyTv.text = energy.toString() + "" + } + }) + + mUserHomeViewModel.signStatus.observe(this, + { (todaySignIn) -> + if (todaySignIn) { + mStubBinding.personalEnergy.visibility = View.VISIBLE + mStubBinding.personalReceiveEnergy.visibility = View.GONE + } else { + mStubBinding.personalEnergy.visibility = View.GONE + mStubBinding.personalReceiveEnergy.visibility = View.VISIBLE + } + }) + + mPersonalViewModel.haloAddData.observe( + this, + { datas: ArrayList -> + if (datas.isNotEmpty()) { + mPersonalFuncGroupAdapter.setListData(datas) + mPersonalViewModel.checkUpdate() + } + }) + + mUnreadViewModel.liveData.observe(this, { messageUnread: MessageUnreadEntity? -> + if (messageUnread != null && messageUnread.total > 0) { + mStubBinding.personalNewFansTips.visibility = + if (messageUnread.fans > 0) View.VISIBLE else View.GONE + mStubBinding.personalHome.text = + if (messageUnread.fans > 0) (if (messageUnread.fans < 100) messageUnread.fans else "99+").toString() + "位新粉丝" else "个人主页" + val count = messageUnread.total - messageUnread.fans + mStubBinding.loginMessageHint.visibility = + if (count > 0) View.VISIBLE else View.GONE + BindingAdapters.setMessageUnread(mStubBinding.loginMessageHint, count) + } else { + mStubBinding.loginMessageHint.visibility = View.GONE + mStubBinding.personalHome.text = "个人主页" + mStubBinding.personalNewFansTips.visibility = View.GONE + EventBus.getDefault() + .post(EBReuse(MESSAGE_READ_OVER)) + } + }) + mUnreadViewModel.zixunConcernLiveData.observe(this, + { hasConcern: Boolean -> + notifyItemChange( + "游戏动态", + if (hasConcern) FunctionalMessageType.NEW_MESSAGE else null + ) + }) + mUnreadViewModel.addonsUnreadLiveData.observe(this, + { (favorite) -> + notifyItemChange( + "我的收藏", + if (favorite > 0) FunctionalMessageType.NEW_MESSAGE else null + ) + }) + } + + private fun notifyItemChange(funcName: String, msg: FunctionalMessageType?) { + val mEntityList = mPersonalFuncGroupAdapter.mEntityList + for ((_, _, _, addons) in mEntityList) { + for (linkEntity in addons) { + if (TextUtils.equals(linkEntity.type, funcName)) { + linkEntity.message = msg + break + } + } + } + mPersonalFuncGroupAdapter.notifyDataSetChanged() + } + + private fun changeLoginState(isLogin: Boolean) { + if (isLogin) { + if (mUserInfoEntity != null) { + mStubBinding.personalUserIcon.display( + if (mUserInfoEntity?.iconBorder == null) "" else mUserInfoEntity?.iconBorder?.url, + mUserInfoEntity?.icon, + null + ) + displayIcon(mStubBinding.personalUserSmallIcon, mUserInfoEntity?.icon) + mStubBinding.personalUserName.visibility = View.VISIBLE + mStubBinding.personalBadge.visibility = View.VISIBLE + mStubBinding.personalHome.visibility = View.VISIBLE + mStubBinding.personalLogin.visibility = View.GONE + mStubBinding.personalUserName.text = mUserInfoEntity?.name + mStubBinding.personalUserNameSmall.text = mUserInfoEntity?.name + } + mUserHomeViewModel.userId = UserManager.getInstance().userId + mUserHomeViewModel.getBadgeList() + mUserHomeViewModel.availableBadges() + mUserHomeViewModel.getUserEnergy() + mUserHomeViewModel.getSignInfo() + loadMessageUnreadTotal(true) + } else { + mStubBinding.personalReceiveEnergy.visibility = View.VISIBLE + mStubBinding.personalEnergy.visibility = View.GONE + mStubBinding.personalUserIcon.display("", "", "") + mStubBinding.personalUserSmallIcon.setImageURI("") + // mPersonalBadgeTv.setText("我的徽章"); + mStubBinding.personalUserNameSmall.text = "立即登录" + mStubBinding.personalUserName.visibility = View.GONE + mStubBinding.personalHome.visibility = View.GONE + mStubBinding.personalBadge.visibility = View.GONE + mStubBinding.personalLogin.visibility = View.VISIBLE + if (mStubBinding.loginMessageHint.visibility == View.VISIBLE) { + mStubBinding.loginMessageHint.visibility = View.GONE + EventBus.getDefault().post(EBReuse(MESSAGE_READ_OVER)) + } + } + } + + private fun inflateRealView() { + mBinding.stub.viewStub?.inflate() + + mStubBinding.collapsingToolbar.setOnClickListener(this) + mStubBinding.toolbar.setOnClickListener(this) + mStubBinding.personalInfo.setOnClickListener(this) + mStubBinding.personalLogin.setOnClickListener(this) + mStubBinding.personalMsg.setOnClickListener(this) + mStubBinding.personalHome.setOnClickListener(this) + mStubBinding.ivArrow.setOnClickListener(this) + mStubBinding.personalLogin.setOnClickListener(this) + mStubBinding.personalUserName.setOnClickListener(this) + mStubBinding.personalUserNameSmall.setOnClickListener(this) + mStubBinding.personalUserIcon.setOnClickListener(this) + mStubBinding.personalUserSmallIcon.setOnClickListener(this) + mStubBinding.personalBadge.setOnClickListener(this) + mStubBinding.personalReceiveEnergy.setOnClickListener(this) + mStubBinding.personalEnergy.setOnClickListener(this) + mStubBinding.personalEnergyCenter.setOnClickListener(this) + mStubBinding.personalEnergyRecord.setOnClickListener(this) + mStubBinding.personalEnergyHouse.setOnClickListener(this) + + mPersonalFuncGroupAdapter = NewPersonalFunctionGroupAdapter(requireContext()) + mStubBinding.personalFunc.layoutManager = LinearLayoutManager(requireContext()) + mStubBinding.personalFunc.adapter = mPersonalFuncGroupAdapter + mStubBinding.personalFunc.addItemDecoration( + SpacingItemDecoration( + onlyDecorateTheFirstItem = true, + notDecorateTheFirstItem = false, + notDecorateTheLastItem = false, + notDecorateTheFirstTwoItems = false, + left = 0, + top = 32F.dip2px(), + right = 0, + bottom = 0 + ) + ) + + val statusBarHeight = + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) 0 else DisplayUtils.getStatusBarHeight( + resources + ) + val params: ViewGroup.LayoutParams = mStubBinding.toolbar.layoutParams + params.height = DisplayUtils.dip2px(50F) + statusBarHeight + mStubBinding.toolbar.layoutParams = params + + mStubBinding.appbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _: AppBarLayout?, verticalOffset: Int -> + val absOffset = abs(verticalOffset) + val invisibleOffset = + DisplayUtils.dip2px(56F + 48F - 50F) - DisplayUtils.getStatusBarHeight(resources) + if (absOffset <= invisibleOffset) { + mStubBinding.personalUserSmallIcon.visibility = View.GONE + mStubBinding.personalUserNameSmall.visibility = View.GONE + mStubBinding.toolbar.background = null + } else { + mStubBinding.personalUserSmallIcon.visibility = View.VISIBLE + mStubBinding.personalUserNameSmall.visibility = View.VISIBLE + mStubBinding.toolbar.setBackgroundResource(R.drawable.bg_personal_top) + } + mStubBinding.listRefresh.isEnabled = absOffset <= 2 + }) + mStubBinding.listRefresh.setColorSchemeColors( + ContextCompat.getColor( + requireContext(), + R.color.theme + ) + ) + mStubBinding.listRefresh.setProgressViewOffset( + false, + 0, + DisplayUtils.dip2px(80F) + DisplayUtils.getStatusBarHeight(requireContext().resources) + ) + mStubBinding.listRefresh.setOnRefreshListener { + mPersonalViewModel.getHaloAddons() + if (CheckLoginUtils.isLogin()) { + mUnreadViewModel.retry() + loadMessageUnreadTotal(false) + mUserHomeViewModel.getBadgeList() + mUserHomeViewModel.availableBadges() + } + mBaseHandler.postDelayed({ mStubBinding.listRefresh.isRefreshing = false }, 2000) + onEvent("我的光环_新", "下拉刷新", "下拉刷新") + } + loadMessageUnreadTotal(true) + } + + private fun observeNoneUIRelatedChanges() { + mPersonalViewModel.getHaloAddons() + mUserViewModel.loginObsUserinfo.observe(this, + { userInfoEntity: ApiResponse? -> + val notifyUserInfo: UserInfoEntity? = userInfoEntity?.data + if (notifyUserInfo != null && mUserInfoEntity == null) { // 单个用户,首次触发 + EventBus.getDefault().post(EBConcernChanged()) + val loginTokenEntity = + UserManager.getInstance().loginTokenEntity + if (mIsLogging && loginTokenEntity != null) { + val loginType = loginTokenEntity.loginType + LogUtils.login( + "success", + loginType, + mPersonalViewModel.getLoginEntranceByType(loginType) + ) + mIsLogging = false + } + } + mUserInfoEntity = notifyUserInfo + if (notifyUserInfo == null) { + mUnreadViewModel.clean() + EventBus.getDefault().post(EBConcernChanged()) + } + }) + mPersonalViewModel.haloAddData.observe( + this, + { datas: ArrayList -> + if (datas.isNotEmpty()) { + loadMessageUnreadTotal(false) + } + }) + mUnreadViewModel.liveData.observe(this, { messageUnread: MessageUnreadEntity? -> + if (messageUnread != null && messageUnread.total > 0) { + // 第一次开启应用时检查消息中心看有没有未读消息确定需不需要弹 Notifier 通知 + showNotifier(messageUnread) + } + }) + } + + private fun showNotifier(messageUnread: MessageUnreadEntity) { + if (mUnreadViewModel.isFirstTimeInit) { + mUnreadViewModel.flagFirstTimeInit(false) + if (messageUnread.meta != null && messageUnread.meta?.user != null) { + if (messageUnread.meta != null) { + var displayText = StringUtils.shrinkStringWithDot( + messageUnread.meta?.user?.name, 8 + ) + val suffixText: String = if ("follow_question" == messageUnread.meta?.type) { + "回答了你关注的问题" + } else { + "回答了你的问题" + } + displayText += suffixText + val content = messageUnread.meta?.answerId + displayText + if (shouldShowNotifier(content)) { + create(activity) + .setText(displayText) + .setDuration(5000) + .setIcon(messageUnread.meta?.user?.icon) + .setOnClickListener { + val bundle = Bundle() + bundle.putString( + EntranceUtils.KEY_ANSWER_ID, + messageUnread.meta?.answerId + ) + bundle.putString( + EntranceUtils.KEY_ENTRANCE, + EntranceUtils.ENTRANCE_UMENG + ) + bundle.putString( + EntranceUtils.KEY_TO, + SimpleAnswerDetailActivity::class.java.name + ) + EntranceUtils.jumpActivity(activity, bundle) + onEvent("消息弹窗", suffixText, "Does not contains any parameter.") + + // 标记已读 + val jsonObject = JSONObject() + try { + jsonObject.put("type", messageUnread.meta?.type) + val body = RequestBody.create( + MediaType.parse("application/json"), + jsonObject.toString() + ) + messageUnread.meta?.messageId?.let { + mPersonalViewModel.postMessageRead( + it, + body + ) { + loadMessageUnreadData() + } + } + } catch (e: Exception) { + e.printStackTrace() + } + hide() + } + .show(true, 500L) + tagNotifierAsShowed(content) + } + } + } + } + } + + // 连接上网络事件 + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(busNetworkState: EBNetworkState) { + if (busNetworkState.isNetworkConnected + && UserManager.getInstance().isLoggedIn + && (mUserInfoEntity == null || TextUtils.isEmpty(UserManager.getInstance().token)) + ) { + mUserViewModel.retryCheckLogin() + } + if (busNetworkState.isNetworkConnected) { + mPersonalViewModel.getHaloAddons() + } + } + +// @Subscribe(threadMode = ThreadMode.MAIN) +// fun onEventMainThread(busNine: EBUISwitch) { +// if (MainWrapperFragment.EB_MAIN_SCROLL_TOP == busNine.getFrom() && MainWrapperFragment.INDEX_PERSONAL == busNine.getPosition()) { +// //mScrollView.fullScroll(ScrollView.FOCUS_UP) +// } +// } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(reuse: EBReuse) { + if (MESSAGE_READ_OVER == reuse.type) { // 消息阅读完成 + mStubBinding.loginMessageHint.visibility = View.GONE + } + } + + + companion object { + const val LOGIN_TAG = "login_tag" //登入标识 + const val LOGOUT_TAG = "logout_tag" // 登出标识 + + private const val MESSAGE_READ_OVER = "MESSAGE_READ_OVER" + private const val SP_BADGE_RECORD_SEVEN_DAY = "badgeRecordSevenDay" + private const val REQUEST_MESSAGE = 199 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.java b/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.java deleted file mode 100644 index 6f892037ae..0000000000 --- a/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.java +++ /dev/null @@ -1,847 +0,0 @@ -package com.gh.gamecenter.personal; - -import android.annotation.SuppressLint; -import android.content.Intent; -import android.database.sqlite.SQLiteException; -import android.os.Build; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewStub; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.widget.Toolbar; -import androidx.core.content.ContextCompat; -import androidx.lifecycle.ViewModelProviders; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; - -import com.facebook.drawee.view.SimpleDraweeView; -import com.gh.base.BaseActivity; -import com.gh.base.fragment.BaseLazyFragment; -import com.gh.common.databind.BindingAdapters; -import com.gh.common.notifier.Notifier; -import com.gh.common.util.CheckLoginUtils; -import com.gh.common.util.DataUtils; -import com.gh.common.util.DialogUtils; -import com.gh.common.util.DirectUtils; -import com.gh.common.util.DisplayUtils; -import com.gh.common.util.EntranceUtils; -import com.gh.common.util.ImageUtils; -import com.gh.common.util.LogUtils; -import com.gh.common.util.LoginHelper; -import com.gh.common.util.MtaHelper; -import com.gh.common.util.NetworkUtils; -import com.gh.common.util.PackageUtils; -import com.gh.common.util.SPUtils; -import com.gh.common.util.StringUtils; -import com.gh.common.util.TimeUtils; -import com.gh.common.util.ToastUtils; -import com.gh.common.view.AvatarBorderView; -import com.gh.common.view.VerticalItemDecoration; -import com.gh.gamecenter.BuildConfig; -import com.gh.gamecenter.GameDetailActivity; -import com.gh.gamecenter.MainActivity; -import com.gh.gamecenter.MessageActivity; -import com.gh.gamecenter.NewsDetailActivity; -import com.gh.gamecenter.R; -import com.gh.gamecenter.entity.AppEntity; -import com.gh.gamecenter.entity.Badge; -import com.gh.gamecenter.entity.BadgeEntity; -import com.gh.gamecenter.entity.FunctionalGroupEntity; -import com.gh.gamecenter.entity.FunctionalLinkEntity; -import com.gh.gamecenter.entity.FunctionalMessageType; -import com.gh.gamecenter.entity.LinkEntity; -import com.gh.gamecenter.entity.LoginTokenEntity; -import com.gh.gamecenter.entity.MessageUnreadEntity; -import com.gh.gamecenter.entity.SignEntity; -import com.gh.gamecenter.entity.UserInfoEntity; -import com.gh.gamecenter.eventbus.EBConcernChanged; -import com.gh.gamecenter.eventbus.EBNetworkState; -import com.gh.gamecenter.eventbus.EBReuse; -import com.gh.gamecenter.eventbus.EBSkip; -import com.gh.gamecenter.fragment.MainWrapperFragment; -import com.gh.gamecenter.manager.UserManager; -import com.gh.gamecenter.message.MessageUnreadRepository; -import com.gh.gamecenter.message.MessageUnreadViewModel; -import com.gh.gamecenter.personalhome.UserHomeViewModel; -import com.gh.gamecenter.qa.answer.detail.SimpleAnswerDetailActivity; -import com.gh.gamecenter.retrofit.BiResponse; -import com.gh.gamecenter.retrofit.Response; -import com.gh.gamecenter.retrofit.RetrofitManager; -import com.gh.gamecenter.room.AppDatabase; -import com.gh.gamecenter.subject.SubjectActivity; -import com.gh.gamecenter.user.UserViewModel; -import com.google.android.material.appbar.AppBarLayout; -import com.halo.assistant.HaloApp; -import com.jakewharton.rxbinding2.view.RxView; -import com.lightgame.utils.Utils; -import com.tencent.connect.common.Constants; - -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; -import org.jetbrains.annotations.NotNull; -import org.json.JSONObject; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import okhttp3.MediaType; -import okhttp3.RequestBody; -import okhttp3.ResponseBody; -import retrofit2.HttpException; - -import static com.gh.gamecenter.fragment.MainWrapperFragment.INDEX_PERSONAL; - -public class PersonalFragment extends BaseLazyFragment { - - @BindView(R.id.list_refresh) - SwipeRefreshLayout mListRefresh; - @BindView(R.id.appbar) - AppBarLayout appbar; - @BindView(R.id.toolbar) - Toolbar toolbar; - @BindView(R.id.personal_sign) - ImageView mPersonalSign; - @BindView(R.id.personal_msg) - ImageView mPersonalMsg; - @BindView(R.id.login_message_hint) - TextView mLoginMessageHint; - @BindView(R.id.personal_user_icon) - AvatarBorderView mUserIcon; - @BindView(R.id.personal_user_small_icon) - SimpleDraweeView mUserIconSmall; - // @BindView(R.id.personal_user_badge) -// SimpleDraweeView mUserBadge; - @BindView(R.id.personal_login) - View mPersonalLogin; - @BindView(R.id.personal_home) - TextView mPersonalHome; - @BindView(R.id.personal_user_name) - TextView mPersonalUserName; - @BindView(R.id.personal_user_name_small) - TextView mPersonalUserNameSmall; -// @BindView(R.id.personal_badge) -// RelativeLayout mPersonalBadge; -// @BindView(R.id.personal_badge_tv) -// TextView mPersonalBadgeTv; -// @BindView(R.id.personal_badge_icon) -// SimpleDraweeView mPersonalBadgeIcon; -// @BindView(R.id.personal_badge_tips) -// View mPersonalBadgeTips; - @BindView(R.id.personal_badge) - RelativeLayout mPersonalBadge; - @BindView(R.id.personal_badge_icon) - SimpleDraweeView mPersonalBadgeIcon; - @BindView(R.id.personalMyBadgeIcon) - ImageView mPersonalMyBadgeIcon; - @BindView(R.id.personal_badge_count_tv) - TextView mPersonalBadgeCountTv; - @BindView(R.id.personal_badge_tv) - ImageView mPersonalBadgeTv; - @BindView(R.id.personal_badge_tips) - View mPersonalBadgeTips; - @BindView(R.id.personal_func) - RecyclerView mFuncRecyclerView; - @BindView(R.id.personal_new_fans_tips) - View personalNewFansTips; - @BindView(R.id.personal_background) - SimpleDraweeView mPersonalBackground; - @BindView(R.id.personal_background_shadow) - View mPersonalBackgroundShadow; - - public final static String LOGIN_TAG = "login_tag"; //登入标识 - public final static String LOGOUT_TAG = "logout_tag"; // 登出标识 - private final static String MESSAGE_READ_OVER = "MESSAGE_READ_OVER"; - private final static String SP_BADGE_RECORD_SEVEN_DAY = "badgeRecordSevenDay"; - private final static int REQUEST_MESSAGE = 199; - - private UserInfoEntity mUserInfoEntity; - - private AppDatabase mDatabase; - - private UserViewModel mUserViewModel; - private MessageUnreadViewModel mUnreadViewModel; - private UserHomeViewModel mUserHomeViewModel; - private PersonalViewModel mPersonalViewModel; - - private PersonalFunctionGroupAdapter mPersonalFuncGroupAdapter; - - private boolean mIsLogging = false; - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (requestCode == Constants.REQUEST_LOGIN) { // QQ Login callback - LoginHelper.onQQLoginCallback(requestCode, resultCode, data); - } else if (requestCode == 32973) {// 32973 WeiBo requestCode - LoginHelper.onWeiboLoginCallback(requestCode, resultCode, data); - } else if (requestCode == REQUEST_MESSAGE) { - if (mUnreadViewModel != null) mUnreadViewModel.retry(); - } - } - - @Override - protected int getLayoutId() { - return R.layout.fragment_personal_stub; - } - - @Override - protected boolean useButterKnife() { - return false; - } - - @SuppressLint("CheckResult") - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mDatabase = AppDatabase.getInstance(getContext()); - final UserViewModel.Factory factory = new UserViewModel.Factory(getActivity().getApplication()); - mUserViewModel = ViewModelProviders.of(this, factory).get(UserViewModel.class); - mUserHomeViewModel = ViewModelProviders.of(this, new UserHomeViewModel.Factory(HaloApp.getInstance().getApplication(), - UserManager.getInstance().getUserId())).get(UserHomeViewModel.class); - mUnreadViewModel = ViewModelProviders.of(this, - new MessageUnreadViewModel.Factory(HaloApp.getInstance().getApplication())).get(MessageUnreadViewModel.class); - mPersonalViewModel = ViewModelProviders.of(this).get(PersonalViewModel.class); - - observeNoneUIRelatedChanges(); - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - if (BuildConfig.DEBUG || BuildConfig.BUILD_TIME != 0) { - View indicator = requireActivity() - .getWindow() - .getDecorView() - .findViewById(android.R.id.content) - .findViewById(BaseActivity.ID_ROOT_INDICATOR); - indicator.setOnClickListener(v -> - requireContext().startActivity(NewPersonalActivity.Companion.getIntent(requireContext())) - ); - } - } - - @Override - public void onFragmentFirstVisible() { - super.onFragmentFirstVisible(); - - inflateRealView(); - observeUIRelatedChanges(); - } - - private void inflateRealView() { - try { - mCachedView = ((ViewStub) (mCachedView.findViewById(R.id.stub))).inflate(); - } catch (Exception e) { - e.printStackTrace(); - } - - ButterKnife.bind(this, mCachedView); - - mPersonalFuncGroupAdapter = new PersonalFunctionGroupAdapter(requireContext()); - mFuncRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); - mFuncRecyclerView.setAdapter(mPersonalFuncGroupAdapter); - mFuncRecyclerView.addItemDecoration(new VerticalItemDecoration(requireContext(), 8f, false)); - - int statusBarHeight = Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT ? 0 : DisplayUtils.getStatusBarHeight(getResources()); - ViewGroup.LayoutParams params = toolbar.getLayoutParams(); - params.height = DisplayUtils.dip2px(50) + statusBarHeight; - toolbar.setLayoutParams(params); - - appbar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> { - int absOffset = Math.abs(verticalOffset); - int invisibleOffset = DisplayUtils.dip2px(56F + 48F - 50F) - DisplayUtils.getStatusBarHeight(getResources()); - if (absOffset <= invisibleOffset) { - mUserIconSmall.setVisibility(View.GONE); - mPersonalUserNameSmall.setVisibility(View.GONE); - toolbar.setBackground(null); - } else { - mUserIconSmall.setVisibility(View.VISIBLE); - mPersonalUserNameSmall.setVisibility(View.VISIBLE); - toolbar.setBackgroundResource(R.drawable.personal_top_bg); - } - mListRefresh.setEnabled(absOffset <= 2); - }); - mListRefresh.setColorSchemeColors(ContextCompat.getColor(requireContext(), R.color.theme)); - mListRefresh.setProgressViewOffset(false, 0, DisplayUtils.dip2px(80) + DisplayUtils.getStatusBarHeight(requireContext().getResources())); - mListRefresh.setOnRefreshListener(() -> { - mPersonalViewModel.getHaloAddons(); - if (CheckLoginUtils.isLogin()) { - mUnreadViewModel.retry(); - MessageUnreadRepository.INSTANCE.loadMessageUnreadTotal(false); - mUserHomeViewModel.getBadgeList(); - mUserHomeViewModel.availableBadges(); - } - mBaseHandler.postDelayed(() -> { - mListRefresh.setRefreshing(false); - }, 2000); - MtaHelper.onEvent("我的光环_新", "下拉刷新", "下拉刷新"); - }); - MessageUnreadRepository.INSTANCE.loadMessageUnreadTotal(true); - } - - private void observeNoneUIRelatedChanges() { - mPersonalViewModel.getHaloAddons(); - mUserViewModel.getLoginObsUserinfo().observe(this, userInfoEntity -> { - UserInfoEntity notifyUserInfo; - if (userInfoEntity != null) { - notifyUserInfo = userInfoEntity.getData(); - } else { - notifyUserInfo = null; - } - - if (notifyUserInfo != null && mUserInfoEntity == null) { // 单个用户,首次触发 - EventBus.getDefault().post(new EBConcernChanged()); - - LoginTokenEntity loginTokenEntity = UserManager.getInstance().getLoginTokenEntity(); - if (mIsLogging && loginTokenEntity != null) { - String loginType = loginTokenEntity.getLoginType(); - LogUtils.login("success", loginType, getLoginEntranceByType(loginType)); - mIsLogging = false; - } - } - - mUserInfoEntity = notifyUserInfo; - if (notifyUserInfo == null) { - mUnreadViewModel.clean(); - EventBus.getDefault().post(new EBConcernChanged()); - } - }); - - mPersonalViewModel.getHaloAddData().observe(this, datas -> { - if (!datas.isEmpty()) { - MessageUnreadRepository.INSTANCE.loadMessageUnreadTotal(false); - } - }); - - mUnreadViewModel.getLiveData().observe(this - , messageUnread -> { - if (messageUnread != null && messageUnread.getTotal() > 0) { - // 第一次开启应用时检查消息中心看有没有未读消息确定需不需要弹 Notifier 通知 - showNotifier(messageUnread); - } - }); - } - - @SuppressLint("CheckResult") - private void observeUIRelatedChanges() { - mUserViewModel.getLoginObsUserinfo().observe(this, userInfoEntity -> { - if (userInfoEntity != null && userInfoEntity.getData() != null) { - changeLoginState(true); - } else { - changeLoginState(false); - } - }); - - mUserHomeViewModel.getBadges().observe(this, badgeEntities -> { - mPersonalBadgeIcon.setImageURI(""); - - if (badgeEntities.isEmpty()) { - mPersonalBadgeTv.setVisibility(View.GONE); - mPersonalBadgeCountTv.setVisibility(View.GONE); - mPersonalMyBadgeIcon.setVisibility(View.VISIBLE); - } else { - mPersonalBadgeTv.setVisibility(View.VISIBLE); - mPersonalBadgeCountTv.setVisibility(View.VISIBLE); - mPersonalMyBadgeIcon.setVisibility(View.GONE); - mPersonalBadgeCountTv.setText(badgeEntities.size() + ""); - - for (BadgeEntity badgeEntity : badgeEntities) { - if (badgeEntity.getWear()) { - ImageUtils.display(mPersonalBadgeIcon, badgeEntity.getIcon()); - - mPersonalBadgeIcon.setOnClickListener(v -> DialogUtils.showViewBadgeDialog(requireContext(), new Badge(badgeEntity.getName(), badgeEntity.getIcon(), badgeEntity.getActions()), - () -> DirectUtils.directToBadgeWall(requireContext(), mUserInfoEntity.getUserId(), mUserInfoEntity.getName(), mUserInfoEntity.getIcon()))); - - break; - } - } - } -// mPersonalBadgeIcon.setImageURI(""); -// -// if (badgeEntities.isEmpty()) { -// mPersonalBadgeTv.setText("我的徽章"); -// } else { -// mPersonalBadgeTv.setText(String.format(Locale.CHINA, "%d枚徽章", badgeEntities.size())); -// -// for (BadgeEntity badgeEntity : badgeEntities) { -// if (badgeEntity.getWear()) { -// ImageUtils.display(mPersonalBadgeIcon, badgeEntity.getIcon()); -// -// mPersonalBadgeIcon.setOnClickListener(v -> DialogUtils.showViewBadgeDialog(requireContext(), new Badge(badgeEntity.getName(), badgeEntity.getIcon(), badgeEntity.getActions()), -// () -> DirectUtils.directToBadgeWall(requireContext(), mUserInfoEntity.getUserId(), mUserInfoEntity.getName(), mUserInfoEntity.getIcon()))); -// -// break; -// } -// } -// } - }); - mUserHomeViewModel.getAvailableBadgeCount().observe(this, count -> mPersonalBadgeTips.setVisibility(count > 0 ? View.VISIBLE : View.GONE)); - - mUserHomeViewModel.getAvailableBadge().observe(this, badge -> { - // 徽章领取弹窗每隔7天弹出一次,所以要判断现在是否是上一次弹出的第7天或者之后 - if (badge != null && System.currentTimeMillis() >= SPUtils.getLong(SP_BADGE_RECORD_SEVEN_DAY)) { - // 徽章领取弹窗每隔7天弹出一次,所以本次弹出后就记录7天后的时间戳 - SPUtils.setLong(SP_BADGE_RECORD_SEVEN_DAY, TimeUtils.getStartTimeOfDay(System.currentTimeMillis() + 86400000 * 6)); - - DialogUtils.showReceiveBadgeDialog(requireContext(), badge, - () -> RetrofitManager.getInstance(requireContext()).getApi() - .applyOrReceiveBadge(badge.getId()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new BiResponse() { - @Override - public void onSuccess(ResponseBody data) { - if ("self".equals(badge.getReceive().getType())) { - ToastUtils.INSTANCE.showToast("领取成功"); - } else { - ToastUtils.INSTANCE.showToast("申请成功"); - } - // 跳转到徽章详情 - DirectUtils.directToBadgeDetail(requireContext(), mUserInfoEntity.getUserId(), badge.getId()); - } - - @Override - public void onFailure(@NotNull Exception exception) { - super.onFailure(exception); - if ("self".equals(badge.getReceive().getType())) { - ToastUtils.INSTANCE.showToast("领取失败"); - } else { - ToastUtils.INSTANCE.showToast("申请失败"); - } - } - })); - } - }); - - mPersonalViewModel.getHaloAddData().observe(this, datas -> { - if (!datas.isEmpty()) { - mPersonalFuncGroupAdapter.setListData(datas); - checkUpdate(); - } - }); - - mUnreadViewModel.getLiveData().observe(this - , messageUnread -> { - if (messageUnread != null && messageUnread.getTotal() > 0) { - personalNewFansTips.setVisibility(messageUnread.getFans() > 0 ? View.VISIBLE : View.GONE); - mPersonalHome.setText(messageUnread.getFans() > 0 ? ((messageUnread.getFans() < 100 ? messageUnread.getFans() : "99+") + "位新粉丝") : "个人主页"); - int count = messageUnread.getTotal() - messageUnread.getFans(); - mLoginMessageHint.setVisibility(count > 0 ? View.VISIBLE : View.GONE); - BindingAdapters.setMessageUnread(mLoginMessageHint, count); - } else { - mLoginMessageHint.setVisibility(View.GONE); - mPersonalHome.setText("个人主页"); - personalNewFansTips.setVisibility(View.GONE); - EventBus.getDefault().post(new EBReuse(MESSAGE_READ_OVER)); - } - }); - mUnreadViewModel.getZixunConcernLiveData().observe(this, hasConcern -> { - notifyItemChange("游戏动态", hasConcern ? FunctionalMessageType.NEW_MESSAGE : null); - }); - mUnreadViewModel.getAddonsUnreadLiveData().observe(this, entity -> { - notifyItemChange("我的收藏", entity.getFavorite() > 0 ? FunctionalMessageType.NEW_MESSAGE : null); - }); - - // 微信/签到 - RxView.clicks(mPersonalSign) - .throttleFirst(1, TimeUnit.SECONDS) - .subscribe(aVoid -> { - if (CheckLoginUtils.isLogin()) { - MtaHelper.onEvent("我的光环", "签到"); - MtaHelper.onEvent("我的光环_新", "签到", "点击签到"); - sign(); - } else { - MtaHelper.onEvent("我的光环_新", "功能入口-跳转登录", "签到"); - CheckLoginUtils.checkLogin(getContext(), "我的光环-签到", () -> { - }); - } - }); - } - - @Override - public void onFragmentResume() { - super.onFragmentResume(); - - if (NetworkUtils.isNetworkConnected(requireContext())) { - mUnreadViewModel.retry(); - mUserHomeViewModel.getBadgeList(); - mUserHomeViewModel.availableBadges(); - } - int currentItem = ((MainWrapperFragment) getParentFragment()).getCurrentItem(); - if (currentItem == INDEX_PERSONAL) { - DisplayUtils.setLightStatusBar(requireActivity(), false); - } - } - - private void showNotifier(MessageUnreadEntity messageUnread) { - if (mUnreadViewModel.isFirstTimeInit()) { - mUnreadViewModel.flagFirstTimeInit(false); - - if (messageUnread.getMeta() != null && messageUnread.getMeta().getUser() != null) { - if (messageUnread.getMeta() != null) { - String displayText = StringUtils.shrinkStringWithDot(messageUnread.getMeta().getUser().getName(), 8); - String suffixText; - if ("follow_question".equals(messageUnread.getMeta().getType())) { - suffixText = "回答了你关注的问题"; - } else { - suffixText = "回答了你的问题"; - } - displayText += suffixText; - - String content = messageUnread.getMeta().getAnswerId() + displayText; - - if (Notifier.shouldShowNotifier(content)) { - Notifier.create(getActivity()) - .setText(displayText) - .setDuration(5000) - .setIcon(messageUnread.getMeta().getUser().getIcon()) - .setOnClickListener(view -> { - Bundle bundle = new Bundle(); - bundle.putString(EntranceUtils.KEY_ANSWER_ID, messageUnread.getMeta().getAnswerId()); - bundle.putString(EntranceUtils.KEY_ENTRANCE, EntranceUtils.ENTRANCE_UMENG); - bundle.putString(EntranceUtils.KEY_TO, SimpleAnswerDetailActivity.class.getName()); - EntranceUtils.jumpActivity(getActivity(), bundle); - - MtaHelper.onEvent("消息弹窗", suffixText, "Does not contains any parameter."); - - // 标记已读 - JSONObject jsonObject = new JSONObject(); - try { - jsonObject.put("type", messageUnread.getMeta().getType()); - RequestBody body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString()); - RetrofitManager.getInstance(requireContext()).getApi() - .postMessageRead(UserManager.getInstance().getUserId(), messageUnread.getMeta().getMessageId(), body) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Response() { - @Override - public void onResponse(@Nullable ResponseBody response) { - super.onResponse(response); - MessageUnreadRepository.INSTANCE.loadMessageUnreadData(); - } - }); - } catch (Exception e) { - e.printStackTrace(); - } - - Notifier.hide(); - }) - .show(true, 500L); - Notifier.tagNotifierAsShowed(content); - } - } - } - } - } - - @OnClick({R.id.toolbar, R.id.collapsingToolbar, R.id.iv_arrow, R.id.personal_info, R.id.personal_login, R.id.personal_user_small_icon, R.id.personal_user_icon, R.id.personal_msg, - R.id.personal_user_name_small, R.id.personal_user_name, R.id.personal_badge, R.id.personal_home}) - public void onViewClicked(View view) { - switch (view.getId()) { - case R.id.collapsingToolbar: - case R.id.toolbar: - case R.id.personal_info: - if (mUserInfoEntity == null) { - CheckLoginUtils.checkLogin(getContext(), "我的光环-手机登录", null); - } - break; - case R.id.personal_login: - MtaHelper.onEvent("我的光环_新", "立即登录", "点击登录"); - CheckLoginUtils.checkLogin(getContext(), "我的光环-立即登录", null); - break; - case R.id.personal_msg: - if (CheckLoginUtils.isLogin()) { - MtaHelper.onEvent("我的光环", "消息"); - MtaHelper.onEvent("我的光环_新", "消息中心", "点击消息中心"); - startActivityForResult(MessageActivity.getIntent(getContext(), "(我的光环)+(消息中心)"), REQUEST_MESSAGE); - } else { - MtaHelper.onEvent("我的光环_新", "功能入口-跳转登录", "消息中心"); - CheckLoginUtils.checkLogin(getContext(), "我的光环-消息", () -> { - }); - } - break; - case R.id.personal_user_small_icon: - case R.id.personal_user_icon: - if (mUserInfoEntity != null) { - MtaHelper.onEvent("我的光环", "个人中心"); - MtaHelper.onEvent("我的光环_新", "头像", "点击头像"); - DirectUtils.directToHomeActivity(requireContext(), UserManager.getInstance().getUserId(), "", "我的光环"); - } else { - MtaHelper.onEvent("我的光环", "手机登录"); - CheckLoginUtils.checkLogin(getContext(), "我的光环-手机登录", null); - } - break; - case R.id.personal_user_name_small: - case R.id.personal_user_name: - if (mUserInfoEntity != null) { - MtaHelper.onEvent("我的光环", "个人中心"); - MtaHelper.onEvent("我的光环_新", "昵称", "点击昵称"); - DirectUtils.directToHomeActivity(requireContext(), UserManager.getInstance().getUserId(), "", "我的光环"); - } else { - MtaHelper.onEvent("我的光环", "手机登录"); - CheckLoginUtils.checkLogin(getContext(), "我的光环-手机登录", null); - } - break; - case R.id.iv_arrow: - case R.id.personal_home: - if (mUserInfoEntity != null) { - MtaHelper.onEvent("我的光环", "个人主页"); - MtaHelper.onEvent("我的光环_新", "个人主页", "进入个人主页"); - DirectUtils.directToHomeActivity(requireContext(), UserManager.getInstance().getUserId(), "", "我的光环"); - } else { - CheckLoginUtils.checkLogin(getContext(), "我的光环-个人主页", null); - } - break; - case R.id.personal_badge: - MtaHelper.onEvent("我的光环_新", "徽章中心", "进入徽章中心"); - DirectUtils.directToBadgeWall(requireContext(), mUserInfoEntity.getUserId(), mUserInfoEntity.getName(), mUserInfoEntity.getIcon()); - break; - default: - break; - } - } - - // 连接上网络事件 - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(EBNetworkState busNetworkState) { - if (busNetworkState.isNetworkConnected() - && UserManager.getInstance().isLoggedIn() - && (mUserInfoEntity == null || TextUtils.isEmpty(UserManager.getInstance().getToken()))) { - mUserViewModel.retryCheckLogin(); - } - if (busNetworkState.isNetworkConnected()) { - mPersonalViewModel.getHaloAddons(); - } - } - -// @Subscribe(threadMode = ThreadMode.MAIN) -// public void onEventMainThread(EBUISwitch busNine) { -// if (MainWrapperFragment.EB_MAIN_SCROLL_TOP.equals(busNine.getFrom()) -// && INDEX_PERSONAL == busNine.getPosition()) { -// //mScrollView.fullScroll(ScrollView.FOCUS_UP); -// } -// } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(EBReuse reuse) { - if (MESSAGE_READ_OVER.equals(reuse.getType())) { // 消息阅读完成 - if (mLoginMessageHint != null) { - mLoginMessageHint.setVisibility(View.GONE); - } - } - } - - private void sign() { - RetrofitManager.getInstance(getContext()).getApi() - .postSign(UserManager.getInstance().getUserId()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Response() { - @Override - public void onResponse(SignEntity signEntity) { - mPersonalSign.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.personal_sign_icon_yellow)); - if (isCanSign(signEntity.getLastTime())) { - DialogUtils.showSignDialog(getContext(), "签到成功,获得经验:1" - , getString(R.string.sign_dialog_content, signEntity.getSerialSign()) - , getString(R.string.sign_dialog_content2, signEntity.getExperience()) - , getSignSkipText(signEntity.getTitle()), () -> { - signSkip(signEntity); - } - ); - signEntity.setLastTime(System.currentTimeMillis() / 1000); - } else { - DialogUtils.showSignDialog(getContext(), "今天已签到,明天再来吧~" - , getString(R.string.sign_dialog_content, signEntity.getSerialSign()) - , getString(R.string.sign_dialog_content2, signEntity.getExperience()) - , getSignSkipText(signEntity.getTitle()), () -> { - signSkip(signEntity); - } - ); - } - - signEntity.setId(UserManager.getInstance().getUserId()); - if (mDatabase.signDao().updateSignEntity(signEntity) <= 0) { - try { - mDatabase.signDao().addSignEntity(signEntity); - } catch (SQLiteException e) { - e.printStackTrace(); - } - } - } - - @Override - public void onFailure(HttpException e) { - if (e == null || e.code() != 401) { - toast(R.string.loading_network_error); - } - } - }); - - } - - private boolean isCanSign(long time) { - SimpleDateFormat formatDay = new SimpleDateFormat("dd", Locale.CHINA); - - long lastSignTime = time * 1000; - long curTime = Utils.getTime(getContext()) * 1000; - int lastSignDay = Integer.parseInt(formatDay.format(lastSignTime)); - int curDay = Integer.parseInt(formatDay.format(curTime)); - return lastSignDay != curDay || curTime - lastSignTime > 24 * 60 * 60 * 1000; - } - - private String getSignSkipText(String text) { - return TextUtils.isEmpty(text) ? "去首页看看" : text; - } - - private void signSkip(SignEntity signEntity) { - SignEntity.Data data = signEntity.getData(); - String entrance = "(我的光环)+(签到)"; - if (data == null || TextUtils.isEmpty(data.getType())) { - EventBus.getDefault().post(new EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_HOME)); - return; - } - switch (data.getType()) { - case "game": - DataUtils.onMtaEvent(getActivity(), "我的光环_签到跳转", "游戏", signEntity.getTitle()); - GameDetailActivity.startGameDetailActivity(getContext(), data.getLink(), entrance); - break; - case "news": - DataUtils.onMtaEvent(getActivity(), "我的光环_签到跳转", "文章", signEntity.getTitle()); - startActivity(NewsDetailActivity.getIntentById(getContext(), data.getLink(), entrance)); - break; - case "column": - DataUtils.onMtaEvent(getActivity(), "我的光环_签到跳转", "专题", signEntity.getTitle()); - SubjectActivity.startSubjectActivity(getContext(), data.getLink(), null, false, entrance); - break; - - default: - LinkEntity linkEntity = new LinkEntity(); - linkEntity.setType(data.getType()); - linkEntity.setLink(data.getLink()); - linkEntity.setText(data.getText()); - linkEntity.setCommunity(data.getCommunity()); - linkEntity.setDisplay(data.getDisplay()); - DirectUtils.directToLinkPage(requireContext(), linkEntity, entrance, ""); - break; - } - } - - private static String getLoginEntranceByType(String loginTag) { - String entrance = ""; - switch (loginTag) { - case "qq": - entrance = "我的光环-QQ"; - break; - case "wechat": - entrance = "我的光环-微信"; - break; - case "weibo": - entrance = "我的光环-新浪微博"; - break; - } - return entrance; - } - - private void changeLoginState(boolean isLogin) { - if (isLogin) { - // 设置背景 - if (mUserInfoEntity.getBackground() != null) { - ImageUtils.display(mPersonalBackground, mUserInfoEntity.getBackground().getUrl()); - // 自定义背景才需要加阴影 - if (TextUtils.isEmpty(mUserInfoEntity.getBackground().getId())) { - mPersonalBackgroundShadow.setVisibility(View.VISIBLE); - } - } else { - ImageUtils.display(mPersonalBackground, R.drawable.bg_home_user_info); - } - - SignEntity signEntity = mDatabase.signDao().getSignEntityById(UserManager.getInstance().getUserId()); - if (signEntity != null && !isCanSign(signEntity.getLastTime())) { - mPersonalSign.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.personal_sign_icon_yellow)); - } else { - mPersonalSign.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.personal_sign_icon_white)); - } - if (mUserInfoEntity != null) { - mUserIcon.display(mUserInfoEntity.getIconBorder() == null ? "" : mUserInfoEntity.getIconBorder().getUrl(), - mUserInfoEntity.getIcon(), mUserInfoEntity.getAuth() == null ? "" : mUserInfoEntity.getAuth().getIcon()); - ImageUtils.displayIcon(mUserIconSmall, mUserInfoEntity.getIcon()); - mPersonalUserName.setVisibility(View.VISIBLE); - mPersonalBadge.setVisibility(View.VISIBLE); - mPersonalHome.setVisibility(View.VISIBLE); - mPersonalLogin.setVisibility(View.GONE); - mPersonalUserName.setText(mUserInfoEntity.getName()); - mPersonalUserNameSmall.setText(mUserInfoEntity.getName()); - } - mUserHomeViewModel.setUserId(UserManager.getInstance().getUserId()); - mUserHomeViewModel.getBadgeList(); - mUserHomeViewModel.availableBadges(); - MessageUnreadRepository.INSTANCE.loadMessageUnreadTotal(true); - } else { - ImageUtils.display(mPersonalBackground, R.drawable.personal_top_bg); - mPersonalBackgroundShadow.setVisibility(View.GONE); - mUserIcon.display("", "", ""); - mUserIconSmall.setImageURI(""); -// mPersonalBadgeTv.setText("我的徽章"); - mPersonalUserNameSmall.setText("立即登录"); - mPersonalUserName.setVisibility(View.GONE); - mPersonalHome.setVisibility(View.GONE); - mPersonalBadge.setVisibility(View.GONE); - mPersonalLogin.setVisibility(View.VISIBLE); - - if (mLoginMessageHint.getVisibility() == View.VISIBLE) { - mLoginMessageHint.setVisibility(View.GONE); - EventBus.getDefault().post(new EBReuse(MESSAGE_READ_OVER)); - } - } - } - - private void checkUpdate() { - String channel = HaloApp.getInstance().getChannel(); - RetrofitManager.getInstance(getContext()) - .getApi() - .getUpdate(PackageUtils.getVersionName(), PackageUtils.getVersionCode(), channel) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Response() { - @Override - public void onResponse(AppEntity response) { - super.onResponse(response); - if (response.getVersionCode() > PackageUtils.getVersionCode()) { - notifyItemChange("设置", FunctionalMessageType.NEW_VERSION); - } else { - notifyItemChange("设置", null); - } - } - }); - } - - private void notifyItemChange(String funcName, FunctionalMessageType msg) { - ArrayList mEntityList = mPersonalFuncGroupAdapter.getMEntityList(); - for (FunctionalGroupEntity mEntity : mEntityList) { - for (FunctionalLinkEntity linkEntity : mEntity.getAddons()) { - if (TextUtils.equals(linkEntity.getType(), funcName)) { - linkEntity.setMessage(msg); - break; - } - } - } - mPersonalFuncGroupAdapter.notifyDataSetChanged(); - } -} diff --git a/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.kt b/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.kt new file mode 100644 index 0000000000..6708a61769 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.kt @@ -0,0 +1,779 @@ +package com.gh.gamecenter.personal + +import android.annotation.SuppressLint +import android.content.Intent +import android.database.sqlite.SQLiteException +import android.os.Build +import android.os.Bundle +import android.text.TextUtils +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.LinearLayoutManager +import com.gh.base.BaseActivity +import com.gh.base.fragment.BaseLazyFragment +import com.gh.common.databind.BindingAdapters +import com.gh.common.notifier.Notifier.Companion.create +import com.gh.common.notifier.Notifier.Companion.hide +import com.gh.common.notifier.Notifier.Companion.shouldShowNotifier +import com.gh.common.notifier.Notifier.Companion.tagNotifierAsShowed +import com.gh.common.util.* +import com.gh.common.util.DirectUtils.directToBadgeDetail +import com.gh.common.util.DirectUtils.directToBadgeWall +import com.gh.common.util.DirectUtils.directToHomeActivity +import com.gh.common.util.ImageUtils.display +import com.gh.common.util.ImageUtils.displayIcon +import com.gh.common.util.LoginHelper.onQQLoginCallback +import com.gh.common.util.LoginHelper.onWeiboLoginCallback +import com.gh.common.util.MtaHelper.onEvent +import com.gh.common.util.SPUtils.getLong +import com.gh.common.util.SPUtils.setLong +import com.gh.common.util.TimeUtils.getStartTimeOfDay +import com.gh.common.util.ToastUtils.showToast +import com.gh.common.view.VerticalItemDecoration +import com.gh.gamecenter.BuildConfig +import com.gh.gamecenter.MessageActivity +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.FragmentPersonalBinding +import com.gh.gamecenter.databinding.FragmentPersonalStubBinding +import com.gh.gamecenter.entity.* +import com.gh.gamecenter.eventbus.EBConcernChanged +import com.gh.gamecenter.eventbus.EBNetworkState +import com.gh.gamecenter.eventbus.EBReuse +import com.gh.gamecenter.fragment.MainWrapperFragment +import com.gh.gamecenter.manager.UserManager +import com.gh.gamecenter.message.MessageUnreadRepository.loadMessageUnreadData +import com.gh.gamecenter.message.MessageUnreadRepository.loadMessageUnreadTotal +import com.gh.gamecenter.message.MessageUnreadViewModel +import com.gh.gamecenter.personal.NewPersonalActivity.Companion.getIntent +import com.gh.gamecenter.personalhome.UserHomeViewModel +import com.gh.gamecenter.qa.answer.detail.SimpleAnswerDetailActivity +import com.gh.gamecenter.room.AppDatabase +import com.gh.gamecenter.user.ApiResponse +import com.gh.gamecenter.user.UserViewModel +import com.google.android.material.appbar.AppBarLayout +import com.halo.assistant.HaloApp +import com.jakewharton.rxbinding2.view.RxView +import com.tencent.connect.common.Constants +import okhttp3.MediaType +import okhttp3.RequestBody +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import org.json.JSONObject +import java.util.* +import java.util.concurrent.TimeUnit +import kotlin.math.abs + +class PersonalFragment : BaseLazyFragment() { + private var mUserInfoEntity: UserInfoEntity? = null + + private lateinit var mDatabase: AppDatabase + + private lateinit var mBinding: FragmentPersonalStubBinding + private lateinit var mStubBinding: FragmentPersonalBinding + private lateinit var mUserViewModel: UserViewModel + private lateinit var mUnreadViewModel: MessageUnreadViewModel + private lateinit var mUserHomeViewModel: UserHomeViewModel + private lateinit var mPersonalViewModel: PersonalViewModel + + private lateinit var mPersonalFuncGroupAdapter: PersonalFunctionGroupAdapter + + private var mIsLogging = false + + override fun getInflatedLayout(): View { + mBinding = DataBindingUtil.inflate(layoutInflater, R.layout.fragment_personal_stub, null, false) + mBinding.stub.setOnInflateListener { _, inflateId -> + mStubBinding = FragmentPersonalBinding.bind(inflateId) + } + return mBinding.root + } + + override fun getLayoutId() = R.layout.fragment_personal_stub + + override fun useButterKnife() = false + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + Constants.REQUEST_LOGIN -> { + onQQLoginCallback(requestCode, resultCode, data) + } + 32973 -> { + onWeiboLoginCallback(requestCode, resultCode, data) + } + REQUEST_MESSAGE -> { + mUnreadViewModel.retry() + } + } + } + + override fun onClick(v: View?) { + super.onClick(v) + mStubBinding.run { + when (v) { + collapsingToolbar, + toolbar, + personalInfo -> { + if (mUserInfoEntity == null) { + CheckLoginUtils.checkLogin(context, "我的光环-手机登录", null) + } + } + personalLogin -> { + onEvent("我的光环_新", "立即登录", "点击登录") + CheckLoginUtils.checkLogin(context, "我的光环-立即登录", null) + } + personalMsg -> { + if (CheckLoginUtils.isLogin()) { + onEvent("我的光环", "消息") + onEvent("我的光环_新", "消息中心", "点击消息中心") + startActivityForResult( + MessageActivity.getIntent(context, "(我的光环)+(消息中心)"), + REQUEST_MESSAGE + ) + } else { + onEvent("我的光环_新", "功能入口-跳转登录", "消息中心") + CheckLoginUtils.checkLogin(context, "我的光环-消息") {} + } + } + personalUserSmallIcon, personalUserIcon -> { + if (mUserInfoEntity != null) { + onEvent("我的光环", "个人中心") + onEvent("我的光环_新", "头像", "点击头像") + directToHomeActivity( + requireContext(), + UserManager.getInstance().userId, + "", + "我的光环" + ) + } else { + onEvent("我的光环", "手机登录") + CheckLoginUtils.checkLogin(context, "我的光环-手机登录", null) + } + } + personalUserNameSmall, personalUserName -> { + if (mUserInfoEntity != null) { + onEvent("我的光环", "个人中心") + onEvent("我的光环_新", "昵称", "点击昵称") + directToHomeActivity( + requireContext(), + UserManager.getInstance().userId, + "", + "我的光环" + ) + } else { + onEvent("我的光环", "手机登录") + CheckLoginUtils.checkLogin(context, "我的光环-手机登录", null) + } + } + ivArrow, personalHome -> { + if (mUserInfoEntity != null) { + onEvent("我的光环", "个人主页") + onEvent("我的光环_新", "个人主页", "进入个人主页") + directToHomeActivity( + requireContext(), + UserManager.getInstance().userId, + "", + "我的光环" + ) + } else { + CheckLoginUtils.checkLogin(context, "我的光环-个人主页", null) + } + } + personalBadge -> { + onEvent("我的光环_新", "徽章中心", "进入徽章中心") + directToBadgeWall( + requireContext(), + mUserInfoEntity?.userId, + mUserInfoEntity?.name, + mUserInfoEntity?.icon + ) + } + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + mDatabase = AppDatabase.getInstance(context) + val factory = UserViewModel.Factory(requireActivity().application) + mUserViewModel = ViewModelProvider(this, factory).get(UserViewModel::class.java) + mUserHomeViewModel = ViewModelProvider( + this, UserHomeViewModel.Factory( + HaloApp.getInstance().application, + UserManager.getInstance().userId + ) + ).get(UserHomeViewModel::class.java) + mUnreadViewModel = ViewModelProvider( + this, + MessageUnreadViewModel.Factory(HaloApp.getInstance().application) + ).get(MessageUnreadViewModel::class.java) + mPersonalViewModel = ViewModelProvider(this).get(PersonalViewModel::class.java) + + observeNoneUIRelatedChanges() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + if (BuildConfig.DEBUG || BuildConfig.BUILD_TIME != 0L) { + val indicator = requireActivity() + .window + .decorView + .findViewById(android.R.id.content) + .findViewById(BaseActivity.ID_ROOT_INDICATOR) + indicator.setOnClickListener { + requireContext().startActivity( + getIntent(requireContext()) + ) + } + } + } + + override fun onFragmentFirstVisible() { + super.onFragmentFirstVisible() + inflateRealView() + observeUIRelatedChanges() + } + + override fun onFragmentResume() { + super.onFragmentResume() + + if (NetworkUtils.isNetworkConnected(requireContext())) { + mUnreadViewModel.retry() + mUserHomeViewModel.getBadgeList() + mUserHomeViewModel.availableBadges() + } + val currentItem = (parentFragment as MainWrapperFragment).currentItem + if (currentItem == MainWrapperFragment.INDEX_PERSONAL) { + DisplayUtils.setLightStatusBar(requireActivity(), false) + } + } + + @SuppressLint("CheckResult") + private fun observeUIRelatedChanges() { + mPersonalViewModel.appEntity.observe(this, { + if (it.versionCode > PackageUtils.getGhVersionCode()) { + notifyItemChange("设置", FunctionalMessageType.NEW_VERSION) + } else { + notifyItemChange("设置", null) + } + }) + + mUserViewModel.loginObsUserinfo.observe( + this, + { userInfoEntity: ApiResponse? -> + if (userInfoEntity != null && userInfoEntity.data != null) { + changeLoginState(true) + } else { + changeLoginState(false) + } + }) + + mUserHomeViewModel.badges.observe(this, + { badgeEntities: List -> + mStubBinding.personalBadgeIcon.setImageURI("") + if (badgeEntities.isEmpty()) { + mStubBinding.personalBadgeTv.visibility = View.GONE + mStubBinding.personalBadgeCountTv.visibility = View.GONE + mStubBinding.personalMyBadgeIcon.visibility = View.VISIBLE + } else { + mStubBinding.personalBadgeTv.visibility = View.VISIBLE + mStubBinding.personalBadgeCountTv.visibility = View.VISIBLE + mStubBinding.personalMyBadgeIcon.visibility = View.GONE + mStubBinding.personalBadgeCountTv.text = badgeEntities.size.toString() + "" + for ((_, _, icon, name, _, wear, _, actions) in badgeEntities) { + if (wear) { + display( + mStubBinding.personalBadgeIcon, + icon + ) + mStubBinding.personalBadgeIcon.setOnClickListener { + DialogUtils.showViewBadgeDialog( + requireContext(), + Badge(name, icon, actions) + ) { + directToBadgeWall( + requireContext(), + mUserInfoEntity?.userId, + mUserInfoEntity?.name, + mUserInfoEntity?.icon + ) + } + } + break + } + } + } +// mStubBinding.personalBadgeIcon.setImageURI("") +// +// if (badgeEntities.isEmpty()) { +// mStubBinding.personalBadgeTv.setText("我的徽章") +// } else { +// mStubBinding.personalBadgeTv.setText( +// String.format( +// Locale.CHINA, +// "%d枚徽章", +// badgeEntities.size +// ) +// ) +// for ((_, _, icon, name, _, wear, _, actions) in badgeEntities) { +// if (wear) { +// display(mStubBinding.personalBadgeIcon, icon) +// mStubBinding.personalBadgeIcon.setOnClickListener(View.OnClickListener { v: View? -> +// DialogUtils.showViewBadgeDialog( +// requireContext(), +// Badge(name, icon, actions) +// ) { +// directToBadgeWall( +// requireContext(), +// mUserInfoEntity?.userId, +// mUserInfoEntity?.name, +// mUserInfoEntity?.icon +// ) +// } +// }) +// break +// } +// } +// } + }) + mUserHomeViewModel.availableBadgeCount.observe(this, + { count: Int -> + mStubBinding.personalBadgeTips.visibility = + if (count > 0) View.VISIBLE else View.GONE + }) + + mUserHomeViewModel.availableBadge.observe(this, + { badge: BadgeEntity? -> + // 徽章领取弹窗每隔7天弹出一次,所以要判断现在是否是上一次弹出的第7天或者之后 + if (badge != null && System.currentTimeMillis() >= getLong(SP_BADGE_RECORD_SEVEN_DAY)) { + // 徽章领取弹窗每隔7天弹出一次,所以本次弹出后就记录7天后的时间戳 + setLong( + SP_BADGE_RECORD_SEVEN_DAY, + getStartTimeOfDay(System.currentTimeMillis() + 86400000 * 6) + ) + DialogUtils.showReceiveBadgeDialog( + requireContext(), badge + ) { + mPersonalViewModel.applyOrReceiveBadge(badge.id, { + if ("self" == badge.receive?.type) { + showToast("领取成功") + } else { + showToast("申请成功") + } + // 跳转到徽章详情 + directToBadgeDetail( + requireContext(), + mUserInfoEntity?.userId, + badge.id + ) + }, { + if ("self" == badge.receive?.type) { + showToast("领取失败") + } else { + showToast("申请失败") + } + }) + } + } + }) + + mPersonalViewModel.haloAddData.observe( + this, + { datas: ArrayList -> + if (datas.isNotEmpty()) { + mPersonalFuncGroupAdapter.setListData(datas) + mPersonalViewModel.checkUpdate() + } + }) + + mUnreadViewModel.liveData.observe(this, { messageUnread: MessageUnreadEntity? -> + if (messageUnread != null && messageUnread.total > 0) { + mStubBinding.personalNewFansTips.visibility = + if (messageUnread.fans > 0) View.VISIBLE else View.GONE + mStubBinding.personalHome.text = + if (messageUnread.fans > 0) (if (messageUnread.fans < 100) messageUnread.fans else "99+").toString() + "位新粉丝" else "个人主页" + val count = messageUnread.total - messageUnread.fans + mStubBinding.loginMessageHint.visibility = + if (count > 0) View.VISIBLE else View.GONE + BindingAdapters.setMessageUnread(mStubBinding.loginMessageHint, count) + } else { + mStubBinding.loginMessageHint.visibility = View.GONE + mStubBinding.personalHome.text = "个人主页" + mStubBinding.personalNewFansTips.visibility = View.GONE + EventBus.getDefault() + .post(EBReuse(MESSAGE_READ_OVER)) + } + }) + mUnreadViewModel.zixunConcernLiveData.observe(this, + { hasConcern: Boolean -> + notifyItemChange( + "游戏动态", + if (hasConcern) FunctionalMessageType.NEW_MESSAGE else null + ) + }) + mUnreadViewModel.addonsUnreadLiveData.observe(this, + { (favorite) -> + notifyItemChange( + "我的收藏", + if (favorite > 0) FunctionalMessageType.NEW_MESSAGE else null + ) + }) + + // 微信/签到 + + // 微信/签到 + RxView.clicks(mStubBinding.personalSign) + .throttleFirst(1, TimeUnit.SECONDS) + .subscribe { + if (CheckLoginUtils.isLogin()) { + onEvent("我的光环", "签到") + onEvent("我的光环_新", "签到", "点击签到") + sign() + } else { + onEvent("我的光环_新", "功能入口-跳转登录", "签到") + CheckLoginUtils.checkLogin(context, "我的光环-签到") {} + } + } + } + + private fun sign() { + mPersonalViewModel.sign { signEntity -> + mStubBinding.personalSign.setImageDrawable( + ContextCompat.getDrawable( + requireContext(), + R.drawable.personal_sign_icon_yellow + ) + ) + if (mPersonalViewModel.isCanSign(signEntity.lastTime)) { + DialogUtils.showSignDialog( + context, + "签到成功,获得经验:1", + getString(R.string.sign_dialog_content, signEntity.serialSign), + getString(R.string.sign_dialog_content2, signEntity.experience), + getSignSkipText(signEntity.title) + ) { mPersonalViewModel.signSkip(signEntity) } + signEntity.lastTime = System.currentTimeMillis() / 1000 + } else { + DialogUtils.showSignDialog( + context, + "今天已签到,明天再来吧~", + getString(R.string.sign_dialog_content, signEntity.serialSign), + getString(R.string.sign_dialog_content2, signEntity.experience), + getSignSkipText(signEntity.title) + ) { mPersonalViewModel.signSkip(signEntity) } + } + signEntity.id = UserManager.getInstance().userId + if (mDatabase.signDao().updateSignEntity(signEntity) <= 0) { + try { + mDatabase.signDao().addSignEntity(signEntity) + } catch (e: SQLiteException) { + e.printStackTrace() + } + } + } + } + + private fun getSignSkipText(text: String): String = + if (TextUtils.isEmpty(text)) "去首页看看" else text + + private fun notifyItemChange(funcName: String, msg: FunctionalMessageType?) { + val mEntityList = mPersonalFuncGroupAdapter.mEntityList + for ((_, _, _, addons) in mEntityList) { + for (linkEntity in addons) { + if (TextUtils.equals(linkEntity.type, funcName)) { + linkEntity.message = msg + break + } + } + } + mPersonalFuncGroupAdapter.notifyDataSetChanged() + } + + private fun changeLoginState(isLogin: Boolean) { + if (isLogin) { + // 设置背景 + if (mUserInfoEntity?.background != null) { + display(mStubBinding.personalBackground, mUserInfoEntity?.background?.url) + // 自定义背景才需要加阴影 + if (TextUtils.isEmpty(mUserInfoEntity?.background?.id)) { + mStubBinding.personalBackgroundShadow.visibility = View.VISIBLE + } + } else { + display(mStubBinding.personalBackground, R.drawable.bg_home_user_info) + } + val signEntity = + mDatabase.signDao().getSignEntityById(UserManager.getInstance().userId) + if (signEntity != null && !mPersonalViewModel.isCanSign(signEntity.lastTime)) { + mStubBinding.personalSign.setImageDrawable( + ContextCompat.getDrawable( + requireContext(), + R.drawable.personal_sign_icon_yellow + ) + ) + } else { + mStubBinding.personalSign.setImageDrawable( + ContextCompat.getDrawable( + requireContext(), + R.drawable.personal_sign_icon_white + ) + ) + } + if (mUserInfoEntity != null) { + mStubBinding.personalUserIcon.display( + if (mUserInfoEntity?.iconBorder == null) "" else mUserInfoEntity?.iconBorder?.url, + mUserInfoEntity?.icon, + null + ) + displayIcon(mStubBinding.personalUserSmallIcon, mUserInfoEntity?.icon) + mStubBinding.personalUserName.visibility = View.VISIBLE + mStubBinding.personalBadge.visibility = View.VISIBLE + mStubBinding.personalHome.visibility = View.VISIBLE + mStubBinding.personalLogin.visibility = View.GONE + mStubBinding.personalUserName.text = mUserInfoEntity?.name + mStubBinding.personalUserNameSmall.text = mUserInfoEntity?.name + } + mUserHomeViewModel.userId = UserManager.getInstance().userId + mUserHomeViewModel.getBadgeList() + mUserHomeViewModel.availableBadges() + loadMessageUnreadTotal(true) + } else { + display(mStubBinding.personalBackground, R.drawable.personal_top_bg) + mStubBinding.personalBackgroundShadow.visibility = View.GONE + mStubBinding.personalUserIcon.display("", "", "") + mStubBinding.personalUserSmallIcon.setImageURI("") + // mPersonalBadgeTv.setText("我的徽章"); + mStubBinding.personalUserNameSmall.text = "立即登录" + mStubBinding.personalUserName.visibility = View.GONE + mStubBinding.personalHome.visibility = View.GONE + mStubBinding.personalBadge.visibility = View.GONE + mStubBinding.personalLogin.visibility = View.VISIBLE + if (mStubBinding.loginMessageHint.visibility == View.VISIBLE) { + mStubBinding.loginMessageHint.visibility = View.GONE + EventBus.getDefault().post(EBReuse(MESSAGE_READ_OVER)) + } + } + } + + private fun inflateRealView() { + mBinding.stub.viewStub?.inflate() + + mStubBinding.collapsingToolbar.setOnClickListener(this) + mStubBinding.toolbar.setOnClickListener(this) + mStubBinding.personalInfo.setOnClickListener(this) + mStubBinding.personalLogin.setOnClickListener(this) + mStubBinding.personalMsg.setOnClickListener(this) + mStubBinding.personalHome.setOnClickListener(this) + mStubBinding.ivArrow.setOnClickListener(this) + mStubBinding.personalLogin.setOnClickListener(this) + mStubBinding.personalUserName.setOnClickListener(this) + mStubBinding.personalUserNameSmall.setOnClickListener(this) + mStubBinding.personalUserIcon.setOnClickListener(this) + mStubBinding.personalUserSmallIcon.setOnClickListener(this) + mStubBinding.personalBadge.setOnClickListener(this) + + mPersonalFuncGroupAdapter = PersonalFunctionGroupAdapter(requireContext()) + mStubBinding.personalFunc.layoutManager = LinearLayoutManager(requireContext()) + mStubBinding.personalFunc.adapter = mPersonalFuncGroupAdapter + mStubBinding.personalFunc.addItemDecoration( + VerticalItemDecoration( + requireContext(), + 8F, + false + ) + ) + + val statusBarHeight = + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) 0 else DisplayUtils.getStatusBarHeight( + resources + ) + val params: ViewGroup.LayoutParams = mStubBinding.toolbar.layoutParams + params.height = DisplayUtils.dip2px(50F) + statusBarHeight + mStubBinding.toolbar.layoutParams = params + + mStubBinding.appbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _: AppBarLayout?, verticalOffset: Int -> + val absOffset = abs(verticalOffset) + val invisibleOffset = + DisplayUtils.dip2px(56F + 48F - 50F) - DisplayUtils.getStatusBarHeight(resources) + if (absOffset <= invisibleOffset) { + mStubBinding.personalUserSmallIcon.visibility = View.GONE + mStubBinding.personalUserNameSmall.visibility = View.GONE + mStubBinding.toolbar.background = null + } else { + mStubBinding.personalUserSmallIcon.visibility = View.VISIBLE + mStubBinding.personalUserNameSmall.visibility = View.VISIBLE + mStubBinding.toolbar.setBackgroundResource(R.drawable.personal_top_bg) + } + mStubBinding.listRefresh.isEnabled = absOffset <= 2 + }) + mStubBinding.listRefresh.setColorSchemeColors( + ContextCompat.getColor( + requireContext(), + R.color.theme + ) + ) + mStubBinding.listRefresh.setProgressViewOffset( + false, + 0, + DisplayUtils.dip2px(80F) + DisplayUtils.getStatusBarHeight(requireContext().resources) + ) + mStubBinding.listRefresh.setOnRefreshListener { + mPersonalViewModel.getHaloAddons() + if (CheckLoginUtils.isLogin()) { + mUnreadViewModel.retry() + loadMessageUnreadTotal(false) + mUserHomeViewModel.getBadgeList() + mUserHomeViewModel.availableBadges() + } + mBaseHandler.postDelayed({ mStubBinding.listRefresh.isRefreshing = false }, 2000) + onEvent("我的光环_新", "下拉刷新", "下拉刷新") + } + loadMessageUnreadTotal(true) + } + + private fun observeNoneUIRelatedChanges() { + mPersonalViewModel.getHaloAddons() + mUserViewModel.loginObsUserinfo.observe(this, + { userInfoEntity: ApiResponse? -> + val notifyUserInfo: UserInfoEntity? = userInfoEntity?.data + if (notifyUserInfo != null && mUserInfoEntity == null) { // 单个用户,首次触发 + EventBus.getDefault().post(EBConcernChanged()) + val loginTokenEntity = + UserManager.getInstance().loginTokenEntity + if (mIsLogging && loginTokenEntity != null) { + val loginType = loginTokenEntity.loginType + LogUtils.login( + "success", + loginType, + mPersonalViewModel.getLoginEntranceByType(loginType) + ) + mIsLogging = false + } + } + mUserInfoEntity = notifyUserInfo + if (notifyUserInfo == null) { + mUnreadViewModel.clean() + EventBus.getDefault().post(EBConcernChanged()) + } + }) + mPersonalViewModel.haloAddData.observe( + this, + { datas: ArrayList -> + if (datas.isNotEmpty()) { + loadMessageUnreadTotal(false) + } + }) + mUnreadViewModel.liveData.observe(this, { messageUnread: MessageUnreadEntity? -> + if (messageUnread != null && messageUnread.total > 0) { + // 第一次开启应用时检查消息中心看有没有未读消息确定需不需要弹 Notifier 通知 + showNotifier(messageUnread) + } + }) + } + + private fun showNotifier(messageUnread: MessageUnreadEntity) { + if (mUnreadViewModel.isFirstTimeInit) { + mUnreadViewModel.flagFirstTimeInit(false) + if (messageUnread.meta != null && messageUnread.meta?.user != null) { + if (messageUnread.meta != null) { + var displayText = StringUtils.shrinkStringWithDot( + messageUnread.meta?.user?.name, 8 + ) + val suffixText: String = if ("follow_question" == messageUnread.meta?.type) { + "回答了你关注的问题" + } else { + "回答了你的问题" + } + displayText += suffixText + val content = messageUnread.meta?.answerId + displayText + if (shouldShowNotifier(content)) { + create(activity) + .setText(displayText) + .setDuration(5000) + .setIcon(messageUnread.meta?.user?.icon) + .setOnClickListener { + val bundle = Bundle() + bundle.putString( + EntranceUtils.KEY_ANSWER_ID, + messageUnread.meta?.answerId + ) + bundle.putString( + EntranceUtils.KEY_ENTRANCE, + EntranceUtils.ENTRANCE_UMENG + ) + bundle.putString( + EntranceUtils.KEY_TO, + SimpleAnswerDetailActivity::class.java.name + ) + EntranceUtils.jumpActivity(activity, bundle) + onEvent("消息弹窗", suffixText, "Does not contains any parameter.") + + // 标记已读 + val jsonObject = JSONObject() + try { + jsonObject.put("type", messageUnread.meta?.type) + val body = RequestBody.create( + MediaType.parse("application/json"), + jsonObject.toString() + ) + messageUnread.meta?.messageId?.let { + mPersonalViewModel.postMessageRead( + it, + body + ) { + loadMessageUnreadData() + } + } + } catch (e: Exception) { + e.printStackTrace() + } + hide() + } + .show(true, 500L) + tagNotifierAsShowed(content) + } + } + } + } + } + + // 连接上网络事件 + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(busNetworkState: EBNetworkState) { + if (busNetworkState.isNetworkConnected + && UserManager.getInstance().isLoggedIn + && (mUserInfoEntity == null || TextUtils.isEmpty(UserManager.getInstance().token)) + ) { + mUserViewModel.retryCheckLogin() + } + if (busNetworkState.isNetworkConnected) { + mPersonalViewModel.getHaloAddons() + } + } + +// @Subscribe(threadMode = ThreadMode.MAIN) +// fun onEventMainThread(busNine: EBUISwitch) { +// if (MainWrapperFragment.EB_MAIN_SCROLL_TOP == busNine.getFrom() && MainWrapperFragment.INDEX_PERSONAL == busNine.getPosition()) { +// //mScrollView.fullScroll(ScrollView.FOCUS_UP) +// } +// } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(reuse: EBReuse) { + if (MESSAGE_READ_OVER == reuse.type) { // 消息阅读完成 + mStubBinding.loginMessageHint.visibility = View.GONE + } + } + + + companion object { + const val LOGIN_TAG = "login_tag" //登入标识 + const val LOGOUT_TAG = "logout_tag" // 登出标识 + + private const val MESSAGE_READ_OVER = "MESSAGE_READ_OVER" + private const val SP_BADGE_RECORD_SEVEN_DAY = "badgeRecordSevenDay" + private const val REQUEST_MESSAGE = 199 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/personal/PersonalViewModel.kt b/app/src/main/java/com/gh/gamecenter/personal/PersonalViewModel.kt index d2548f1bf8..5ea40bc4ce 100644 --- a/app/src/main/java/com/gh/gamecenter/personal/PersonalViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/personal/PersonalViewModel.kt @@ -2,46 +2,63 @@ package com.gh.gamecenter.personal import android.annotation.SuppressLint import android.app.Application +import android.text.TextUtils import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData import com.gh.common.constant.Constants -import com.gh.common.util.SPUtils +import com.gh.common.util.* +import com.gh.gamecenter.GameDetailActivity +import com.gh.gamecenter.MainActivity +import com.gh.gamecenter.NewsDetailActivity import com.gh.gamecenter.R -import com.gh.gamecenter.entity.FunctionalGroupEntity -import com.gh.gamecenter.entity.FunctionalLinkEntity +import com.gh.gamecenter.entity.* +import com.gh.gamecenter.eventbus.EBSkip +import com.gh.gamecenter.fragment.MainWrapperFragment +import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.retrofit.BiResponse +import com.gh.gamecenter.retrofit.Response import com.gh.gamecenter.retrofit.RetrofitManager +import com.gh.gamecenter.subject.SubjectActivity import com.halo.assistant.HaloApp +import com.lightgame.utils.Utils import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers +import okhttp3.RequestBody +import okhttp3.ResponseBody +import org.greenrobot.eventbus.EventBus +import retrofit2.HttpException +import java.text.SimpleDateFormat +import java.util.* +import kotlin.collections.ArrayList class PersonalViewModel(application: Application) : AndroidViewModel(application) { - var haloAddData = MutableLiveData>() + val haloAddData = MutableLiveData>() + val appEntity = MutableLiveData() private val commonFuncs = arrayListOf( - Triple("我的游戏", R.drawable.personal_my_game, "我的游戏"), - Triple("游戏评论", R.drawable.personal_game_comment, "游戏评论"), - Triple("我的问答", R.drawable.personal_my_questions, "我的问答"), - Triple("视频投稿", R.drawable.personal_video_submission, "视频投稿"), - Triple("我的收藏", R.drawable.personal_my_collect, "我的收藏"), - Triple("浏览记录", R.drawable.personal_browsing_history, "浏览记录"), - Triple("账号安全", R.drawable.personal_account_security, "账号安全"), - Triple("模拟器游戏", R.drawable.personal_simulator_game, "模拟器游戏"), - Triple("收货信息", R.drawable.personal_delivery_info, "收货信息") + Triple("我的游戏", R.drawable.personal_my_game, "我的游戏"), + Triple("游戏评论", R.drawable.personal_game_comment, "游戏评论"), + Triple("我的问答", R.drawable.personal_my_questions, "我的问答"), + Triple("视频投稿", R.drawable.personal_video_submission, "视频投稿"), + Triple("我的收藏", R.drawable.personal_my_collect, "我的收藏"), + Triple("浏览记录", R.drawable.personal_browsing_history, "浏览记录"), + Triple("账号安全", R.drawable.personal_account_security, "账号安全"), + Triple("模拟器游戏", R.drawable.personal_simulator_game, "模拟器游戏"), + Triple("收货信息", R.drawable.personal_delivery_info, "收货信息") ) private val contentCenterFuncs = arrayListOf( - Triple("游戏动态", R.drawable.personal_game_dynamic, "游戏动态"), - Triple("资讯中心", R.drawable.personal_news_center, "资讯中心"), - Triple("礼包中心", R.drawable.personal_gif_center, "礼包中心"), - Triple("工具箱", R.drawable.personal_tools, "工具箱") + Triple("游戏动态", R.drawable.personal_game_dynamic, "游戏动态"), + Triple("资讯中心", R.drawable.personal_news_center, "资讯中心"), + Triple("礼包中心", R.drawable.personal_gif_center, "礼包中心"), + Triple("工具箱", R.drawable.personal_tools, "工具箱") ) private val otherFuncs = arrayListOf( - Triple("帮助与反馈", R.drawable.personal_feedback, "帮助与反馈"), - Triple("实名认证", R.drawable.personal_verified, "实名认证"), - Triple("微信提醒", R.drawable.personal_wechat_remind, "微信提醒"), - Triple("安装包清理", R.drawable.personal_package_chean, "安装包清理"), - Triple("分享光环", R.drawable.personal_share, "分享光环"), - Triple("设置", R.drawable.personal_setting, "设置") + Triple("帮助与反馈", R.drawable.personal_feedback, "帮助与反馈"), + Triple("实名认证", R.drawable.personal_verified, "实名认证"), + Triple("微信提醒", R.drawable.personal_wechat_remind, "微信提醒"), + Triple("安装包清理", R.drawable.personal_package_chean, "安装包清理"), + Triple("分享光环", R.drawable.personal_share, "分享光环"), + Triple("设置", R.drawable.personal_setting, "设置") ) init { @@ -51,23 +68,23 @@ class PersonalViewModel(application: Application) : AndroidViewModel(application @SuppressLint("CheckResult") fun getHaloAddons() { RetrofitManager.getInstance(getApplication()) - .api.getHaloAddons(HaloApp.getInstance().channel) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : BiResponse>() { - override fun onSuccess(data: ArrayList) { - haloAddData.postValue(data) - data.forEach loop@{ - it.addons.forEach { link -> - if (link.type == "设置") { - SPUtils.setString(Constants.SP_PRIVACY_CURRENT_MD5, link.checkSum?.privacyPolicy - ?: "") - return@loop - } + .api.getHaloAddons(HaloApp.getInstance().channel) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse>() { + override fun onSuccess(data: ArrayList) { + haloAddData.postValue(data) + data.forEach loop@{ + it.addons.forEach { link -> + if (link.type == "设置") { + SPUtils.setString(Constants.SP_PRIVACY_CURRENT_MD5, link.checkSum?.privacyPolicy + ?: "") + return@loop } } } - }) + } + }) } private fun initDefaultData() { @@ -101,4 +118,144 @@ class PersonalViewModel(application: Application) : AndroidViewModel(application datas.add(groupEntity3) haloAddData.postValue(datas) } + + fun checkUpdate() { + RetrofitManager.getInstance(getApplication()) + .api + .getUpdate( + PackageUtils.getGhVersionName(), + PackageUtils.getGhVersionCode(), + HaloApp.getInstance().channel + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: AppEntity?) { + super.onResponse(response) + if (response != null) { + appEntity.postValue(response) + } + } + }) + } + + fun postMessageRead(messageId: String, body: RequestBody, callback: () -> Unit) { + RetrofitManager.getInstance(getApplication()).api + .postMessageRead( + UserManager.getInstance().userId, + messageId, + body + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : + Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + callback.invoke() + } + }) + } + + fun sign(successCallback: (signEntity: SignEntity) -> Unit) { + val context = getApplication().applicationContext + RetrofitManager.getInstance(getApplication()).api + .postSign(UserManager.getInstance().userId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(signEntity: SignEntity?) { + if (signEntity != null) { + successCallback.invoke(signEntity) + } + } + + override fun onFailure(e: HttpException?) { + if (e == null || e.code() != 401) { + ToastUtils.toast(context.getString(R.string.loading_network_error)) + } + } + }) + } + + @SuppressLint("CheckResult") + fun applyOrReceiveBadge( + id: String, + successCallback: (data: ResponseBody) -> Unit, + failureCallback: () -> Unit + ) { + RetrofitManager.getInstance(getApplication()).api + .applyOrReceiveBadge(id) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: ResponseBody) { + successCallback.invoke(data) + } + + override fun onFailure(exception: java.lang.Exception) { + super.onFailure(exception) + failureCallback.invoke() + } + }) + } + + fun signSkip(signEntity: SignEntity) { + val context = getApplication().applicationContext + val data = signEntity.data + val entrance = "(我的光环)+(签到)" + if (data == null || TextUtils.isEmpty(data.type)) { + EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_HOME)) + return + } + when (data.type) { + "game" -> { + DataUtils.onMtaEvent(context, "我的光环_签到跳转", "游戏", signEntity.title) + GameDetailActivity.startGameDetailActivity(context, data.link, entrance) + } + "news" -> { + DataUtils.onMtaEvent(context, "我的光环_签到跳转", "文章", signEntity.title) + context.startActivity(NewsDetailActivity.getIntentById(context, data.link, entrance)) + } + "column" -> { + DataUtils.onMtaEvent(context, "我的光环_签到跳转", "专题", signEntity.title) + SubjectActivity.startSubjectActivity( + context, + data.link, + null, + false, + entrance + ) + } + else -> { + val linkEntity = LinkEntity() + linkEntity.type = data.type + linkEntity.link = data.link + linkEntity.text = data.text + linkEntity.community = data.community + linkEntity.display = data.display + DirectUtils.directToLinkPage(context, linkEntity, entrance, "") + } + } + } + + fun isCanSign(time: Long): Boolean { + val context = getApplication().applicationContext + val formatDay = SimpleDateFormat("dd", Locale.CHINA) + val lastSignTime = time * 1000 + val curTime = Utils.getTime(context) * 1000 + val lastSignDay = formatDay.format(lastSignTime).toInt() + val curDay = formatDay.format(curTime).toInt() + return lastSignDay != curDay || curTime - lastSignTime > 24 * 60 * 60 * 1000 + } + + fun getLoginEntranceByType(loginTag: String): String { + var entrance = "" + when (loginTag) { + "qq" -> entrance = "我的光环-QQ" + "wechat" -> entrance = "我的光环-微信" + "weibo" -> entrance = "我的光环-新浪微博" + } + return entrance + } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/FollowersOrFansViewModel.kt b/app/src/main/java/com/gh/gamecenter/personalhome/FollowersOrFansViewModel.kt index 1703d19b39..4d67affb4c 100644 --- a/app/src/main/java/com/gh/gamecenter/personalhome/FollowersOrFansViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/personalhome/FollowersOrFansViewModel.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModelProvider import com.gh.gamecenter.R import com.gh.gamecenter.baselist.ListViewModel import com.gh.gamecenter.entity.FollowersOrFansEntity +import com.gh.gamecenter.eventbus.EBUserFollow import com.gh.gamecenter.personalhome.fans.FansActivity import com.gh.gamecenter.retrofit.Response import com.gh.gamecenter.retrofit.RetrofitManager @@ -16,6 +17,7 @@ import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody +import org.greenrobot.eventbus.EventBus import retrofit2.HttpException class FollowersOrFansViewModel(application: Application, @@ -58,6 +60,7 @@ class FollowersOrFansViewModel(application: Application, } followingLiveData.postValue(position) + EventBus.getDefault().post(EBUserFollow(userId, isFollow)) } override fun onFailure(e: HttpException?) { diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt index 226662fccb..96a1b1f518 100644 --- a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt @@ -41,6 +41,7 @@ import com.halo.assistant.HaloApp import com.lightgame.utils.Utils import kotlinx.android.synthetic.main.fragment_home.* import kotlinx.android.synthetic.main.reuse_no_connection.* +import java.util.* import kotlin.math.abs class UserHomeFragment : NormalFragment() { @@ -61,7 +62,12 @@ class UserHomeFragment : NormalFragment() { override fun getLayoutId() = 0 override fun getInflatedLayout(): View { - mHomeBinding = DataBindingUtil.inflate(requireActivity().layoutInflater, R.layout.fragment_home, null, false) + mHomeBinding = DataBindingUtil.inflate( + requireActivity().layoutInflater, + R.layout.fragment_home, + null, + false + ) return mHomeBinding!!.root } @@ -71,7 +77,8 @@ class UserHomeFragment : NormalFragment() { mPath = arguments?.getString(EntranceUtils.KEY_PATH) ?: "" val userId = arguments?.getString(EntranceUtils.KEY_USER_ID) ?: "" - mUserHomeViewModel = viewModelProvider(UserHomeViewModel.Factory(HaloApp.getInstance().application, userId)) + mUserHomeViewModel = + viewModelProvider(UserHomeViewModel.Factory(HaloApp.getInstance().application, userId)) mUserViewModel = viewModelProvider(UserViewModel.Factory(HaloApp.getInstance().application)) mMessageUnreadViewModel = viewModelProvider() @@ -128,9 +135,17 @@ class UserHomeFragment : NormalFragment() { if (badge.wear) { ImageUtils.display(mHomeBinding?.badgeIcon, badge.icon) mHomeBinding?.badgeIcon?.setOnClickListener { - DialogUtils.showViewBadgeDialog(requireContext(), Badge(badge.name, badge.icon, badge.actions)) { + DialogUtils.showViewBadgeDialog( + requireContext(), + Badge(badge.name, badge.icon, badge.actions) + ) { if (::mPersonalEntity.isInitialized) { - directToBadgeWall(requireContext(), mPersonalEntity.id, mPersonalEntity.name, mPersonalEntity.icon) + directToBadgeWall( + requireContext(), + mPersonalEntity.id, + mPersonalEntity.name, + mPersonalEntity.icon + ) } } } @@ -234,12 +249,18 @@ class UserHomeFragment : NormalFragment() { set.run { clone(contentContainer) clear(R.id.user_icon, ConstraintSet.BOTTOM) - connect(R.id.user_icon, ConstraintSet.TOP, R.id.statusBarView, ConstraintSet.BOTTOM, 50F.dip2px()) + connect( + R.id.user_icon, + ConstraintSet.TOP, + R.id.statusBarView, + ConstraintSet.BOTTOM, + 50F.dip2px() + ) applyTo(contentContainer) } userCountContainer.post { - val newHeight = userCountContainer.bottom + (32F + 16F).dip2px() + val newHeight = userCountContainer.bottom + (12F + 16F).dip2px() userBackgroundContainer.layoutParams = userBackgroundContainer.layoutParams.apply { height = newHeight } @@ -248,8 +269,15 @@ class UserHomeFragment : NormalFragment() { newSet.run { clone(contentContainer) clear(R.id.user_icon, ConstraintSet.TOP) - val marginBottom = newHeight - DisplayUtils.getStatusBarHeight(resources) - 50F.dip2px() - 96F.dip2px() - connect(R.id.user_icon, ConstraintSet.BOTTOM, R.id.user_background_container, ConstraintSet.BOTTOM, marginBottom) + val marginBottom = + newHeight - DisplayUtils.getStatusBarHeight(resources) - 50F.dip2px() - 96F.dip2px() + connect( + R.id.user_icon, + ConstraintSet.BOTTOM, + R.id.user_background_container, + ConstraintSet.BOTTOM, + marginBottom + ) applyTo(contentContainer) } } @@ -262,11 +290,20 @@ class UserHomeFragment : NormalFragment() { mHomeBinding?.run { appbar.addOnOffsetChangedListener(OnOffsetChangedListener { _: AppBarLayout?, verticalOffset: Int -> if (isAdded) { - val statusBarHeight = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) 0 else DisplayUtils.getStatusBarHeight(resources) + val statusBarHeight = + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) 0 else DisplayUtils.getStatusBarHeight( + resources + ) val absOffset = abs(verticalOffset) - val invisibleOffset = 264f.dip2px() - 50f.dip2px() - 2f.dip2px() - statusBarHeight + val invisibleOffset = + 264f.dip2px() - 50f.dip2px() - 2f.dip2px() - statusBarHeight if (absOffset < invisibleOffset) { - toolbar.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.transparent)) + toolbar.setBackgroundColor( + ContextCompat.getColor( + requireContext(), + R.color.transparent + ) + ) toolbarContainer.background = null userSmallContainer.visibility = View.GONE } else { @@ -274,7 +311,12 @@ class UserHomeFragment : NormalFragment() { toolbar.setBackgroundColor(R.color.white.toColor()) toolbarContainer.background = BitmapDrawable(resources, mBitmap) } else { - toolbar.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.theme)) + toolbar.setBackgroundColor( + ContextCompat.getColor( + requireContext(), + R.color.theme + ) + ) } userSmallContainer.visibility = View.VISIBLE } @@ -301,9 +343,14 @@ class UserHomeFragment : NormalFragment() { val tag = "android:switcher:${mHomeBinding?.viewpager?.id}:" val gameFragment = childFragmentManager.findFragmentByTag("${tag}0") - ?: UserGameFragment.getInstance(mUserHomeViewModel.userId, count.gameComment) + ?: UserGameFragment.getInstance(mUserHomeViewModel.userId, count.gameComment) val qaFragment = childFragmentManager.findFragmentByTag("${tag}1") - ?: UserHistoryFragment.getInstance(mUserHomeViewModel.userId, UserHistoryViewModel.SCENE.QUESTION_ANSWER, count, type) + ?: UserHistoryFragment.getInstance( + mUserHomeViewModel.userId, + UserHistoryViewModel.SCENE.QUESTION_ANSWER, + count, + type + ) // val videoFragment = childFragmentManager.findFragmentByTag("${tag}2") // ?: UserVideoHistoryFragment.getInstance(mUserHomeViewModel.userId, count) @@ -330,7 +377,8 @@ class UserHomeFragment : NormalFragment() { } private fun getTabView(title: String): View { - val view = LayoutInflater.from(HaloApp.getInstance().application.baseContext).inflate(R.layout.tab_item_user_home, null) + val view = LayoutInflater.from(HaloApp.getInstance().application.baseContext) + .inflate(R.layout.tab_item_user_home, null) val tabTitle = view.findViewById(R.id.tab_title) if (tabTitle is CheckedTextView) { tabTitle.text = title @@ -339,8 +387,16 @@ class UserHomeFragment : NormalFragment() { } private fun trackMtaEvent(name: String? = "") { - MtaHelper.onEvent("个人主页", mPath, StringUtils.combineTwoString(name, mUserHomeViewModel.userId)) - MtaHelper.onEvent("个人主页", "不区分位置", StringUtils.combineTwoString(name, mUserHomeViewModel.userId)) + MtaHelper.onEvent( + "个人主页", + mPath, + StringUtils.combineTwoString(name, mUserHomeViewModel.userId) + ) + MtaHelper.onEvent( + "个人主页", + "不区分位置", + StringUtils.combineTwoString(name, mUserHomeViewModel.userId) + ) } private fun updateUnreadInfo(messageEntity: MessageUnreadEntity) { @@ -369,23 +425,34 @@ class UserHomeFragment : NormalFragment() { // 截取背景图片,供toolbar使用 if (!personalData.background?.url.isNullOrEmpty()) { - ImageUtils.getBitmap(personalData.background?.url ?: "", object : BiCallback { - override fun onFirst(first: Bitmap) { - userBackground.postDelayed({ - if (activity?.isFinishing == false && !isStateSaved) { - val statusBarHeight = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) 0 else DisplayUtils.getStatusBarHeight(resources) - val bitmap = getBitmapFromView(userBackground) - bitmap?.let { - mBitmap = Bitmap.createBitmap(it, 0, it.height - statusBarHeight - 50f.dip2px(), it.width, statusBarHeight + 50f.dip2px()) + ImageUtils.getBitmap( + personalData.background?.url ?: "", + object : BiCallback { + override fun onFirst(first: Bitmap) { + userBackground.postDelayed({ + if (activity?.isFinishing == false && !isStateSaved) { + val statusBarHeight = + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) 0 else DisplayUtils.getStatusBarHeight( + resources + ) + val bitmap = getBitmapFromView(userBackground) + bitmap?.let { + mBitmap = Bitmap.createBitmap( + it, + 0, + it.height - statusBarHeight - 50f.dip2px(), + it.width, + statusBarHeight + 50f.dip2px() + ) + } } - } - }, 1000) - } + }, 1000) + } - override fun onSecond(second: Boolean) { - Utils.log("获取背景图片失败") - } - }) + override fun onSecond(second: Boolean) { + Utils.log("获取背景图片失败") + } + }) } // 设置有边框挂件的头像 @@ -411,7 +478,11 @@ class UserHomeFragment : NormalFragment() { userChangeBgBtn.visibility = View.VISIBLE recentVisitContainer.visibility = View.VISIBLE recentVisitIcon.setOnClickListener { - DirectUtils.directToHomeActivity(requireContext(), personalData.lastVisitor?.id, "个人主页-最近来访") + DirectUtils.directToHomeActivity( + requireContext(), + personalData.lastVisitor?.id, + "个人主页-最近来访" + ) } // 默认显示悬浮窗,点击图标进入更换背景页,悬浮窗消失 @@ -439,7 +510,12 @@ class UserHomeFragment : NormalFragment() { // 个性签名 userIntroduce.setOnClickListener { IntegralLogHelper.log("click_what's_up", LOCATION) - startActivity(UserInfoEditActivity.getIntent(context, UserViewModel.TYPE_INTRODUCE)) + startActivity( + UserInfoEditActivity.getIntent( + context, + UserViewModel.TYPE_INTRODUCE + ) + ) } } @@ -447,14 +523,24 @@ class UserHomeFragment : NormalFragment() { personalData.background?.url?.let { userBackground.setOnClickListener { - startActivity(ImageViewerActivity.getIntent(requireContext(), arrayListOf(personalData.background!!.url), 0, userIcon, "$mEntrance+($mPath)", true)) + startActivity( + ImageViewerActivity.getIntent( + requireContext(), + arrayListOf(personalData.background!!.url), + 0, + userIcon, + "$mEntrance+($mPath)", + true + ) + ) } } // 礼仪测试标签 regulationTestContainer.setOnClickListener { if (::mPersonalEntity.isInitialized - && mUserHomeViewModel.userId == UserManager.getInstance().userId) { + && mUserHomeViewModel.userId == UserManager.getInstance().userId + ) { IntegralLogHelper.log("click_test_label", LOCATION) DialogUtils.showPassRegulationDialog(requireContext(), mPersonalEntity.icon) } @@ -464,7 +550,12 @@ class UserHomeFragment : NormalFragment() { badgeContainer.setOnClickListener { if (::mPersonalEntity.isInitialized) { IntegralLogHelper.log("click_badge_label", LOCATION) - directToBadgeWall(requireContext(), mPersonalEntity.id, mPersonalEntity.name, mPersonalEntity.icon) + directToBadgeWall( + requireContext(), + mPersonalEntity.id, + mPersonalEntity.name, + mPersonalEntity.icon + ) } } @@ -477,24 +568,50 @@ class UserHomeFragment : NormalFragment() { MtaHelper.onEvent("个人主页详情", "个人主页详情", "头像") startActivity(AvatarBorderActivity.getIntent(requireContext())) } else { - startActivity(ImageViewerActivity.getIntent(requireContext(), arrayListOf(personalData.icon), 0, userIcon, "$mEntrance+($mPath)", true)) + startActivity( + ImageViewerActivity.getIntent( + requireContext(), + arrayListOf(personalData.icon), + 0, + userIcon, + "$mEntrance+($mPath)", + true + ) + ) } } userFollowerContainer.setOnClickListener { IntegralLogHelper.log("click_follow", LOCATION) MtaHelper.onEvent("个人主页详情", "个人主页详情", "关注数") - startActivity(FollowersActivity.getIntent(requireContext(), mUserHomeViewModel.userId, mEntrance, mPath)) + startActivity( + FollowersActivity.getIntent( + requireContext(), + mUserHomeViewModel.userId, + mEntrance, + mPath + ) + ) } userFansContainer.setOnClickListener { IntegralLogHelper.log("click_follower", LOCATION) MtaHelper.onEvent("个人主页详情", "个人主页详情", "粉丝数") - requireContext().startActivity(FansActivity.getIntent(requireContext(), mUserHomeViewModel.userId, mEntrance, mPath)) + requireContext().startActivity( + FansActivity.getIntent( + requireContext(), + mUserHomeViewModel.userId, + mEntrance, + mPath + ) + ) } userVoteContainer.setOnClickListener { IntegralLogHelper.log("click_like", LOCATION) MtaHelper.onEvent("个人主页详情", "个人主页详情", "赞同数") - Utils.toast(requireContext(), "共获得 " + NumberUtils.transSimpleCount(entity?.count?.vote!!) + " 赞同") + Utils.toast( + requireContext(), + "共获得 " + NumberUtils.transSimpleCount(entity?.count?.vote!!) + " 赞同" + ) } userEditBtn.setOnClickListener { IntegralLogHelper.log("click_edit", LOCATION) @@ -511,10 +628,17 @@ class UserHomeFragment : NormalFragment() { userConcernedBtn.setOnClickListener { ifLogin("个人主页-关注-[关注]") { MtaHelper.onEvent("个人主页详情", "个人主页详情", "关注按钮") - DialogUtils.showAlertDialog(requireContext(), "取消关注", "确定要取消关注 ${personalData.name} 吗?", - "确定取消", "暂不取消", DialogUtils.ConfirmListener { - mUserHomeViewModel.unFollow() - }, null) + DialogUtils.showAlertDialog( + requireContext(), + "取消关注", + "确定要取消关注 ${personalData.name} 吗?", + "确定取消", + "暂不取消", + DialogUtils.ConfirmListener { + mUserHomeViewModel.unFollow() + }, + null + ) } } @@ -566,23 +690,30 @@ class UserHomeFragment : NormalFragment() { if (!::mPopupWindow.isInitialized) { val contentView = View.inflate(activity, R.layout.popup_user_home_more, null) mPopupWindow = PopupWindow( - contentView, - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT + contentView, + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT ) contentView.run { findViewById(R.id.shareBtn) - .setOnClickListener { - IntegralLogHelper.log("click_share", "更多面板") - mPopupWindow.dismiss() - shareUserHome() - } + .setOnClickListener { + IntegralLogHelper.log("click_share", "更多面板") + mPopupWindow.dismiss() + shareUserHome() + } findViewById(R.id.reportBtn).setOnClickListener { IntegralLogHelper.log("click_report", "更多面板") mPopupWindow.dismiss() - DialogUtils.showReportReasonDialog(requireContext()) { reason, desc -> + val items = arrayListOf( + context.getString(R.string.report_reason_one), + context.getString(R.string.report_reason_two), + context.getString(R.string.report_reason_three), + context.getString(R.string.report_reason_four), + context.getString(R.string.report_reason_other) + ) + DialogUtils.showReportReasonDialog(requireContext(), items) { reason, desc -> mUserHomeViewModel.postReport(reason, desc) } } @@ -603,18 +734,20 @@ class UserHomeFragment : NormalFragment() { (if (mBadgeCount == 0) "" else "给力~ 已领取 $mBadgeCount 枚徽章\n") + "要好玩,上光环" if (::mPersonalEntity.isInitialized) { - ShareUtils.getInstance(requireContext()).showShareUserHomeWindows(requireActivity(), - mHomeBinding?.root, - if ("internal" == BuildConfig.FLAVOR) { - Constants.SHARE_USER_HOME_ADDRESS_DEV - } else { - Constants.SHARE_USER_HOME_ADDRESS - } + "?user=${mPersonalEntity.id}", - mPersonalEntity.icon, - "【推荐】来自光环助手的${mPersonalEntity.name}", - content, - ShareUtils.ShareEntrance.userHome, - mPersonalEntity.id, null) + ShareUtils.getInstance(requireContext()).showShareUserHomeWindows( + requireActivity(), + mHomeBinding?.root, + if ("internal" == BuildConfig.FLAVOR) { + Constants.SHARE_USER_HOME_ADDRESS_DEV + } else { + Constants.SHARE_USER_HOME_ADDRESS + } + "?user=${mPersonalEntity.id}", + mPersonalEntity.icon, + "【推荐】来自光环助手的${mPersonalEntity.name}", + content, + ShareUtils.ShareEntrance.userHome, + mPersonalEntity.id, null + ) } } diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeViewModel.kt b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeViewModel.kt index 1e070fa220..74bb332798 100644 --- a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeViewModel.kt @@ -8,6 +8,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import com.gh.common.util.EnergyTaskHelper +import com.gh.common.util.ErrorHelper import com.gh.common.util.ToastUtils import com.gh.common.util.createRequestBody import com.gh.gamecenter.R @@ -34,7 +35,7 @@ class UserHomeViewModel(application: Application, var userId: String) : AndroidV var availableBadge = MutableLiveData() var availableBadgeCount = MutableLiveData() var playGamesCount = MutableLiveData() - var energy = MutableLiveData() + var energy = MutableLiveData() var level = MutableLiveData() var sign = MutableLiveData() var signStatus = MutableLiveData() @@ -145,7 +146,7 @@ class UserHomeViewModel(application: Application, var userId: String) : AndroidV .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : BiResponse() { override fun onSuccess(data: JsonObject) { - energy.postValue(data["energy"].asInt) + energy.postValue(data["energy"].asLong) } }) } @@ -167,7 +168,7 @@ class UserHomeViewModel(application: Application, var userId: String) : AndroidV fun postReport(reason: String, desc: String) { val requestMap = hashMapOf() requestMap["reason"] = reason - if (reason == "其它") { + if (reason == "其他原因") { requestMap["description"] = desc } RetrofitManager.getInstance(getApplication()) @@ -182,20 +183,7 @@ class UserHomeViewModel(application: Application, var userId: String) : AndroidV override fun onFailure(exception: Exception) { super.onFailure(exception) if (exception is HttpException) { - try { - val responseBody = exception.response().errorBody() - val string = responseBody!!.string() - val content = JSONObject(string) - when (val code = content.getInt("code")) { - 403102 -> ToastUtils.showToast("你已经举报过该用户了哦") - - 400001 -> ToastUtils.showToast("字数超过500或者未填写原因") - - else -> ToastUtils.showToast(code.toString()) - } - } catch (e1: Exception) { - e1.printStackTrace() - } + ErrorHelper.handleError(HaloApp.getInstance().application, exception.response().errorBody()?.string()) } } }) diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewFragment.kt index eebe5cd7a2..250b4c16f0 100644 --- a/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewFragment.kt @@ -19,6 +19,7 @@ import com.gh.gamecenter.CropImageActivity import com.gh.gamecenter.R import com.gh.gamecenter.databinding.FragmentBackgroundPreviewBinding import com.gh.gamecenter.entity.BackgroundImageEntity +import com.gh.gamecenter.entity.ErrorEntity import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.normal.NormalFragment import com.gh.gamecenter.user.UserViewModel @@ -29,6 +30,7 @@ import com.zhihu.matisse.engine.impl.PicassoEngine import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers +import retrofit2.HttpException import java.io.File class BackgroundPreviewFragment : NormalFragment() { @@ -45,14 +47,20 @@ class BackgroundPreviewFragment : NormalFragment() { override fun getLayoutId(): Int = 0 override fun getInflatedLayout(): View { - mBinding = DataBindingUtil.inflate(layoutInflater, R.layout.fragment_background_preview, null, false) + mBinding = DataBindingUtil.inflate( + layoutInflater, + R.layout.fragment_background_preview, + null, + false + ) return mBinding.root } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mLocalPath = arguments?.getString(EntranceUtils.KEY_LOCAL_PATH) ?: "" - backgroundImageEntity = arguments?.getParcelable(BackgroundImageEntity::class.java.simpleName) + backgroundImageEntity = + arguments?.getParcelable(BackgroundImageEntity::class.java.simpleName) mUserViewModel = viewModelProvider(UserViewModel.Factory(HaloApp.getInstance().application)) mUserViewModel.uploadBackground.observeNonNull(this) { @@ -73,7 +81,8 @@ class BackgroundPreviewFragment : NormalFragment() { } private fun changeViewParams() { - val screenHeight = DisplayUtils.px2dip(requireContext(), DisplayUtils.getScreenHeight().toFloat()) + val screenHeight = + DisplayUtils.px2dip(requireContext(), DisplayUtils.getScreenHeight().toFloat()) val picProportion = if (screenHeight > 640) 6 / 13f else 9 / 16f val width = mBinding.previewMineIv.width val height = mBinding.previewMineIv.height @@ -84,13 +93,16 @@ class BackgroundPreviewFragment : NormalFragment() { mineGhIvParams.topMargin = ((height - realHeight) / 2).toInt() + 1f.dip2px() mBinding.mineGhIv.layoutParams = mineGhIvParams - val personalHomeIvParams = mBinding.personalHomeIv.layoutParams as ConstraintLayout.LayoutParams + val personalHomeIvParams = + mBinding.personalHomeIv.layoutParams as ConstraintLayout.LayoutParams //最后+1dp是因为预览图有1dp的边框 personalHomeIvParams.topMargin = ((height - realHeight) / 2).toInt() + 1f.dip2px() mBinding.personalHomeIv.layoutParams = personalHomeIvParams - val changeBackgroundTvParams = mBinding.changeBackgroundTv.layoutParams as ConstraintLayout.LayoutParams - changeBackgroundTvParams.topMargin = (realHeight + (height - realHeight) / 2 + 26f.dip2px()).toInt() + val changeBackgroundTvParams = + mBinding.changeBackgroundTv.layoutParams as ConstraintLayout.LayoutParams + changeBackgroundTvParams.topMargin = + (realHeight + (height - realHeight) / 2 + 26f.dip2px()).toInt() mBinding.changeBackgroundTv.layoutParams = changeBackgroundTvParams mBinding.mineContainer.visibility = View.VISIBLE @@ -101,20 +113,42 @@ class BackgroundPreviewFragment : NormalFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) mLocalPath = arguments?.getString(EntranceUtils.KEY_LOCAL_PATH) ?: "" - backgroundImageEntity = arguments?.getParcelable(BackgroundImageEntity::class.java.simpleName) + backgroundImageEntity = + arguments?.getParcelable(BackgroundImageEntity::class.java.simpleName) mOriginBitmap = BitmapUtils.getBitmapByFile(mLocalPath, Bitmap.Config.ARGB_8888) if (mOriginBitmap == null) return mTempBitmap = Bitmap.createBitmap(mOriginBitmap!!) mBinding.mineGhIv.setImageBitmap(mOriginBitmap) mBinding.personalHomeIv.setImageBitmap(mOriginBitmap) - val screenHeight = DisplayUtils.px2dip(requireContext(), DisplayUtils.getScreenHeight().toFloat()) + val screenHeight = + DisplayUtils.px2dip(requireContext(), DisplayUtils.getScreenHeight().toFloat()) if (screenHeight > 640) { - mBinding.previewMineIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.preview_mine_full)) - mBinding.previewHomeIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.preview_home_full)) + mBinding.previewMineIv.setImageDrawable( + ContextCompat.getDrawable( + requireContext(), + R.drawable.preview_mine_full + ) + ) + mBinding.previewHomeIv.setImageDrawable( + ContextCompat.getDrawable( + requireContext(), + R.drawable.preview_home_full + ) + ) } else { - mBinding.previewMineIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.preview_mine)) - mBinding.previewHomeIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.preview_home)) + mBinding.previewMineIv.setImageDrawable( + ContextCompat.getDrawable( + requireContext(), + R.drawable.preview_mine + ) + ) + mBinding.previewHomeIv.setImageDrawable( + ContextCompat.getDrawable( + requireContext(), + R.drawable.preview_home + ) + ) } mBinding.normalTitle.text = "预览" @@ -159,14 +193,19 @@ class BackgroundPreviewFragment : NormalFragment() { } mBinding.commitTv.setOnClickListener { - PermissionHelper.checkStoragePermissionBeforeAction(requireContext(), object : EmptyCallback { - override fun onCallback() { - mTempBitmap?.let { - val filePath: String = "${requireContext().cacheDir.absolutePath}${File.separator}${MD5Utils.getContentMD5(mLocalPath)}.webp" - savePicture(filePath, it) + PermissionHelper.checkStoragePermissionBeforeAction( + requireContext(), + object : EmptyCallback { + override fun onCallback() { + mTempBitmap?.let { + val filePath: String = + "${requireContext().cacheDir.absolutePath}${File.separator}${ + MD5Utils.getContentMD5(mLocalPath) + }.webp" + savePicture(filePath, it) + } } - } - }) + }) } } @@ -201,51 +240,73 @@ class BackgroundPreviewFragment : NormalFragment() { mPostDialog = WaitingDialogFragment.newInstance("加载中...") mPostDialog?.show(childFragmentManager, null) Single.just(bitmap) - .map { - if (mBinding.alphaSeek.progress == 100) { - it - } else { - BitmapUtils.getTransparentBitmap(bitmap, Bitmap.Config.ARGB_8888, mBinding.alphaSeek.progress) - } + .map { + if (mBinding.alphaSeek.progress == 100) { + it + } else { + BitmapUtils.getTransparentBitmap( + bitmap, + Bitmap.Config.ARGB_8888, + mBinding.alphaSeek.progress + ) } - .map { - BitmapUtils.saveBitmap(it, path) - path - } - .flatMap { - uploadImage(it) - } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ - mPostDialog?.dismiss() - val entity = BackgroundImageEntity(backgroundImageEntity?.id - ?: "", it, opacity = mBinding.alphaSeek.progress, blur = mBinding.blurSeek.progress) - mUserViewModel.changeUserInfo(GsonUtils.toJson(entity), UserViewModel.TYPE_BACKGROUND) - }, { - it.printStackTrace() - mPostDialog?.dismiss() - }) + } + .map { + BitmapUtils.saveBitmap(it, path) + path + } + .flatMap { + uploadImage(it) + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + mPostDialog?.dismiss() + val entity = BackgroundImageEntity( + backgroundImageEntity?.id + ?: "", + it, + opacity = mBinding.alphaSeek.progress, + blur = mBinding.blurSeek.progress + ) + mUserViewModel.changeUserInfo( + GsonUtils.toJson(entity), + UserViewModel.TYPE_BACKGROUND + ) + }, { + it.printStackTrace() + mPostDialog?.dismiss() + }) } private fun uploadImage(path: String): Single { return Single.create { - UploadImageUtils.uploadImage(UploadImageUtils.UploadType.user_background, path, object : UploadImageUtils.OnUploadImageListener { - override fun onSuccess(imageUrl: String) { - it.onSuccess(imageUrl) - } + UploadImageUtils.uploadImage( + UploadImageUtils.UploadType.user_background, + path, + object : UploadImageUtils.OnUploadImageListener { + override fun onSuccess(imageUrl: String) { + it.onSuccess(imageUrl) + } - override fun onError(e: Throwable?) { - it.onError(e ?: Throwable()) - } + override fun onError(e: Throwable?) { + if (e is HttpException) { + val entity = + e.response()?.errorBody()?.string()?.toObject() + if (entity?.code == 403033) { + toast("图片违规") + } + } + it.onError(e ?: Throwable()) + } - override fun onProgress(total: Long, progress: Long) { + override fun onProgress(total: Long, progress: Long) { - } + } - }) + }) } } @@ -254,15 +315,15 @@ class BackgroundPreviewFragment : NormalFragment() { PermissionHelper.checkStoragePermissionBeforeAction(activity, object : EmptyCallback { override fun onCallback() { Matisse.from(activity) - .choose(MimeType.ofImage()) - .showSingleMediaType(true) - .countable(true) - .addFilter(GhMatisseFilter()) - .maxSelectable(1) - .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) - .thumbnailScale(0.85f) - .imageEngine(PicassoEngine()) - .forResult(MEDIA_STORE_REQUEST) + .choose(MimeType.ofImage()) + .showSingleMediaType(true) + .countable(true) + .addFilter(GhMatisseFilter()) + .maxSelectable(1) + .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) + .thumbnailScale(0.85f) + .imageEngine(PicassoEngine()) + .forResult(MEDIA_STORE_REQUEST) } }) } @@ -273,7 +334,8 @@ class BackgroundPreviewFragment : NormalFragment() { if (requestCode == MEDIA_STORE_REQUEST && resultCode == Activity.RESULT_OK) { val selectedPaths = Matisse.obtainPathResult(data) if (selectedPaths.size > 0) { - val intent = BackgroundClipActivity.getIntent(requireContext(), selectedPaths[0], mEntrance) + val intent = + BackgroundClipActivity.getIntent(requireContext(), selectedPaths[0], mEntrance) startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP) } } else if (requestCode == REQUEST_CODE_IMAGE_CROP && resultCode == Activity.RESULT_OK) { @@ -282,11 +344,12 @@ class BackgroundPreviewFragment : NormalFragment() { mOriginBitmap = BitmapUtils.getBitmapByFile(imagePath, Bitmap.Config.ARGB_8888) if (mOriginBitmap == null) return val progress = mBinding.blurSeek.progress - mTempBitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && progress != 0) { - BitmapUtils.getBlurBitmap(requireContext(), mOriginBitmap, progress) - } else { - Bitmap.createBitmap(mOriginBitmap!!) - } + mTempBitmap = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && progress != 0) { + BitmapUtils.getBlurBitmap(requireContext(), mOriginBitmap, progress) + } else { + Bitmap.createBitmap(mOriginBitmap!!) + } mBinding.mineGhIv.setImageBitmap(mTempBitmap) mBinding.personalHomeIv.setImageBitmap(mTempBitmap) } diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/border/ChooseAvatarBorderAdapter.kt b/app/src/main/java/com/gh/gamecenter/personalhome/border/ChooseAvatarBorderAdapter.kt index 738041813f..f82f98c7fe 100644 --- a/app/src/main/java/com/gh/gamecenter/personalhome/border/ChooseAvatarBorderAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/personalhome/border/ChooseAvatarBorderAdapter.kt @@ -54,6 +54,7 @@ class ChooseAvatarBorderAdapter(context: Context, // 商品挂件但未兑换或者已过期,显示光能 !mIsFree && (borderEntity.expire == null || (borderEntity.expire != null + && borderEntity.expire!! != 0L && borderEntity.expire!! < TimeUtil.currentTime())) -> { isEnable = false holder.binding.descTv.run { diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryAdapter.kt b/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryAdapter.kt index 05db4b7992..4aaf858790 100644 --- a/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryAdapter.kt @@ -95,8 +95,8 @@ class UserHistoryAdapter(context: Context, } entity = historyEntity -// userName.visibility = View.GONE topLine.goneIf(position == 0) + forumNameLl.visibleIf(historyEntity.community.id.isNotEmpty()) userIcon.display(historyEntity.user?.border, historyEntity.user?.icon, historyEntity.user?.auth?.icon) executePendingBindings() @@ -265,6 +265,7 @@ class UserHistoryAdapter(context: Context, "community_article_vote" -> "赞同了帖子" "community_article" -> if (isEdit) "修改了帖子" else "发布了帖子" "update-answer" -> "更新了回答" + "video" -> "发布了视频" else -> "" } } @@ -278,6 +279,7 @@ class UserHistoryAdapter(context: Context, "community_article_vote" -> "赞同了帖子" "community_article" -> "发布了帖子" "update-answer" -> "更新了回答" + "video" -> "发布了视频" else -> "" } } diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryFragment.kt index 72852e013e..0eb76b96e9 100644 --- a/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/personalhome/home/UserHistoryFragment.kt @@ -208,7 +208,7 @@ class UserHistoryFragment : ListFragment { + val communityId = if (!entity.communityId.isNullOrEmpty()) entity.communityId + ?: "" else entity.bbs.id itemView.context.startActivity(ForumVideoDetailActivity.getIntent(itemView.context, entity.id - ?: "", true)) + ?: "", communityId, true)) } "answer" -> { val intent = CommentActivity.getAnswerCommentIntent(itemView.context, @@ -167,7 +169,7 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH itemView.context.startActivity(intent) } "video" -> { - itemView.context.startActivity(ForumVideoDetailActivity.getIntent(itemView.context, entity.id, true)) + itemView.context.startActivity(ForumVideoDetailActivity.getIntent(itemView.context, entity.id, entity.community.id, true)) } else -> { val communityId = if (entity.community.id.isNotEmpty()) entity.community.id @@ -259,11 +261,11 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH @SuppressLint("CheckResult") fun voteAnswer(entity: AnswerEntity) { + if (entity.status == "pending") { + ToastUtils.showToast("内容审核中") + return + } if (entity.type == "video") { - if (entity.status == "pending") { - ToastUtils.showToast("内容审核中") - return - } RetrofitManager.getInstance(itemView.context) .api.voteVideo(entity.id) .subscribeOn(Schedulers.io()) diff --git a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt index b90e22ba8b..20d8527c56 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt @@ -43,7 +43,7 @@ import com.gh.gamecenter.entity.* import com.gh.gamecenter.eventbus.EBReuse import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.normal.NormalFragment -import com.gh.gamecenter.personal.PersonalFragment.LOGIN_TAG +import com.gh.gamecenter.personal.PersonalFragment import com.gh.gamecenter.qa.answer.edit.AnswerEditActivity import com.gh.gamecenter.qa.comment.CommentActivity import com.gh.gamecenter.qa.dialog.MoreFunctionPanelDialog @@ -1205,7 +1205,7 @@ open class AnswerDetailFragment : NormalFragment() { @Subscribe(threadMode = ThreadMode.MAIN) fun onEventMainThread(reuse: EBReuse) { - if (reuse.type == LOGIN_TAG && !TextUtils.isEmpty(mAnswerId)) { // 登入 + if (reuse.type == PersonalFragment.LOGIN_TAG && !TextUtils.isEmpty(mAnswerId)) { // 登入 mViewModel.getAnswerDetail(mAnswerId, mEntrance) } } diff --git a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt index 5b3db39e39..eabf189ee9 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt @@ -13,6 +13,7 @@ import com.gh.common.util.* import com.gh.gamecenter.R import com.gh.gamecenter.entity.SpecialColumn import com.gh.gamecenter.entity.VoteEntity +import com.gh.gamecenter.eventbus.EBUserFollow import com.gh.gamecenter.qa.entity.AnswerDetailEntity import com.gh.gamecenter.retrofit.Response import com.gh.gamecenter.retrofit.RetrofitManager @@ -23,6 +24,7 @@ import io.reactivex.schedulers.Schedulers import okhttp3.MediaType import okhttp3.RequestBody import okhttp3.ResponseBody +import org.greenrobot.eventbus.EventBus import org.json.JSONObject import retrofit2.HttpException import java.util.* @@ -237,6 +239,7 @@ class AnswerDetailViewModel(application: Application) : AndroidViewModel(applica // 取消关注成功 mFollowLiveData.postValue(false) } + EventBus.getDefault().post(EBUserFollow(targetUserId, isFollow)) } override fun onFailure(e: HttpException?) { diff --git a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/SimpleAnswerDetailActivity.kt b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/SimpleAnswerDetailActivity.kt index 26ba780c05..5c06d50528 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/SimpleAnswerDetailActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/SimpleAnswerDetailActivity.kt @@ -9,6 +9,14 @@ import com.gh.gamecenter.NormalActivity class SimpleAnswerDetailActivity : NormalActivity() { + override fun provideNormalIntent(): Intent? { + return getTargetIntent( + this, + SimpleAnswerDetailActivity::class.java, + SimpleAnswerDetailFragment::class.java + ) + } + companion object { @JvmStatic fun getIntent(context: Context, answerId: String, entrance: String, path: String): Intent { diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailContentViewHolder.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailContentViewHolder.kt index 4f7fa9a5e2..a6cce1befe 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailContentViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailContentViewHolder.kt @@ -2,13 +2,10 @@ package com.gh.gamecenter.qa.article.detail import android.annotation.SuppressLint import android.app.Activity -import android.text.TextUtils -import android.view.LayoutInflater import android.view.View -import android.view.animation.LinearInterpolator import android.webkit.JavascriptInterface import android.webkit.WebView -import android.widget.TextView +import android.widget.LinearLayout import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import com.gh.common.DefaultUrlHandler @@ -17,18 +14,16 @@ import com.gh.common.util.* import com.gh.common.view.RichEditor import com.gh.gamecenter.ImageViewerActivity import com.gh.gamecenter.R -import com.gh.gamecenter.databinding.ArticleDetailFourmTagItemBinding import com.gh.gamecenter.databinding.ItemArticleDetailContentBinding -import com.gh.gamecenter.entity.CommunityEntity import com.gh.gamecenter.manager.UserManager -import com.gh.gamecenter.qa.column.detail.AskColumnDetailActivity import com.gh.gamecenter.qa.editor.OnLinkClickListener import com.gh.gamecenter.qa.entity.ArticleDetailEntity -import com.google.android.flexbox.FlexboxLayout import java.util.* -class ArticleDetailContentViewHolder(var binding: ItemArticleDetailContentBinding, var viewModel: ArticleDetailViewModel) - : RecyclerView.ViewHolder(binding.root) { +class ArticleDetailContentViewHolder( + var binding: ItemArticleDetailContentBinding, + var viewModel: ArticleDetailViewModel +) : RecyclerView.ViewHolder(binding.root) { private var mEntrance = "" val articleImgUrlList = ArrayList() @@ -39,7 +34,15 @@ class ArticleDetailContentViewHolder(var binding: ItemArticleDetailContentBindin richEditor.setInputEnabled(false) richEditor.setPadding(20, 20, 20, 15) richEditor.addJavascriptInterface(JsInterface(article.status), "imagelistener") - richEditor.addJavascriptInterface(OnLinkClickListener(root.context, article.title, article.status, mEntrance, "帖子详情"), "OnLinkClickListener") + richEditor.addJavascriptInterface( + OnLinkClickListener( + root.context, + article.title, + article.status, + mEntrance, + "帖子详情" + ), "OnLinkClickListener" + ) richEditor.setLayoutCallback(object : EmptyCallback { override fun onCallback() { viewModel.articleRenderedLiveData.postValue(true) @@ -71,40 +74,67 @@ class ArticleDetailContentViewHolder(var binding: ItemArticleDetailContentBindin approvalStatusTv.background = R.drawable.bg_approval_status_fail.toDrawable() } } + if (article.status != "pass") { + (statusContainer.layoutParams as LinearLayout.LayoutParams).apply { + topMargin = 7f.dip2px() + statusContainer.layoutParams = this + } + titleTv.setPadding(20f.dip2px(), 16f.dip2px(), 20f.dip2px(), 5f.dip2px()) + } val bbsType = if (article.type == "game_bbs") "游戏论坛" else "综合论坛" followBtn.setOnClickListener { MtaHelper.onEvent("帖子详情", "内容区域", "关注") - NewLogUtils.logArticleDetailClick("click_article_detail_follow", article.user.id - ?: "", "帖子", article.community.id, bbsType) + NewLogUtils.logArticleDetailClick( + "click_article_detail_follow", article.user.id + ?: "", "帖子", article.community.id, bbsType + ) root.context.ifLogin("帖子详情-[关注]用户") { if (followBtn.text == "关注") { viewModel.follow() } else { - DialogUtils.showAlertDialog(root.context, - "取消关注", - "确定要取消关注 ${article.user.name} 吗?", - "确定取消", - "暂不取消", - DialogUtils.ConfirmListener { - viewModel.unfollow() - }, null) + DialogUtils.showAlertDialog( + root.context, + "取消关注", + "确定要取消关注 ${article.user.name} 吗?", + "确定取消", + "暂不取消", + DialogUtils.ConfirmListener { + viewModel.unfollow() + }, null + ) } } } userNameTv.setOnClickListener { MtaHelper.onEvent("帖子详情", "内容区域", "用户名字") - NewLogUtils.logArticleDetailClick("click_article_detail_nickname", article.user.id - ?: "", "帖子", article.community.id, bbsType) - DirectUtils.directToHomeActivity(root.context, article.user.id, 1, mEntrance, "帖子详情") + NewLogUtils.logArticleDetailClick( + "click_article_detail_nickname", article.user.id + ?: "", "帖子", article.community.id, bbsType + ) + DirectUtils.directToHomeActivity( + root.context, + article.user.id, + 1, + mEntrance, + "帖子详情" + ) } userIconIv.setOnClickListener { MtaHelper.onEvent("帖子详情", "内容区域", "用户头像") - NewLogUtils.logArticleDetailClick("click_article_detail_profile_photo", article.user.id - ?: "", "帖子", article.community.id, bbsType) - DirectUtils.directToHomeActivity(root.context, article.user.id, 1, mEntrance, "帖子详情") + NewLogUtils.logArticleDetailClick( + "click_article_detail_profile_photo", article.user.id + ?: "", "帖子", article.community.id, bbsType + ) + DirectUtils.directToHomeActivity( + root.context, + article.user.id, + 1, + mEntrance, + "帖子详情" + ) } - titleTv.text = if (article.choicenessStatus == "pass") { + titleTv.text = if (article.getSimplifyChoicenessStatus() == "pass") { SpanBuilder(" ${article.title}").image(0, 1, R.drawable.ic_essence).build() } else { article.title @@ -118,20 +148,31 @@ class ArticleDetailContentViewHolder(var binding: ItemArticleDetailContentBindin } if (article.time.create == article.time.edit) { - releaseTimeTv.text = String.format("发布于%s", NewsUtils.getFormattedTime(article.time.create)) + releaseTimeTv.text = + String.format("发布于%s", NewsUtils.getFormattedTime(article.time.create)) } else { - releaseTimeTv.text = String.format("发布于%s 最后编辑于%s", NewsUtils.getFormattedTime(article.time.create), NewsUtils.getFormattedTime(article.time.edit)) + releaseTimeTv.text = String.format( + "发布于%s 最后编辑于%s", + NewsUtils.getFormattedTime(article.time.create), + NewsUtils.getFormattedTime(article.time.edit) + ) } richEditor.visibility = View.VISIBLE article.community.let { entity -> gameName.text = entity.name val icon = if (!entity.icon.isNullOrEmpty()) entity.icon else entity.game?.getIcon() - val iconSubscript = if (!entity.iconSubscript.isNullOrEmpty()) entity.iconSubscript else entity.game?.iconSubscript + val iconSubscript = + if (!entity.iconSubscript.isNullOrEmpty()) entity.iconSubscript else entity.game?.iconSubscript forumIconView.displayGameIcon(icon, iconSubscript) forumContainer.setOnClickListener { DirectUtils.directForumDetail(forumContainer.context, entity.id, "帖子详情") LogUtils.uploadAccessToBbs(entity.id, "文章内所属论坛") - NewLogUtils.logArticleOrQuestionDetailForumClick("帖子详情页", "click_article_detail_forum", entity.id, bbsType) + NewLogUtils.logArticleOrQuestionDetailForumClick( + "帖子详情页", + "click_article_detail_forum", + entity.id, + bbsType + ) } } @@ -150,14 +191,23 @@ class ArticleDetailContentViewHolder(var binding: ItemArticleDetailContentBindin } badgeIv.goneIf(article.user.badge == null) - badgeTv.goneIf(article.user.badge == null) +// badgeTv.goneIf(article.user.badge == null) badgeTv.text = article.user.badge?.name ImageUtils.display(badgeIv, article.user.badge?.icon) badgeIv.setOnClickListener { DialogUtils.showViewBadgeDialog(root.context, article.user.badge) { - MtaHelper.onEvent("进入徽章墙_用户记录", "帖子详情", "${article.user.name}(${article.user.id})") + MtaHelper.onEvent( + "进入徽章墙_用户记录", + "帖子详情", + "${article.user.name}(${article.user.id})" + ) MtaHelper.onEvent("徽章中心", "进入徽章中心", "帖子详情") - DirectUtils.directToBadgeWall(root.context, viewModel.detailEntity?.user?.id, article.user.name, article.user.icon) + DirectUtils.directToBadgeWall( + root.context, + viewModel.detailEntity?.user?.id, + article.user.name, + article.user.icon + ) } } badgeTv.setOnClickListener { badgeIv.performClick() } @@ -192,25 +242,25 @@ class ArticleDetailContentViewHolder(var binding: ItemArticleDetailContentBindin runOnUiThread { binding.richEditor.replaceDfImageByUrl(url) } } else -> { - if (status == "pending") { - ToastUtils.showToast("内容审核中") - return - } else if (status == "fail") { - ToastUtils.showToast("内容审核不通过") - return - } - var current = 0 - var i = 0 - val size = articleImgUrlList.size - while (i < size) { - if (url.contains(articleImgUrlList.get(i))) { - current = i + clickToastByStatus(status) { + var current = 0 + var i = 0 + val size = articleImgUrlList.size + while (i < size) { + if (url.contains(articleImgUrlList.get(i))) { + current = i + } + 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 + ) } - 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) } } } diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailFragment.kt index a62a9af45b..7fae628db8 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailFragment.kt @@ -8,8 +8,6 @@ import android.view.LayoutInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup -import android.widget.ImageView -import android.widget.LinearLayout import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat @@ -64,7 +62,11 @@ class ArticleDetailFragment : BaseCommentFragment(ArticleDetailEntity::class.java.simpleName)?.let { - mViewModel.detailEntity = it - mAdapter?.articleDetailVH?.bindView(it) - updateView() - } - data?.getParcelableExtra(ArticleDraftEntity::class.java.simpleName)?.let { - mViewModel.detailEntity?.me?.articleDraft = it - } + data?.getParcelableExtra(ArticleDetailEntity::class.java.simpleName) + ?.let { + mViewModel.detailEntity = it + mAdapter?.articleDetailVH?.bindView(it) + updateView() + } + data?.getParcelableExtra(ArticleDraftEntity::class.java.simpleName) + ?.let { + mViewModel.detailEntity?.me?.articleDraft = it + } mReuseNoConn?.performClick() //重新刷新 } else if (requestCode == ImageViewerActivity.REQUEST_FOR_VIEWED_IMAGE && resultCode == Activity.RESULT_OK) { val imageSet = data?.extras?.get(ImageViewerActivity.VIEWED_IMAGE) as HashSet @@ -123,8 +128,10 @@ class ArticleDetailFragment : BaseCommentFragment(EntranceUtils.KEY_COMMUNITY_DATA)?.id - ?: "")) + ArticleDetailViewModel.Factory( + HaloApp.getInstance().application, + arguments?.getString(EntranceUtils.KEY_COMMUNITY_ARTICLE_ID) ?: "", + arguments?.getParcelable(EntranceUtils.KEY_COMMUNITY_DATA)?.id + ?: "" + ) + ) } override fun provideListAdapter(): ListAdapter<*> { return mAdapter - ?: ArticleDetailAdapter(requireContext(), mViewModel, BaseCommentAdapter.AdapterType.COMMENT, mEntrance).apply { mAdapter = this } + ?: ArticleDetailAdapter( + requireContext(), + mViewModel, + BaseCommentAdapter.AdapterType.COMMENT, + mEntrance + ).apply { mAdapter = this } } override fun onBackPressed(): Boolean { - if (SyncDataBetweenPageHelper.setResultAndFinish(requireContext(), mViewModel.detailEntity)) { + if (SyncDataBetweenPageHelper.setResultAndFinish( + requireContext(), + mViewModel.detailEntity + ) + ) { return true } @@ -183,20 +211,20 @@ class ArticleDetailFragment : BaseCommentFragment - (mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = insets.systemWindowInsetTop + (mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = + insets.systemWindowInsetTop insets.consumeSystemWindowInsets() } - mSkeletonScreen = Skeleton.bind(skeletonView).shimmer(false).load(R.layout.fragment_article_detail_skeleton).show() + mSkeletonScreen = Skeleton.bind(skeletonView).shimmer(false) + .load(R.layout.fragment_article_detail_skeleton).show() mBinding.inputContainer.bottomLikeIv.setOnClickListener { MtaHelper.onEvent("帖子详情", "底部", "点赞") requireContext().ifLogin("帖子详情-赞同") { if (mViewModel.detailEntity?.me?.isCommunityArticleVote == false) { - if (mViewModel.detailEntity?.status == "pass") { + clickToastByStatus(mViewModel.detailEntity?.status ?: "") { mViewModel.likeArticle() - } else { - ToastUtils.showToast("内容审核中") } if (EntranceUtils.ENTRANCE_WELCOME == mEntrance) { LogUtils.uploadLikeFromWelcomeDialog() @@ -211,17 +239,19 @@ class ArticleDetailFragment : BaseCommentFragment if (isHighlighted) { if (mViewModel.detailEntity!!.me.moderatorPermissions.highlightCommunityArticle == Permissions.REPORTER) { toast("提交成功") + mViewModel.detailEntity?.choicenessStatus = "apply" } else { toast("操作成功") - requireActivity().finish() + mViewModel.detailEntity?.choicenessStatus = "pass" + mViewModel.updateDetailLiveData.postValue(mViewModel.detailEntity) } } else { toast("权限错误,请刷新后重试") @@ -356,18 +403,17 @@ class ArticleDetailFragment : BaseCommentFragment if (isHidden) { - if (mViewModel.detailEntity!!.me.moderatorPermissions.hideCommunityArticle == Permissions.REPORTER) { - toast("提交成功") + if (mViewModel.detailEntity?.me?.isModerator == true) { + toast("已隐藏") } else { - toast("操作成功") - //mViewModel.getArticleDetail() + toast("已删除") } EventBus.getDefault().post(EBDeleteDetail(mViewModel.detailEntity?.id ?: "")) requireActivity().finish() @@ -433,8 +479,17 @@ class ArticleDetailFragment : BaseCommentFragment() - if (mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId && !mViewModel.detailEntity?.me!!.isModerator && mViewModel.detailEntity?.status == "pass" && mViewModel.detailEntity?.choicenessStatus != "pass") { - entities.add(MenuItemEntity("申请加精", R.drawable.icon_more_panel_essence)) + if (mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId && !mViewModel.detailEntity?.me!!.isModerator && mViewModel.detailEntity?.status == "pass") { + val isEnable = + mViewModel.detailEntity?.getSimplifyChoicenessStatus() != "pass" + entities.add( + MenuItemEntity( + "申请加精", + if (isEnable) + R.drawable.icon_more_panel_essence else R.drawable.icon_more_panel_essence_unenable, + isEnable = isEnable + ) + ) } if (mViewModel.detailEntity?.user?.id == UserManager.getInstance().userId && mViewModel.detailEntity?.status == "pass") { entities.add(MenuItemEntity("修改", R.drawable.icon_more_panel_edit)) @@ -442,19 +497,40 @@ class ArticleDetailFragment : BaseCommentFragment { - startActivityForResult(ArticleEditActivity.getPatchIntent(requireContext(), mViewModel.detailEntity!!), ArticleDetailActivity.ARTICLE_PATCH_REQUEST) - NewLogUtils.logSharePanelClick("click_modification", mViewModel.detailEntity?.user?.id + startActivityForResult( + ArticleEditActivity.getPatchIntent( + requireContext(), + mViewModel.detailEntity!! + ), ArticleDetailActivity.ARTICLE_PATCH_REQUEST + ) + NewLogUtils.logSharePanelClick( + "click_modification", mViewModel.detailEntity?.user?.id ?: "", "帖子", mViewModel.detailEntity?.id - ?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType) + ?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType + ) } "投诉" -> { ifLogin("帖子详情") { BbsReportHelper.showReportDialog(mViewModel.detailEntity?.id ?: "") } - NewLogUtils.logSharePanelClick("click_report", mViewModel.detailEntity?.user?.id + NewLogUtils.logSharePanelClick( + "click_report", mViewModel.detailEntity?.user?.id ?: "", "帖子", mViewModel.detailEntity?.id - ?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType) + ?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType + ) } "申请加精" -> { - if (mViewModel.detailEntity?.choicenessStatus == "apply") { + if (mViewModel.detailEntity?.getSimplifyChoicenessStatus() == "apply") { ToastUtils.showToast("申请加精审核中") return@showMoreDialog } mViewModel.doApplyHighlightThisArticle(mViewModel.articleId) - NewLogUtils.logSharePanelClick("click_apply_essence", mViewModel.detailEntity?.user?.id + NewLogUtils.logSharePanelClick( + "click_apply_essence", mViewModel.detailEntity?.user?.id ?: "", "帖子", mViewModel.detailEntity?.id - ?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType) + ?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType + ) } "加精选" -> { + if (mViewModel.detailEntity?.getSimplifyChoicenessStatus() == "apply") { + ToastUtils.showToast("加精审核中") + return@showMoreDialog + } addEssenceForum(mViewModel.detailEntity!!) - NewLogUtils.logSharePanelClick("click_essence", mViewModel.detailEntity?.user?.id + NewLogUtils.logSharePanelClick( + "click_essence", mViewModel.detailEntity?.user?.id ?: "", "帖子", mViewModel.detailEntity?.id - ?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType) + ?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType + ) } "修改活动标签" -> { - ChooseActivityDialogFragment.show(requireActivity() as AppCompatActivity, ChooseActivityDialogFragment.ActivityLabelLocation.BBS_ARTICLE, mViewModel.detailEntity?.tagActivityId) { label -> - if (label != null) { - mViewModel.modifyArticleActivityTag(mViewModel.detailEntity?.community?.id - ?: "", mViewModel.articleId, label) - NewLogUtils.logSharePanelClick("click_modification_activity_tag", mViewModel.detailEntity?.user?.id - ?: "", "帖子", mViewModel.detailEntity?.id - ?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType) - } + ChooseActivityDialogFragment.show( + requireActivity() as AppCompatActivity, + ChooseActivityDialogFragment.ActivityLabelLocation.BBS_ARTICLE, + mViewModel.detailEntity?.tagActivityId + ) { label -> + mViewModel.modifyArticleActivityTag( + mViewModel.detailEntity?.community?.id ?: "", + mViewModel.articleId, + label + ) + NewLogUtils.logSharePanelClick( + "click_modification_activity_tag", + mViewModel.detailEntity?.user?.id ?: "", + "帖子", + mViewModel.detailEntity?.id ?: "", + mViewModel.detailEntity?.community?.id ?: "", + bbsType + ) } } - "删除" -> { - DialogUtils.showNewAlertDialog(requireContext(), "提示", "删除帖子后,其中的所有评论及回复都将被删除", "取消", "删除", {}, { - mViewModel.doHideThisArticle(mViewModel.detailEntity!!.community.id, mViewModel.articleId) - }) - NewLogUtils.logSharePanelClick("click_delete", mViewModel.detailEntity?.user?.id + "删除", "隐藏" -> { + DialogUtils.showNewAlertDialog( + requireContext(), + "提示", + "${it.text}帖子后,其中的所有评论及回复都将被${it.text}", + "取消", + it.text, + {}, + { + mViewModel.doHideThisArticle( + mViewModel.detailEntity!!.community.id, + mViewModel.articleId + ) + }) + NewLogUtils.logSharePanelClick( + "click_delete", mViewModel.detailEntity?.user?.id ?: "", "帖子", mViewModel.detailEntity?.id - ?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType) + ?: "", mViewModel.detailEntity?.community?.id ?: "", bbsType + ) } } } @@ -534,36 +655,51 @@ class ArticleDetailFragment : BaseCommentFragment Permissions.GUEST) { - highlightDialogHintContent = if (permissions.highlightCommunityArticle == Permissions.REPORTER) { - "你的操作将提交给小编审核,确定提交吗?" - } else { - "你的操作将立即生效,确定提交吗?(你的管理权限为:高级)" - } - } - when { - article.isHighlighted -> toast("帖子已经加精") - - else -> DialogUtils.showAlertDialog(requireContext(), "加精帖子", highlightDialogHintContent, - "确定", "取消", - { mViewModel.doHighlightThisArticle(mViewModel.detailEntity!!.community.id, mViewModel.articleId) }, null) + highlightDialogHintContent = + if (permissions.highlightCommunityArticle == Permissions.REPORTER) { + "你的操作将提交给小编审核,确定提交吗?" + } else { + "你的操作将立即生效,确定提交吗?" + } } + DialogUtils.showAlertDialog( + requireContext(), + "加精帖子", + highlightDialogHintContent, + "确定", + "取消", + { + mViewModel.doHighlightThisArticle( + mViewModel.detailEntity!!.community.id, + mViewModel.articleId + ) + }, + null + ) } private fun updateView() { val articleDetail = mViewModel.detailEntity ?: return - updateFollowMenu(articleDetail.me.isFollower, articleDetail.user.id == UserManager.getInstance().userId) + updateFollowMenu( + articleDetail.me.isFollower, + articleDetail.user.id == UserManager.getInstance().userId + ) mReuseNoConn?.visibility = View.GONE mListLoading?.visibility = View.GONE mBinding.inputContainer.bottomContainer.visibility = View.VISIBLE mBinding.bottomShadowView.visibility = View.VISIBLE - mBinding.inputContainer.bottomCommentTv.text = mViewModel.getCommentText(mViewModel.detailEntity?.count?.comment - ?: 0, "评论") + mBinding.inputContainer.bottomCommentTv.text = mViewModel.getCommentText( + mViewModel.detailEntity?.count?.comment + ?: 0, "评论" + ) val community = articleDetail.community - val icon = if (!community.icon.isNullOrEmpty()) community.icon else community.game?.getIcon() - val iconSubscript = if (!community.iconSubscript.isNullOrEmpty()) community.iconSubscript else community.game?.iconSubscript + val icon = + if (!community.icon.isNullOrEmpty()) community.icon else community.game?.getIcon() + val iconSubscript = + if (!community.iconSubscript.isNullOrEmpty()) community.iconSubscript else community.game?.iconSubscript mBinding.forumGameIv.displayGameIcon(icon, iconSubscript) ImageUtils.display(mBinding.userAvatar, articleDetail.user.icon) mBinding.forumGameIv.visibility = View.VISIBLE @@ -574,7 +710,8 @@ class ArticleDetailFragment : BaseCommentFragment 56F.dip2px()) { mBinding.forumGameIv.visibility = View.GONE mBinding.userAvatar.visibility = View.VISIBLE - mAttentionMenu?.isVisible = articleDetail.user.id != UserManager.getInstance().userId + mAttentionMenu?.isVisible = + articleDetail.user.id != UserManager.getInstance().userId mBinding.forumTitleTv.text = articleDetail.user.name mIsToolbarUserShow = true } else if (mIsToolbarUserShow && mListRv.computeVerticalScrollOffset() <= 56F.dip2px()) { @@ -590,8 +727,10 @@ class ArticleDetailFragment : BaseCommentFragment 0) + NewLogUtils.logSlideArticleOrQuestionDetail( + "帖子详情页", "slide_article_detail_page", (filterView?.top + ?: 0) > 0 + ) if ((filterView?.top ?: 0) > 0) { NewLogUtils.logCommentAreaEnter("帖子") } @@ -609,10 +748,20 @@ class ArticleDetailFragment : BaseCommentFragment() override fun provideDataObservable(page: Int): Observable> { - return RetrofitManager.getInstance(getApplication()).api.getCommunityArticleCommentList(communityId, articleId, currentSortType.value, page) + return RetrofitManager.getInstance(getApplication()).api.getCommunityArticleCommentList( + communityId, + articleId, + currentSortType.value, + page + ) } override fun mergeResultLiveData() { @@ -59,167 +72,193 @@ class ArticleDetailViewModel(application: Application, fun getArticleDetail() { mApi.getCommunityArticleDetail(communityId, articleId) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Response() { - override fun onResponse(response: ArticleDetailEntity?) { - detailEntity = response - topItemData = CommentItemData(articleDetail = response) - commentCount = response?.count?.comment ?: 0 - loadResultLiveData.postValue(LoadResult.SUCCESS) - mergeListData(mListLiveData.value, displayFloor = true) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: ArticleDetailEntity?) { + detailEntity = response + topItemData = CommentItemData(articleDetail = response) + commentCount = response?.count?.comment ?: 0 + loadResultLiveData.postValue(LoadResult.SUCCESS) + mergeListData(mListLiveData.value, displayFloor = true) - NewLogUtils.logForumContentBrowser(articleId, "bbs_article") - } + NewLogUtils.logForumContentBrowser(articleId, "bbs_article") + } - override fun onFailure(e: HttpException?) { - if (e?.code().toString().startsWith("404")) { - loadResultLiveData.postValue(LoadResult.DELETED) - } else { - loadResultLiveData.postValue(LoadResult.NETWORK_ERROR) - } + override fun onFailure(e: HttpException?) { + if (e?.code().toString().startsWith("404")) { + loadResultLiveData.postValue(LoadResult.DELETED) + } else { + loadResultLiveData.postValue(LoadResult.NETWORK_ERROR) } - }) + } + }) } fun cancelLikeArticle() { mApi.postCommunityArticleUnVote(communityId, articleId) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Response() { - override fun onResponse(response: VoteEntity?) { - // 赞同减一 - detailEntity?.me?.isCommunityArticleVote = false - detailEntity!!.count.vote-- + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: VoteEntity?) { + // 赞同减一 + detailEntity?.me?.isCommunityArticleVote = false + detailEntity!!.count.vote-- - like.postValue(response) + like.postValue(response) - syncVoteData() - } + syncVoteData() + } - override fun onFailure(e: HttpException?) { - ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string()) - } - }) + override fun onFailure(e: HttpException?) { + ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string()) + } + }) } fun likeArticle() { mApi.postCommunityArticleVote(communityId, articleId) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Response() { - override fun onResponse(response: VoteEntity?) { - // 赞同加一 - detailEntity?.me?.isCommunityArticleOppose = false - detailEntity?.me?.isCommunityArticleVote = true - detailEntity!!.count.vote++ + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: VoteEntity?) { + // 赞同加一 + detailEntity?.me?.isCommunityArticleOppose = false + detailEntity?.me?.isCommunityArticleVote = true + detailEntity!!.count.vote++ - like.postValue(response) + like.postValue(response) - syncVoteData() + syncVoteData() - EnergyTaskHelper.postEnergyTask("vote_community_article", articleId) - } + EnergyTaskHelper.postEnergyTask("vote_community_article", articleId) + } - override fun onFailure(e: HttpException?) { - ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string()) - } - }) + override fun onFailure(e: HttpException?) { + ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string()) + } + }) } fun dislikeArticle() { mApi.postCommunityArticleOppose(communityId, articleId) - .subscribeOn(Schedulers.io()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - if (detailEntity?.me?.isCommunityArticleVote == true) { - detailEntity!!.count.vote-- - } - detailEntity?.me?.isCommunityArticleOppose = true - detailEntity?.me?.isCommunityArticleVote = false - - dislike.postValue(true) - - syncVoteData() + .subscribeOn(Schedulers.io()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + if (detailEntity?.me?.isCommunityArticleVote == true) { + detailEntity!!.count.vote-- } + detailEntity?.me?.isCommunityArticleOppose = true + detailEntity?.me?.isCommunityArticleVote = false - override fun onFailure(e: HttpException?) { - ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string()) - } - }) + dislike.postValue(true) + + syncVoteData() + } + + override fun onFailure(e: HttpException?) { + ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string()) + } + }) } fun cancelDislikeArticle() { mApi.postCommunityArticleUnoppose(communityId, articleId) - .subscribeOn(Schedulers.io()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - detailEntity?.me?.isCommunityArticleOppose = false + .subscribeOn(Schedulers.io()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + detailEntity?.me?.isCommunityArticleOppose = false - dislike.postValue(false) + dislike.postValue(false) - syncVoteData() - } + syncVoteData() + } - override fun onFailure(e: HttpException?) { - ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string()) - } - }) + override fun onFailure(e: HttpException?) { + ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string()) + } + }) } private fun syncVoteData() { articleId.apply { - SyncPageRepository.postSyncData(SyncDataEntity(this, + SyncPageRepository.postSyncData( + SyncDataEntity( + this, SyncFieldConstants.ARTICLE_VOTE_COUNT, detailEntity?.count?.vote, - checkFieldEntity = true)) - SyncPageRepository.postSyncData(SyncDataEntity(this, + checkFieldEntity = true + ) + ) + SyncPageRepository.postSyncData( + SyncDataEntity( + this, SyncFieldConstants.ARTICLE_VOTE, detailEntity?.me?.isCommunityArticleVote, - checkFieldEntity = true)) + checkFieldEntity = true + ) + ) } } private fun syncFollowData(isFollow: Boolean) { articleId.apply { - SyncPageRepository.postSyncData(SyncDataEntity(this, + SyncPageRepository.postSyncData( + SyncDataEntity( + this, SyncFieldConstants.IS_FOLLOWER, isFollow, - checkFieldEntity = true)) + checkFieldEntity = true + ) + ) } } fun collectionCommand(isCollection: Boolean, callback: (isFollow: Boolean) -> Unit) { val observable = if (isCollection) { - mApi.postCommunityArticleFavorites(UserManager.getInstance().userId, communityId, articleId) + mApi.postCommunityArticleFavorites( + UserManager.getInstance().userId, + communityId, + articleId + ) } else { - mApi.deleteCommunityArticleFavorites(UserManager.getInstance().userId, communityId, articleId) + mApi.deleteCommunityArticleFavorites( + UserManager.getInstance().userId, + communityId, + articleId + ) } observable - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - EventBus.getDefault().post(EBCollectionChanged(articleId, true, CollectionUtils.CollectionType.communityArticle)) - if (isCollection) { - // 收藏成功 - callback(true) - ToastUtils.showToast(getApplication().getString(R.string.collection_success)) - } else { - // 取消收藏成功 - callback(false) - ToastUtils.showToast(getApplication().getString(R.string.collection_cancel)) - } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + EventBus.getDefault().post( + EBCollectionChanged( + articleId, + true, + CollectionUtils.CollectionType.communityArticle + ) + ) + if (isCollection) { + // 收藏成功 + callback(true) + ToastUtils.showToast(getApplication().getString(R.string.collection_success)) + } else { + // 取消收藏成功 + callback(false) + ToastUtils.showToast(getApplication().getString(R.string.collection_cancel)) } + } - override fun onFailure(e: HttpException?) { - if (isCollection) { - ToastUtils.showToast(getApplication().getString(R.string.collection_failure)) - } else { - ToastUtils.showToast(getApplication().getString(R.string.collection_cancel_failure)) - } + override fun onFailure(e: HttpException?) { + if (isCollection) { + ToastUtils.showToast(getApplication().getString(R.string.collection_failure)) + } else { + ToastUtils.showToast(getApplication().getString(R.string.collection_cancel_failure)) } - }) + } + }) } fun follow() { @@ -237,98 +276,104 @@ class ArticleDetailViewModel(application: Application, mApi.deleteFollowing(targetUserId) } observable - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - if (isFollow) { - // 关注成功 - mFollowLiveData.postValue(true) - syncFollowData(true) - } else { - // 取消关注成功 - mFollowLiveData.postValue(false) - syncFollowData(false) - } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + if (isFollow) { + // 关注成功 + mFollowLiveData.postValue(true) + syncFollowData(true) + } else { + // 取消关注成功 + mFollowLiveData.postValue(false) + syncFollowData(false) } + EventBus.getDefault().post(EBUserFollow(targetUserId, isFollow)) + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - Utils.toast(getApplication(), R.string.loading_failed_hint) - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + Utils.toast(getApplication(), R.string.loading_failed_hint) + } + }) } fun doHighlightThisArticle(communityId: String, articleId: String?) { mApi.highlightCommunityArticle(communityId, articleId) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - highlight.postValue(true) - } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + highlight.postValue(true) + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - highlight.postValue(false) - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + highlight.postValue(false) + } + }) } fun doApplyHighlightThisArticle(articleId: String?) { mApi.applyHighlightCommunityArticle(articleId) - .compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - applyHighlight.postValue(true) - } + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + applyHighlight.postValue(true) + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - applyHighlight.postValue(false) - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + applyHighlight.postValue(false) + } + }) } fun doHideThisArticle(communityId: String, articleId: String?) { mApi.hideCommunityArticle(communityId, articleId) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - hide.postValue(true) - } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + hide.postValue(true) + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - hide.postValue(false) - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + hide.postValue(false) + } + }) } - fun modifyArticleActivityTag(communityId: String, articleId: String, label: ActivityLabelEntity) { - val body = json { "tag_activity_id" to label.id }.toRequestBody() + fun modifyArticleActivityTag( + communityId: String, + articleId: String, + label: ActivityLabelEntity? + ) { + val body = json { "tag_activity_id" to label?.id }.toRequestBody() mApi.modifyArticleActivityTag(communityId, articleId, body) - .compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - detailEntity?.apply { - tagActivityId = label.id - tagActivityName = label.name - updateDetailLiveData.postValue(this) - } + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + detailEntity?.apply { + tagActivityId = label?.id ?: "" + tagActivityName = label?.name ?: "" + updateDetailLiveData.postValue(this) + ToastUtils.showToast("修改活动标签成功") } + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - ToastUtils.showToast("修改活动标签失败") - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + ToastUtils.showToast("修改活动标签失败") + } + }) } override fun hideCommentSuccess() { @@ -355,15 +400,18 @@ class ArticleDetailViewModel(application: Application, // }) // } - class Factory(private val application: Application, - private val articleId: String = "", - private val communityId: String = "") : ViewModelProvider.NewInstanceFactory() { + class Factory( + private val application: Application, + private val articleId: String = "", + private val communityId: String = "" + ) : ViewModelProvider.NewInstanceFactory() { override fun create(modelClass: Class): T { return ArticleDetailViewModel( - application = application, - articleId = articleId, - communityId = communityId) as T + application = application, + articleId = articleId, + communityId = communityId + ) as T } } diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/edit/ArticleEditActivity.kt b/app/src/main/java/com/gh/gamecenter/qa/article/edit/ArticleEditActivity.kt index 652b8f92ec..eba4b7853a 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/article/edit/ArticleEditActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/article/edit/ArticleEditActivity.kt @@ -482,6 +482,7 @@ class ArticleEditActivity : BaseRichEditorActivity(), Keyb } else if (mViewModel.type == BbsType.OFFICIAL_BBS.value) { if (mViewModel.gameEntity == null) { mGameName.text = "选择游戏" + mForumIcon.visibility = View.GONE } else { mGameName.text = mViewModel.gameEntity?.name mForumIcon.displayGameIcon(mViewModel.gameEntity?.icon, mViewModel.gameEntity?.iconSubscript) diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentAdapter.kt index e0a6637d38..90e6f16681 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentAdapter.kt @@ -16,12 +16,14 @@ import com.gh.gamecenter.baselist.ListAdapter import com.gh.gamecenter.entity.CommentEntity import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity -class NewCommentAdapter(context: Context, - var mViewModel: NewCommentViewModel, - var mIsShowingConversation: Boolean, - var mCommentCallBackListener: OnCommentCallBackListener, - var mCommentOptionClickListener: OnCommentOptionClickListener? = null, - var mEntrance: String) : ListAdapter(context) { +class NewCommentAdapter( + context: Context, + var mViewModel: NewCommentViewModel, + var mIsShowingConversation: Boolean, + var mCommentCallBackListener: OnCommentCallBackListener, + var mCommentOptionClickListener: OnCommentOptionClickListener? = null, + var mEntrance: String +) : ListAdapter(context) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return if (viewType == ItemViewType.LOADING) { @@ -61,12 +63,28 @@ class NewCommentAdapter(context: Context, val colon = " :" val parentUserName = " ${commentEntity.parentUser?.name} " - val prefixSpan = SpanBuilder(prefix).color(holder.itemView.context, 0, prefix.length, R.color.text_999999).build() + val prefixSpan = SpanBuilder(prefix).color( + holder.itemView.context, + 0, + prefix.length, + R.color.text_999999 + ).build() val parentUserNameSpan = SpanBuilder(parentUserName) - .click(0, parentUserName.length, R.color.text_666666) { - DirectUtils.directToHomeActivity(holder.itemView.context, commentEntity.user.id, 1, mEntrance, "") - }.build() - val colonSpan = SpanBuilder(colon).color(holder.itemView.context, 0, colon.length, R.color.text_999999).build() + .click(0, parentUserName.length, R.color.text_666666) { + DirectUtils.directToHomeActivity( + holder.itemView.context, + commentEntity.user.id, + 1, + mEntrance, + "" + ) + }.build() + val colonSpan = SpanBuilder(colon).color( + holder.itemView.context, + 0, + colon.length, + R.color.text_999999 + ).build() val authorSpan = if (commentEntity.parentUser?.me?.isCommentOwner == true) { SpanBuilder("作者").image(0, "作者".length, R.drawable.ic_hint_author).build() } else { @@ -74,17 +92,18 @@ class NewCommentAdapter(context: Context, } holder.commentContentTv.text = SpannableStringBuilder() - .append(prefixSpan) - .append(parentUserNameSpan) - .append(authorSpan) - .append(colonSpan) - .append(commentEntity.content) + .append(prefixSpan) + .append(parentUserNameSpan) + .append(authorSpan) + .append(colonSpan) + .append(commentEntity.content) } else { holder.commentContentTv.text = commentEntity.content } holder.commentContentTv.setOnLongClickListener(View.OnLongClickListener { isChildLongClick = true - commentEntity.content?.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "")?.copyTextAndToast() + commentEntity.content?.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "") + ?.copyTextAndToast() return@OnLongClickListener true }) @@ -100,23 +119,51 @@ class NewCommentAdapter(context: Context, holder.userBadgeSdv.setOnClickListener { v -> DialogUtils.showViewBadgeDialog(mContext, commentEntity.user.badge) { - MtaHelper.onEvent("进入徽章墙_用户记录", key, commentEntity.user.name + "(" + commentEntity.user.id + ")") + MtaHelper.onEvent( + "进入徽章墙_用户记录", + key, + commentEntity.user.name + "(" + commentEntity.user.id + ")" + ) MtaHelper.onEvent("徽章中心", "进入徽章中心", key) - DirectUtils.directToBadgeWall(mContext, commentEntity.user.id, commentEntity.user.name, commentEntity.user.icon) + DirectUtils.directToBadgeWall( + mContext, + commentEntity.user.id, + commentEntity.user.name, + commentEntity.user.icon + ) } } holder.badgeNameTv.setOnClickListener { v -> holder.userBadgeSdv.performClick() } holder.quoteAuthorBadgeSdv.setOnClickListener { v -> DialogUtils.showViewBadgeDialog(mContext, commentEntity.parentUser!!.badge) { - MtaHelper.onEvent("进入徽章墙_用户记录", key, commentEntity.parentUser!!.name + "(" + commentEntity.parentUser!!.id + ")") + MtaHelper.onEvent( + "进入徽章墙_用户记录", + key, + commentEntity.parentUser!!.name + "(" + commentEntity.parentUser!!.id + ")" + ) MtaHelper.onEvent("徽章中心", "进入徽章中心", key) - DirectUtils.directToBadgeWall(mContext, commentEntity.parentUser!!.id, commentEntity.parentUser!!.name, commentEntity.parentUser!!.icon) + DirectUtils.directToBadgeWall( + mContext, + commentEntity.parentUser!!.id, + commentEntity.parentUser!!.name, + commentEntity.parentUser!!.icon + ) } } holder.commentLikeContainer.setOnClickListener { - CommentUtils.likeComment(mContext, mViewModel.answerId, mViewModel.articleId, - mViewModel.communityId, mViewModel.videoId, mViewModel.questionId, commentEntity, holder.commentLikeCountTv, holder.commentLikeIv, null) + CommentUtils.likeComment( + mContext, + mViewModel.answerId, + mViewModel.articleId, + mViewModel.communityId, + mViewModel.videoId, + mViewModel.questionId, + commentEntity, + holder.commentLikeCountTv, + holder.commentLikeIv, + null + ) } holder.itemView.setOnClickListener { @@ -135,33 +182,40 @@ class NewCommentAdapter(context: Context, when (mViewModel.commentType) { CommentType.ANSWER, CommentType.ANSWER_CONVERSATION -> { - CommentHelper.showAnswerCommentOptions(it, - commentEntity, - mIsShowingConversation, - mViewModel.answerId, - mCommentOptionClickListener) + CommentHelper.showAnswerCommentOptions( + it, + commentEntity, + mIsShowingConversation, + mViewModel.answerId, + mCommentOptionClickListener + ) } CommentType.COMMUNITY_ARTICLE, CommentType.COMMUNITY_ARTICLE_CONVERSATION -> { - CommentHelper.showCommunityArticleCommentOptions(it, - commentEntity, - mIsShowingConversation, - mViewModel.articleId, - mViewModel.communityId, - isShowTop = false, - ignoreModerator = false, - listener = mCommentOptionClickListener) + CommentHelper.showCommunityArticleCommentOptions( + it, + commentEntity, + mIsShowingConversation, + mViewModel.articleId, + mViewModel.communityId, + isShowTop = false, + ignoreModerator = false, + listener = mCommentOptionClickListener + ) } CommentType.VIDEO, CommentType.VIDEO_CONVERSATION -> { - CommentHelper.showVideoCommentOptions(it, - commentEntity, - mIsShowingConversation, - mViewModel.videoId, - mViewModel.isVideoAuthor, - mCommentOptionClickListener) + CommentHelper.showVideoCommentOptions( + it, + commentEntity, + mIsShowingConversation, + mViewModel.videoId, + mViewModel.isVideoAuthor, + false, + mCommentOptionClickListener + ) } } } @@ -182,8 +236,24 @@ class NewCommentAdapter(context: Context, val userHomePageTabPosition = if (mViewModel.commentType.isVideo()) 2 else 1 - holder.commentUserIconDv.setOnClickListener { DirectUtils.directToHomeActivity(mContext, commentEntity.user.id, userHomePageTabPosition, mEntrance, path) } - holder.commentUserNameTv.setOnClickListener { DirectUtils.directToHomeActivity(mContext, commentEntity.user.id, userHomePageTabPosition, mEntrance, path) } + holder.commentUserIconDv.setOnClickListener { + DirectUtils.directToHomeActivity( + mContext, + commentEntity.user.id, + userHomePageTabPosition, + mEntrance, + path + ) + } + holder.commentUserNameTv.setOnClickListener { + DirectUtils.directToHomeActivity( + mContext, + commentEntity.user.id, + userHomePageTabPosition, + mEntrance, + path + ) + } if (commentEntity.priority != 0) { holder.commentBadge.visibility = View.VISIBLE @@ -194,7 +264,12 @@ class NewCommentAdapter(context: Context, private fun initFooterViewHolder(holder: FooterViewHolder) { holder.hint.textSize = 12f - holder.hint.setTextColor(ContextCompat.getColor(holder.itemView.context, R.color.text_B3B3B3)) + holder.hint.setTextColor( + ContextCompat.getColor( + holder.itemView.context, + R.color.text_B3B3B3 + ) + ) if (mIsNetworkError) { holder.loading.visibility = View.GONE holder.hint.setText(R.string.loading_error_network) diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/StairsCommentViewHolder.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/StairsCommentViewHolder.kt index ea6c9dce03..d0777345a8 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/comment/StairsCommentViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/comment/StairsCommentViewHolder.kt @@ -20,7 +20,10 @@ import com.gh.gamecenter.manager.UserManager import com.halo.assistant.HaloApp import io.reactivex.disposables.Disposable -class StairsCommentViewHolder(val binding: StairsCommentItemBinding, val isReplyComment: Boolean = false) : BaseRecyclerViewHolder(binding.root) { +class StairsCommentViewHolder( + val binding: StairsCommentItemBinding, + val isReplyComment: Boolean = false +) : BaseRecyclerViewHolder(binding.root) { var isFirstClick = true @@ -32,7 +35,12 @@ class StairsCommentViewHolder(val binding: StairsCommentItemBinding, val isReply binding.commentLikeCount.visibility = View.GONE } else { // 检查是否已点赞 if (userDataEntity != null && userDataEntity.isCommentVoted) { - binding.commentLikeCount.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font)) + binding.commentLikeCount.setTextColor( + ContextCompat.getColor( + mContext, + R.color.theme_font + ) + ) binding.commentLike.setImageResource(R.drawable.comment_vote_select) } binding.commentLikeCount.visibility = View.VISIBLE @@ -56,12 +64,18 @@ class StairsCommentViewHolder(val binding: StairsCommentItemBinding, val isReply } if (parentUser != null && !TextUtils.isEmpty(parentUser.name)) { val name = "${entity.user.name} 回复 ${parentUser.name}" - binding.commentUserName.text = SpanBuilder(name).color((entity.user.name?.length - ?: 0) + 1, (entity.user.name?.length ?: 0) + 3, R.color.text_666666).build() + binding.commentUserName.text = SpanBuilder(name).color( + (entity.user.name?.length + ?: 0) + 1, (entity.user.name?.length ?: 0) + 3, R.color.text_666666 + ).build() } else { binding.commentUserName.text = userInfo.name } - binding.commentUserIcon.display(userInfo.iconBorder?.url, userInfo.icon, userInfo.auth?.icon) + binding.commentUserIcon.display( + userInfo.iconBorder?.url, + userInfo.icon, + userInfo.auth?.icon + ) } else { if (entity.me != null && entity.me!!.isContentOwner && entity.parent == null) { binding.commentAuthor.visibility = View.VISIBLE @@ -70,19 +84,31 @@ class StairsCommentViewHolder(val binding: StairsCommentItemBinding, val isReply } if (parentUser != null && !TextUtils.isEmpty(parentUser.name)) { val name = "${entity.user.name} 回复 ${parentUser.name}" - binding.commentUserName.text = SpanBuilder(name).color((entity.user.name?.length - ?: 0) + 1, (entity.user.name?.length ?: 0) + 3, R.color.text_666666).build() + binding.commentUserName.text = SpanBuilder(name).color( + (entity.user.name?.length + ?: 0) + 1, (entity.user.name?.length ?: 0) + 3, R.color.text_666666 + ).build() } else { binding.commentUserName.text = entity.user.name } - binding.commentUserIcon.display(entity.user.border, entity.user.icon, entity.user.auth?.icon) + binding.commentUserIcon.display( + entity.user.border, + entity.user.icon, + entity.user.auth?.icon + ) } } - fun initCommentViewHolder(holder: StairsCommentViewHolder, mViewModel: NewCommentViewModel, commentEntity: CommentEntity, - mEntrance: String, mIsShowingConversation: Boolean, mCommentOptionClickListener: OnCommentOptionClickListener?, - mCommentCallBackListener: OnCommentCallBackListener) { + fun initCommentViewHolder( + holder: StairsCommentViewHolder, + mViewModel: NewCommentViewModel, + commentEntity: CommentEntity, + mEntrance: String, + mIsShowingConversation: Boolean, + mCommentOptionClickListener: OnCommentOptionClickListener?, + mCommentCallBackListener: OnCommentCallBackListener + ) { val context = holder.binding.root.context var isChildLongClick = false holder.setCommentUserView(binding.root.context, commentEntity) @@ -98,19 +124,34 @@ class StairsCommentViewHolder(val binding: StairsCommentItemBinding, val isReply } else { 24f.dip2px() } - initStairsReplyComment(holder, mViewModel, commentEntity, mEntrance, mIsShowingConversation, mCommentOptionClickListener, mCommentCallBackListener) + initStairsReplyComment( + holder, + mViewModel, + commentEntity, + mEntrance, + mIsShowingConversation, + mCommentOptionClickListener, + mCommentCallBackListener + ) } holder.binding.commentContainer.layoutParams = params if (!TextUtils.isEmpty(mViewModel.videoId)) { - val spannable = TextHelper.getHighlightedSpannableStringThatIsWrappedInsideWrapper(context, commentEntity.content - ?: "") + val spannable = TextHelper.getHighlightedSpannableStringThatIsWrappedInsideWrapper( + context, commentEntity.content + ?: "" + ) //当评论同时满足以下两个条件:①来源于作者;②权重为1时,前端不显示“置顶”标志 if (!(commentEntity.me?.isContentOwner == true && commentEntity.priority == 1)) { if (commentEntity.priority != 0) { spannable.append(" ") - spannable.setSpan(CenterImageSpan(HaloApp.getInstance().application, R.drawable.ic_comment_top), spannable.length - 1, spannable.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + spannable.setSpan( + CenterImageSpan( + HaloApp.getInstance().application, + R.drawable.ic_comment_top + ), spannable.length - 1, spannable.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ) } } holder.binding.commentContent.text = spannable @@ -131,51 +172,108 @@ class StairsCommentViewHolder(val binding: StairsCommentItemBinding, val isReply holder.binding.sdvUserBadge.setOnClickListener { v -> DialogUtils.showViewBadgeDialog(binding.root.context, commentEntity.user.badge) { - MtaHelper.onEvent("进入徽章墙_用户记录", key, commentEntity.user.name + "(" + commentEntity.user.id + ")") + MtaHelper.onEvent( + "进入徽章墙_用户记录", + key, + commentEntity.user.name + "(" + commentEntity.user.id + ")" + ) MtaHelper.onEvent("徽章中心", "进入徽章中心", key) - DirectUtils.directToBadgeWall(binding.root.context, commentEntity.user.id, commentEntity.user.name, commentEntity.user.icon) + DirectUtils.directToBadgeWall( + binding.root.context, + commentEntity.user.id, + commentEntity.user.name, + commentEntity.user.icon + ) } } - var isVote = holder.binding.commentLikeCount.currentTextColor == ContextCompat.getColor(context, R.color.theme_font) + var isVote = holder.binding.commentLikeCount.currentTextColor == ContextCompat.getColor( + context, + R.color.theme_font + ) holder.binding.commentLikeContainer.setOnClickListener { FastClickUtils.click { if (!it) { - if (holder.binding.commentLikeCount.currentTextColor == ContextCompat.getColor(context, R.color.theme_font)) { + if (holder.binding.commentLikeCount.currentTextColor == ContextCompat.getColor( + context, + R.color.theme_font + ) + ) { commentEntity.vote = commentEntity.vote - 1 - holder.binding.commentLikeCount.setTextColor(ContextCompat.getColor(context, R.color.hint)) + holder.binding.commentLikeCount.setTextColor( + ContextCompat.getColor( + context, + R.color.hint + ) + ) holder.binding.commentLike.setImageResource(R.drawable.comment_vote_unselect) holder.binding.commentLikeCount.text = transSimpleCount(commentEntity.vote) - holder.binding.commentLikeCount.visibility = if (commentEntity.vote == 0) View.GONE else View.VISIBLE + holder.binding.commentLikeCount.visibility = + if (commentEntity.vote == 0) View.GONE else View.VISIBLE } else { commentEntity.vote = commentEntity.vote + 1 - holder.binding.commentLikeCount.setTextColor(ContextCompat.getColor(context, R.color.theme_font)) + holder.binding.commentLikeCount.setTextColor( + ContextCompat.getColor( + context, + R.color.theme_font + ) + ) holder.binding.commentLike.setImageResource(R.drawable.comment_vote_select) holder.binding.commentLikeCount.text = transSimpleCount(commentEntity.vote) holder.binding.commentLikeCount.visibility = View.VISIBLE } } else { - if (isVote && holder.binding.commentLikeCount.currentTextColor != ContextCompat.getColor(context, R.color.theme_font)) { + if (isVote && holder.binding.commentLikeCount.currentTextColor != ContextCompat.getColor( + context, + R.color.theme_font + ) + ) { //取消点赞 - CommentUtils.unVoteVideoComment(binding.root.context, mViewModel.videoId, commentEntity, holder.binding.commentLikeCount, holder.binding.commentLike) - } else if (!isVote && holder.binding.commentLikeCount.currentTextColor == ContextCompat.getColor(context, R.color.theme_font)) { + CommentUtils.unVoteVideoComment( + binding.root.context, + mViewModel.videoId, + commentEntity, + holder.binding.commentLikeCount, + holder.binding.commentLike + ) + } else if (!isVote && holder.binding.commentLikeCount.currentTextColor == ContextCompat.getColor( + context, + R.color.theme_font + ) + ) { //点赞 - CommentUtils.voteVideoComment(binding.root.context, mViewModel.answerId, mViewModel.articleId, - mViewModel.communityId, mViewModel.videoId, commentEntity, holder.binding.commentLikeCount, holder.binding.commentLike, null) + CommentUtils.voteVideoComment( + binding.root.context, + mViewModel.answerId, + mViewModel.articleId, + mViewModel.communityId, + mViewModel.videoId, + commentEntity, + holder.binding.commentLikeCount, + holder.binding.commentLike, + null + ) } - isVote = holder.binding.commentLikeCount.currentTextColor == ContextCompat.getColor(context, R.color.theme_font) + isVote = + holder.binding.commentLikeCount.currentTextColor == ContextCompat.getColor( + context, + R.color.theme_font + ) } } } holder.itemView.setOnLongClickListener(View.OnLongClickListener { isChildLongClick = true - CommentHelper.showVideoCommentOptions(holder.binding.commentLikeContainer, - commentEntity, - mIsShowingConversation, - mViewModel.videoId, - mViewModel.isVideoAuthor, - mCommentOptionClickListener) + CommentHelper.showVideoCommentOptions( + holder.binding.commentLikeContainer, + commentEntity, + mIsShowingConversation, + mViewModel.videoId, + mViewModel.isVideoAuthor, + false, + mCommentOptionClickListener + ) return@OnLongClickListener true }) @@ -201,21 +299,53 @@ class StairsCommentViewHolder(val binding: StairsCommentItemBinding, val isReply CommentType.COMMUNITY_QUESTION, CommentType.COMMUNITY_QUESTION_CONVERSATION -> "问题详情-评论管理" } - holder.binding.commentUserIcon.setOnClickListener { DirectUtils.directToHomeActivity(binding.root.context, commentEntity.user.id, 2, mEntrance, path) } - holder.binding.commentUserName.setOnClickListener { DirectUtils.directToHomeActivity(binding.root.context, commentEntity.user.id, 2, mEntrance, path) } + holder.binding.commentUserIcon.setOnClickListener { + DirectUtils.directToHomeActivity( + binding.root.context, + commentEntity.user.id, + 2, + mEntrance, + path + ) + } + holder.binding.commentUserName.setOnClickListener { + DirectUtils.directToHomeActivity( + binding.root.context, + commentEntity.user.id, + 2, + mEntrance, + path + ) + } } //楼层回复 - private fun initStairsReplyComment(holder: StairsCommentViewHolder, mViewModel: NewCommentViewModel, commentEntity: CommentEntity, - mEntrance: String, mIsShowingConversation: Boolean, mCommentOptionClickListener: OnCommentOptionClickListener?, - mCommentCallBackListener: OnCommentCallBackListener) { - holder.binding.replyContainer.visibility = if (commentEntity.reply > 0 || !commentEntity.subCommentList.isNullOrEmpty()) View.VISIBLE else View.GONE - holder.binding.expandMoreLl.visibility = if (commentEntity.reply > 0) View.VISIBLE else View.GONE + private fun initStairsReplyComment( + holder: StairsCommentViewHolder, + mViewModel: NewCommentViewModel, + commentEntity: CommentEntity, + mEntrance: String, + mIsShowingConversation: Boolean, + mCommentOptionClickListener: OnCommentOptionClickListener?, + mCommentCallBackListener: OnCommentCallBackListener + ) { + holder.binding.replyContainer.visibility = + if (commentEntity.reply > 0 || !commentEntity.subCommentList.isNullOrEmpty()) View.VISIBLE else View.GONE + holder.binding.expandMoreLl.visibility = + if (commentEntity.reply > 0) View.VISIBLE else View.GONE var stairsCommentReplyAdapter: StairsCommentReplyAdapter? holder.binding.stairsRv.apply { isNestedScrollingEnabled = false layoutManager = LinearLayoutManager(holder.binding.root.context) - stairsCommentReplyAdapter = StairsCommentReplyAdapter(holder.binding.root.context, mViewModel, commentEntity, mEntrance, mIsShowingConversation, mCommentOptionClickListener, mCommentCallBackListener) + stairsCommentReplyAdapter = StairsCommentReplyAdapter( + holder.binding.root.context, + mViewModel, + commentEntity, + mEntrance, + mIsShowingConversation, + mCommentOptionClickListener, + mCommentCallBackListener + ) if (commentEntity.subCommentList != null) { stairsCommentReplyAdapter?.replyComments?.addAll(commentEntity.subCommentList!!) } @@ -237,7 +367,8 @@ class StairsCommentViewHolder(val binding: StairsCommentItemBinding, val isReply page++ getCommentReply { if (it < 3 || replyComments.size == commentEntity.reply + (commentEntity.subCommentList?.size - ?: 0)) { + ?: 0) + ) { setExpandMoreView(holder, commentEntity, false) } else { setExpandMoreView(holder, commentEntity, true) @@ -249,17 +380,31 @@ class StairsCommentViewHolder(val binding: StairsCommentItemBinding, val isReply } } - private fun setExpandMoreView(holder: StairsCommentViewHolder, commentEntity: CommentEntity, isExpand: Boolean) { + private fun setExpandMoreView( + holder: StairsCommentViewHolder, + commentEntity: CommentEntity, + isExpand: Boolean + ) { if (isExpand) { holder.binding.expandMoreTv.text = if (isFirstClick) { "展开${commentEntity.reply}条回复" } else { "展开更多回复" } - holder.binding.expandMoreIv.setImageDrawable(ContextCompat.getDrawable(holder.binding.root.context, R.drawable.ic_expand_down)) + holder.binding.expandMoreIv.setImageDrawable( + ContextCompat.getDrawable( + holder.binding.root.context, + R.drawable.ic_expand_down + ) + ) } else { holder.binding.expandMoreTv.text = "收起" - holder.binding.expandMoreIv.setImageDrawable(ContextCompat.getDrawable(holder.binding.root.context, R.drawable.ic_shrink_up)) + holder.binding.expandMoreIv.setImageDrawable( + ContextCompat.getDrawable( + holder.binding.root.context, + R.drawable.ic_shrink_up + ) + ) } } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentAdapter.kt index d4a7cabdd8..f18b1a04c3 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentAdapter.kt @@ -28,16 +28,18 @@ import com.gh.gamecenter.qa.article.detail.ArticleDetailViewModel import com.gh.gamecenter.qa.article.detail.CommentItemData import com.gh.gamecenter.qa.comment.CommentActivity import com.gh.gamecenter.qa.comment.OnCommentOptionClickListener +import com.gh.gamecenter.qa.comment.conversation.CommentConversationViewModel import com.gh.gamecenter.qa.entity.ArticleDetailEntity import com.gh.gamecenter.qa.entity.QuestionsDetailEntity import com.gh.gamecenter.qa.video.detail.comment.VideoCommentViewModel -abstract class BaseCommentAdapter(context: Context, - private var mViewModel: BaseCommentViewModel, - private var mType: AdapterType, - private var mEntrance: String, - var commentClosure: ((CommentEntity) -> Unit)? = null) - : ListAdapter(context), ISyncAdapterHandler { +abstract class BaseCommentAdapter( + context: Context, + private var mViewModel: BaseCommentViewModel, + private var mType: AdapterType, + private var mEntrance: String, + var commentClosure: ((CommentEntity) -> Unit)? = null +) : ListAdapter(context), ISyncAdapterHandler { var filterVH: CommentFilterViewHolder? = null @@ -67,31 +69,59 @@ abstract class BaseCommentAdapter(context: Context, && oldItem?.commentNormal?.floor == newItem?.commentNormal?.floor && oldItem?.commentNormal?.isTop == newItem?.commentNormal?.isTop && oldItem?.commentNormal?.accept == newItem?.commentNormal?.accept + && oldItem?.commentNormal?.choiceness == newItem?.commentNormal?.choiceness } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (viewType) { ItemViewType.ITEM_FOOTER -> { - val binding: ItemArticleDetailCommentFooterBinding = DataBindingUtil.inflate(mLayoutInflater, R.layout.item_article_detail_comment_footer, parent, false) + val binding: ItemArticleDetailCommentFooterBinding = DataBindingUtil.inflate( + mLayoutInflater, + R.layout.item_article_detail_comment_footer, + parent, + false + ) CommentFooterViewHolder(binding) } ITEM_COMMENT_NORMAL -> { - val binding: ItemArticleDetailCommentBinding = DataBindingUtil.inflate(mLayoutInflater, R.layout.item_article_detail_comment, parent, false) + val binding: ItemArticleDetailCommentBinding = DataBindingUtil.inflate( + mLayoutInflater, + R.layout.item_article_detail_comment, + parent, + false + ) CommentItemViewHolder(binding, mType) } ITEM_FILTER -> { - val binding: PieceArticleDetailCommentFilterBinding = DataBindingUtil.inflate(mLayoutInflater, R.layout.piece_article_detail_comment_filter, parent, false) + val binding: PieceArticleDetailCommentFilterBinding = DataBindingUtil.inflate( + mLayoutInflater, + R.layout.piece_article_detail_comment_filter, + parent, + false + ) CommentFilterViewHolder(binding).apply { filterVH = this } } ITEM_ERROR_EMPTY -> { - CommentErrorViewHolder(mLayoutInflater.inflate(R.layout.item_article_detail_comment_empty, parent, false)) + CommentErrorViewHolder( + mLayoutInflater.inflate( + R.layout.item_article_detail_comment_empty, + parent, + false + ) + ) } ITEM_ERROR_CONNECTION -> { - CommentErrorViewHolder(mLayoutInflater.inflate(R.layout.item_article_detail_comment_empty, parent, false)) + CommentErrorViewHolder( + mLayoutInflater.inflate( + R.layout.item_article_detail_comment_empty, + parent, + false + ) + ) } else -> throw IllegalAccessException() @@ -119,8 +149,14 @@ abstract class BaseCommentAdapter(context: Context, override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when (holder) { is CommentItemViewHolder -> { - holder.bindComment(mEntityList[position].commentNormal!!, mViewModel, mEntrance, commentClosure) { deleteCommentEntity -> - val findEntity = mEntityList.find { it.commentNormal != null && it.commentNormal?.id == deleteCommentEntity.id } + holder.bindComment( + mEntityList[position].commentNormal!!, + mViewModel, + mEntrance, + commentClosure + ) { deleteCommentEntity -> + val findEntity = + mEntityList.find { it.commentNormal != null && it.commentNormal?.id == deleteCommentEntity.id } val index = mEntityList.indexOf(findEntity) mEntityList.remove(findEntity) notifyItemRemoved(index) @@ -132,18 +168,26 @@ abstract class BaseCommentAdapter(context: Context, val isArticleDetail = this is ArticleDetailAdapter if (isArticleDetail) { - SyncPageRepository.postSyncData(SyncDataEntity(mViewModel.articleId, + SyncPageRepository.postSyncData( + SyncDataEntity( + mViewModel.articleId, SyncFieldConstants.ARTICLE_COMMENT_COUNT, mViewModel.commentCount, - checkFieldEntity = true)) + checkFieldEntity = true + ) + ) } else { mEntityList[0].commentTop?.reply = (mEntityList[0].commentTop?.reply - ?: 0) - 1 - SyncPageRepository.postSyncData(SyncDataEntity(mEntityList[0].commentTop?.id - ?: "", + ?: 0) - 1 + SyncPageRepository.postSyncData( + SyncDataEntity( + mEntityList[0].commentTop?.id + ?: "", SyncFieldConstants.ARTICLE_COMMENT_REPLY_COUNT, mEntityList[0].commentTop?.reply, - checkFieldEntity = true)) + checkFieldEntity = true + ) + ) //刷新评论详情头部 notifyItemChanged(0) } @@ -163,7 +207,8 @@ abstract class BaseCommentAdapter(context: Context, return Pair(comment.id ?: "", comment) } - inner class CommentFooterViewHolder(var binding: ItemArticleDetailCommentFooterBinding) : RecyclerView.ViewHolder(binding.root) { + inner class CommentFooterViewHolder(var binding: ItemArticleDetailCommentFooterBinding) : + RecyclerView.ViewHolder(binding.root) { fun bindView(isLoading: Boolean, isNetworkError: Boolean, isOver: Boolean) { when { isNetworkError -> { @@ -187,8 +232,13 @@ abstract class BaseCommentAdapter(context: Context, } inner class CommentErrorViewHolder(view: View) : RecyclerView.ViewHolder(view) - inner class CommentFilterViewHolder(var binding: PieceArticleDetailCommentFilterBinding) : RecyclerView.ViewHolder(binding.root) { - fun bindView(article: ArticleDetailEntity? = null, questions: QuestionsDetailEntity? = null, comment: CommentEntity? = null) { + inner class CommentFilterViewHolder(var binding: PieceArticleDetailCommentFilterBinding) : + RecyclerView.ViewHolder(binding.root) { + fun bindView( + article: ArticleDetailEntity? = null, + questions: QuestionsDetailEntity? = null, + comment: CommentEntity? = null + ) { binding.run { val commentCount = mViewModel.commentCount commentHintTv.text = when { @@ -232,7 +282,8 @@ abstract class BaseCommentAdapter(context: Context, private fun updateSortType() { binding.run { - val isLatestSelected = mViewModel.currentSortType == BaseCommentViewModel.SortType.LATEST + val isLatestSelected = + mViewModel.currentSortType == BaseCommentViewModel.SortType.LATEST val selectedTextView = if (isLatestSelected) filterLatestTv else filterOldestTv val unselectedTextView = if (!isLatestSelected) filterLatestTv else filterOldestTv @@ -242,8 +293,10 @@ abstract class BaseCommentAdapter(context: Context, } } - class CommentItemViewHolder(var binding: ItemArticleDetailCommentBinding, var type: AdapterType) - : RecyclerView.ViewHolder(binding.root) { + class CommentItemViewHolder( + var binding: ItemArticleDetailCommentBinding, + var type: AdapterType + ) : RecyclerView.ViewHolder(binding.root) { init { if (type == AdapterType.SUB_COMMENT) { @@ -254,10 +307,13 @@ abstract class BaseCommentAdapter(context: Context, } @SuppressLint("SetTextI18n") - fun bindComment(comment: CommentEntity, - viewModel: BaseCommentViewModel, - entrance: String, - commentClosure: ((CommentEntity) -> Unit)? = null, deleteCallBack: ((comment: CommentEntity) -> Unit)? = null) { + fun bindComment( + comment: CommentEntity, + viewModel: BaseCommentViewModel, + entrance: String, + commentClosure: ((CommentEntity) -> Unit)? = null, + deleteCallBack: ((comment: CommentEntity) -> Unit)? = null + ) { bindComment(binding, viewModel, comment, entrance, deleteCallBack) if (type == AdapterType.COMMENT) { // 帖子详情页面用的样式 @@ -267,32 +323,80 @@ abstract class BaseCommentAdapter(context: Context, binding.root.setOnClickListener { when { viewModel.articleId.isNotEmpty() -> { - CommentActivity.getArticleCommentIntent(binding.root.context, viewModel.articleId, viewModel.commentCount, true, viewModel.communityId, comment, true).apply { - (binding.root.context as AppCompatActivity).startActivityForResult(this, CommentActivity.REQUEST_CODE) + CommentActivity.getArticleCommentIntent( + binding.root.context, + viewModel.articleId, + viewModel.commentCount, + true, + viewModel.communityId, + comment, + true + ).apply { + (binding.root.context as AppCompatActivity).startActivityForResult( + this, + CommentActivity.REQUEST_CODE + ) } MtaHelper.onEvent("帖子详情", "全部评论", "评论正文") } viewModel.videoId.isNotEmpty() -> { - CommentActivity.getVideoCommentReplyIntent(binding.root.context, viewModel.videoId, viewModel.commentCount, comment.me?.isContentOwner == true, true, true, comment).apply { - (binding.root.context as AppCompatActivity).startActivityForResult(this, CommentActivity.REQUEST_CODE) + CommentActivity.getVideoCommentReplyIntent( + binding.root.context, + viewModel.videoId, + viewModel.commentCount, + comment.me?.isContentOwner == true, + true, + true, + comment + ).apply { + (binding.root.context as AppCompatActivity).startActivityForResult( + this, + CommentActivity.REQUEST_CODE + ) } } viewModel.questionId.isNotEmpty() -> { - CommentActivity.getQuestionCommentReplyIntent(binding.root.context, viewModel.questionId, viewModel.communityId, viewModel.commentCount, true, true, comment).apply { - (binding.root.context as AppCompatActivity).startActivityForResult(this, CommentActivity.REQUEST_CODE) + CommentActivity.getQuestionCommentReplyIntent( + binding.root.context, + viewModel.questionId, + viewModel.communityId, + viewModel.commentCount, + true, + true, + comment + ).apply { + (binding.root.context as AppCompatActivity).startActivityForResult( + this, + CommentActivity.REQUEST_CODE + ) } } } - NewLogUtils.logCommentClick("click_comment_area_comment", - comment.user.id ?: "", contentType, comment.id ?: "", bbsId, bbsType) + NewLogUtils.logCommentClick( + "click_comment_area_comment", + comment.user.id ?: "", contentType, comment.id ?: "", bbsId, bbsType + ) } binding.commentCountTv.setOnClickListener { - CommentActivity.getCommentDetailIntent(binding.root.context, comment.id!!, viewModel.communityId, viewModel.articleId, viewModel.videoId, viewModel.questionId, false, comment.floor, entrance, PATH_ARTICLE_DETAIL).apply { + CommentActivity.getCommentDetailIntent( + binding.root.context, + comment.id!!, + viewModel.communityId, + viewModel.articleId, + viewModel.videoId, + viewModel.questionId, + false, + comment.floor, + entrance, + PATH_ARTICLE_DETAIL + ).apply { binding.root.context.startActivity(this) } MtaHelper.onEvent("帖子详情", "全部评论", "回复") - NewLogUtils.logCommentClick("click_comment_area_reply", - comment.user.id ?: "", contentType, comment.id ?: "", bbsId, bbsType) + NewLogUtils.logCommentClick( + "click_comment_area_reply", + comment.user.id ?: "", contentType, comment.id ?: "", bbsId, bbsType + ) } binding.contentTv.text = comment.content binding.commentCountTv.text = viewModel.getCommentText(comment.reply, "回复") @@ -310,14 +414,30 @@ abstract class BaseCommentAdapter(context: Context, val colon = " :" val parentUserName = " ${comment.parentUser?.name} " - val prefixSpan = SpanBuilder(prefix).color(binding.root.context, 0, prefix.length, R.color.text_999999).build() + val prefixSpan = SpanBuilder(prefix).color( + binding.root.context, + 0, + prefix.length, + R.color.text_999999 + ).build() val parentUserNameSpan = SpanBuilder(parentUserName) - .bold(0, parentUserName.length) - .click(0, parentUserName.length, R.color.text_666666) { - DirectUtils.directToHomeActivity(binding.root.context, comment.user.id, 1, entrance, PATH_ARTICLE_DETAIL_COMMENT) - MtaHelper.onEvent("帖子详情", "引用回复区域", "用户名字") - }.build() - val colonSpan = SpanBuilder(colon).color(binding.root.context, 0, colon.length, R.color.text_999999).build() + .bold(0, parentUserName.length) + .click(0, parentUserName.length, R.color.text_666666) { + DirectUtils.directToHomeActivity( + binding.root.context, + comment.user.id, + 1, + entrance, + PATH_ARTICLE_DETAIL_COMMENT + ) + MtaHelper.onEvent("帖子详情", "引用回复区域", "用户名字") + }.build() + val colonSpan = SpanBuilder(colon).color( + binding.root.context, + 0, + colon.length, + R.color.text_999999 + ).build() val authorSpan = if (comment.parentUser?.me?.isCommentOwner == true) { SpanBuilder("作者").image(0, "作者".length, R.drawable.ic_hint_author).build() } else { @@ -325,11 +445,11 @@ abstract class BaseCommentAdapter(context: Context, } binding.contentTv.text = SpannableStringBuilder() - .append(prefixSpan) - .append(parentUserNameSpan) - .append(authorSpan) - .append(colonSpan) - .append(comment.content) + .append(prefixSpan) + .append(parentUserNameSpan) + .append(authorSpan) + .append(colonSpan) + .append(comment.content) } else { binding.contentTv.text = comment.content } @@ -338,7 +458,11 @@ abstract class BaseCommentAdapter(context: Context, } @SuppressLint("SetTextI18n") - fun updateSubComment(comment: CommentEntity, viewModel: BaseCommentViewModel, entrance: String) { + fun updateSubComment( + comment: CommentEntity, + viewModel: BaseCommentViewModel, + entrance: String + ) { val subCommentList = comment.subCommentList val ownerUserId = when { viewModel.articleId.isNotEmpty() -> { @@ -359,60 +483,132 @@ abstract class BaseCommentAdapter(context: Context, binding.subCommentContainer.setRoundedColorBackground(R.color.text_F5F5F5, 5F) subCommentList?.firstOrNull()?.let { - binding.firstSubCommentTv.text = getSubCommentSpanned(it.user.name, if (it.user.id == ownerUserId) "作者" else "", it.content) + binding.firstSubCommentTv.text = getSubCommentSpanned( + it.user.name, + if (it.user.id == ownerUserId) "作者" else "", + it.content + ) } subCommentList?.secondOrNull()?.let { - binding.secondSubCommentTv.text = getSubCommentSpanned(it.user.name, if (it.user.id == ownerUserId) "作者" else "", it.content) + binding.secondSubCommentTv.text = getSubCommentSpanned( + it.user.name, + if (it.user.id == ownerUserId) "作者" else "", + it.content + ) } binding.subCommentContainer.setOnClickListener { - CommentActivity.getCommentDetailIntent(binding.root.context, comment.id!!, viewModel.communityId, viewModel.articleId, viewModel.videoId, viewModel.questionId, false, comment.floor, entrance, PATH_ARTICLE_DETAIL).apply { + CommentActivity.getCommentDetailIntent( + binding.root.context, + comment.id!!, + viewModel.communityId, + viewModel.articleId, + viewModel.videoId, + viewModel.questionId, + false, + comment.floor, + entrance, + PATH_ARTICLE_DETAIL + ).apply { binding.root.context.startActivity(this) } } } - private fun getSubCommentSpanned(name: String?, author: String?, content: String?): SpannableStringBuilder { + private fun getSubCommentSpanned( + name: String?, + author: String?, + content: String? + ): SpannableStringBuilder { val finalAuthor = author ?: "" val finalName = "$name " val colon = " :" - val nameSpan = SpanBuilder(finalName).color(0, finalName.length, R.color.theme_font).build() - val authorSpan = if (finalAuthor.isNotEmpty()) SpanBuilder(finalAuthor).image(0, finalAuthor.length, R.drawable.ic_hint_author).build() else "" + val nameSpan = + SpanBuilder(finalName).color(0, finalName.length, R.color.theme_font).build() + val authorSpan = if (finalAuthor.isNotEmpty()) SpanBuilder(finalAuthor).image( + 0, + finalAuthor.length, + R.drawable.ic_hint_author + ).build() else "" val colonSpan = SpanBuilder(colon).color(0, colon.length, R.color.theme_font).build() - return SpannableStringBuilder().append(nameSpan).append(authorSpan).append(colonSpan).append(content) + return SpannableStringBuilder().append(nameSpan).append(authorSpan).append(colonSpan) + .append(content) } companion object { - fun bindComment(binding: ItemArticleDetailCommentBinding, - viewModel: BaseCommentViewModel, - comment: CommentEntity, - entrance: String, deleteCallBack: ((comment: CommentEntity) -> Unit)? = null) { - val path = if (viewModel is ArticleDetailViewModel) PATH_ARTICLE_DETAIL else PATH_ARTICLE_DETAIL_COMMENT + fun bindComment( + binding: ItemArticleDetailCommentBinding, + viewModel: BaseCommentViewModel, + comment: CommentEntity, + entrance: String, deleteCallBack: ((comment: CommentEntity) -> Unit)? = null + ) { + val path = when { + viewModel.articleId.isNotEmpty() -> { + if (viewModel is CommentConversationViewModel) PATH_ARTICLE_DETAIL_COMMENT else PATH_ARTICLE_DETAIL + } + viewModel.questionId.isNotEmpty() -> { + if (viewModel is CommentConversationViewModel) PATH_QUESTION_DETAIL_COMMENT else PATH_QUESTION_DETAIL + } + viewModel.videoId.isNotEmpty() -> { + if (viewModel is CommentConversationViewModel) PATH_VIDEO_DETAIL_COMMENT else PATH_VIDEO_DETAIL + } + else -> "" + } val mtaKey = if (viewModel is ArticleDetailViewModel) "全部评论" else "评论详情-全部回复" binding.comment = comment - binding.userIconIv.display(comment.user.border, comment.user.icon, comment.user.auth?.icon) + binding.userIconIv.display( + comment.user.border, + comment.user.icon, + comment.user.auth?.icon + ) binding.adoptionTv.goneIf(!comment.accept) val (bbsId, contentType, bbsType) = getLogData(viewModel) binding.userIconIv.setOnClickListener { MtaHelper.onEvent("帖子详情", mtaKey, "用户头像") - DirectUtils.directToHomeActivity(binding.root.context, comment.user.id, 1, entrance, path) - NewLogUtils.logCommentClick("click_comment_area_profile_photo", - comment.user.id ?: "", contentType, comment.id ?: "", bbsId, bbsType) + DirectUtils.directToHomeActivity( + binding.root.context, + comment.user.id, + 1, + entrance, + path + ) + NewLogUtils.logCommentClick( + "click_comment_area_profile_photo", + comment.user.id ?: "", contentType, comment.id ?: "", bbsId, bbsType + ) } binding.userNameTv.setOnClickListener { - DirectUtils.directToHomeActivity(binding.root.context, comment.user.id, 1, entrance, path) + DirectUtils.directToHomeActivity( + binding.root.context, + comment.user.id, + 1, + entrance, + path + ) MtaHelper.onEvent("帖子详情", mtaKey, "用户名字") - NewLogUtils.logCommentClick("click_comment_area_nickname", - comment.user.id ?: "", contentType, comment.id ?: "", bbsId, bbsType) + NewLogUtils.logCommentClick( + "click_comment_area_nickname", + comment.user.id ?: "", contentType, comment.id ?: "", bbsId, bbsType + ) } binding.likeCountTv.text = viewModel.getLikeText(comment.vote) if (comment.me?.isCommentVoted == true) { - binding.likeCountTv.setCompoundDrawablesWithIntrinsicBounds(R.drawable.comment_vote_select, 0, 0, 0) + binding.likeCountTv.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.comment_vote_select, + 0, + 0, + 0 + ) } else { - binding.likeCountTv.setCompoundDrawablesWithIntrinsicBounds(R.drawable.comment_vote_unselect, 0, 0, 0) + binding.likeCountTv.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.comment_vote_unselect, + 0, + 0, + 0 + ) } binding.likeCountTv.setDebouncedClickListener { @@ -425,9 +621,11 @@ abstract class BaseCommentAdapter(context: Context, } else { MtaHelper.onEvent("帖子详情", "评论详情-全部回复", "点赞") } - NewLogUtils.logCommentClick("click_comment_area_like", - comment.user.id ?: "", contentType, comment.id - ?: "", bbsId, bbsType) + NewLogUtils.logCommentClick( + "click_comment_area_like", + comment.user.id ?: "", contentType, comment.id + ?: "", bbsId, bbsType + ) } else { ToastUtils.showToast("已点过赞了") } @@ -436,9 +634,18 @@ abstract class BaseCommentAdapter(context: Context, binding.badgeTv.setOnClickListener { DialogUtils.showViewBadgeDialog(binding.root.context, comment.user.badge) { - MtaHelper.onEvent("进入徽章墙_用户记录", "帖子详情-评论管理", comment.user.name + "(" + comment.user.id + ")") + MtaHelper.onEvent( + "进入徽章墙_用户记录", + "帖子详情-评论管理", + comment.user.name + "(" + comment.user.id + ")" + ) MtaHelper.onEvent("徽章中心", "进入徽章中心", "帖子详情-评论管理") - DirectUtils.directToBadgeWall(binding.root.context, comment.user.id, comment.user.name, comment.user.icon) + DirectUtils.directToBadgeWall( + binding.root.context, + comment.user.id, + comment.user.name, + comment.user.icon + ) } } binding.badgeIv.setOnClickListener { binding.badgeTv.performClick() } @@ -446,13 +653,34 @@ abstract class BaseCommentAdapter(context: Context, binding.moreIv.setOnClickListener { when { viewModel.articleId.isNotEmpty() -> { - showCommunityArticleCommentOptions(it, binding, comment, viewModel, path, deleteCallBack) + showCommunityArticleCommentOptions( + it, + binding, + comment, + viewModel, + path, + deleteCallBack + ) } viewModel.videoId.isNotEmpty() -> { - showVideoCommentOptions(it, binding, comment, viewModel, deleteCallBack) + showVideoCommentOptions( + it, + binding, + comment, + viewModel, + path, + deleteCallBack + ) } viewModel.questionId.isNotEmpty() -> { - showQuestionCommentOption(it, binding, comment, viewModel, deleteCallBack) + showQuestionCommentOption( + it, + binding, + comment, + viewModel, + path, + deleteCallBack + ) } } NewLogUtils.logCommentClick("click_comment_area_more") @@ -476,106 +704,234 @@ abstract class BaseCommentAdapter(context: Context, type = (viewModel as? VideoCommentViewModel)?.videoDetail?.type ?: "" } } - val contentType = if (viewModel.articleId.isNotEmpty()) "帖子评论" else if (viewModel.questionId.isNotEmpty()) "提问帖评论" else "视频帖评论" + val contentType = + if (viewModel.articleId.isNotEmpty()) "帖子评论" else if (viewModel.questionId.isNotEmpty()) "提问帖评论" else "视频帖评论" val bbsType = if (type == "game_bbs") "游戏论坛" else "综合论坛" return Triple(bbsId, contentType, bbsType) } - private fun showQuestionCommentOption(view: View, binding: ItemArticleDetailCommentBinding, comment: CommentEntity, viewModel: BaseCommentViewModel, deleteCallBack: ((comment: CommentEntity) -> Unit)?) { - CommentHelper.showQuestionCommentOption(view, comment, viewModel.questionId, object : OnCommentOptionClickListener { - override fun onCommentOptionClick(entity: CommentEntity, option: String) { - when (option) { - "删除评论" -> { - DialogUtils.showNewAlertDialog(binding.moreIv.context, "提示", "删除评论后,评论下所有的回复都将被删除", "取消", "删除", null, { - viewModel.deleteComment(comment) { - deleteCallBack?.invoke(comment) - } - }) - } - "采纳" -> { - DialogUtils.showNewAlertDialog(binding.root.context, "提示", "确定采纳该评论?", "取消", "确认", null, Gravity.CENTER, false, {}, { - viewModel.acceptQuestionComment(viewModel.questionId, comment) - }) - } - "加精选" -> { - viewModel.highlightQuestionComment(comment) - } - "置顶" -> { - DialogUtils.showNewAlertDialog(binding.root.context, "提示", "是否将此条评论置顶?", "取消", "确认", null, Gravity.CENTER, false, {}, { - commentTop(binding.root.context, viewModel, comment, false) - }) - } - "取消置顶" -> { - DialogUtils.showNewAlertDialog(binding.root.context, "提示", "是否将此条评论取消置顶?", "取消", "确认", null, Gravity.CENTER, false, {}, { - viewModel.updateCommentTop(comment.id - ?: "", top = false, isAgain = false) { isSuccess, errorCode -> - if (isSuccess) { - viewModel.load(LoadType.REFRESH) - } - } - }) - } - } - } - }) - } - - private fun showVideoCommentOptions(view: View, binding: ItemArticleDetailCommentBinding, comment: CommentEntity, viewModel: BaseCommentViewModel, deleteCallBack: ((comment: CommentEntity) -> Unit)?) { - CommentHelper.showVideoCommentOptions(view, comment, false, viewModel.videoId, - comment.me?.isContentOwner == true, object : OnCommentOptionClickListener { - override fun onCommentOptionClick(entity: CommentEntity, option: String) { - when (option) { - "删除评论" -> { - DialogUtils.showNewAlertDialog(binding.moreIv.context, "提示", "删除评论后,评论下所有的回复都将被删除", "取消", "删除", null, { - viewModel.deleteComment(comment) { - deleteCallBack?.invoke(comment) - } - }) - } - } - } - }) - } - - private fun showCommunityArticleCommentOptions(view: View, binding: ItemArticleDetailCommentBinding, comment: CommentEntity, viewModel: BaseCommentViewModel, path: String, deleteCallBack: ((comment: CommentEntity) -> Unit)?) { - CommentHelper.showCommunityArticleCommentOptions( - view, - comment, - false, - viewModel.articleId, - viewModel.communityId, - isShowTop = path == PATH_ARTICLE_DETAIL, - ignoreModerator = true, - listener = object : OnCommentOptionClickListener { - override fun onCommentOptionClick(entity: CommentEntity, option: String) { - when (option) { - "删除评论" -> { - DialogUtils.showNewAlertDialog(binding.moreIv.context, "提示", "删除评论后,评论下所有的回复都将被删除", "取消", "删除", null, { + private fun showQuestionCommentOption( + view: View, + binding: ItemArticleDetailCommentBinding, + comment: CommentEntity, + viewModel: BaseCommentViewModel, + path: String, + deleteCallBack: ((comment: CommentEntity) -> Unit)? + ) { + CommentHelper.showQuestionCommentOption( + view, + comment, + viewModel.questionId, + path == PATH_QUESTION_DETAIL, + object : OnCommentOptionClickListener { + override fun onCommentOptionClick(entity: CommentEntity, option: String) { + when (option) { + "删除评论" -> { + DialogUtils.showNewAlertDialog( + binding.moreIv.context, + "提示", + "删除评论后,评论下所有的回复都将被删除", + "取消", + "删除", + null, + { viewModel.deleteComment(comment) { deleteCallBack?.invoke(comment) } }) - } - "置顶" -> { - DialogUtils.showNewAlertDialog(binding.root.context, "提示", "是否将此条评论置顶?", "取消", "确认", null, Gravity.CENTER, false, {}, { - commentTop(binding.root.context, viewModel, comment, false) + } + "采纳" -> { + DialogUtils.showNewAlertDialog( + binding.root.context, + "提示", + "确定采纳该评论?", + "取消", + "确认", + null, + Gravity.CENTER, + false, + {}, + { + viewModel.acceptQuestionComment( + viewModel.questionId, + comment, + true + ) }) - } - "取消置顶" -> { - DialogUtils.showNewAlertDialog(binding.root.context, "提示", "是否将此条评论取消置顶?", "取消", "确认", null, Gravity.CENTER, false, {}, { - viewModel.updateCommentTop(comment.id - ?: "", top = false, isAgain = false) { isSuccess, errorCode -> + } + "取消采纳" -> { + viewModel.acceptQuestionComment( + viewModel.questionId, + comment, + false + ) + } + "加精选" -> { + viewModel.highlightQuestionComment(comment) + } + "置顶" -> { + DialogUtils.showNewAlertDialog( + binding.root.context, + "提示", + "是否将此条评论置顶?", + "取消", + "确认", + null, + Gravity.CENTER, + false, + {}, + { + commentTop( + binding.root.context, + viewModel, + comment, + false + ) + }) + } + "取消置顶" -> { + DialogUtils.showNewAlertDialog( + binding.root.context, + "提示", + "是否将此条评论取消置顶?", + "取消", + "确认", + null, + Gravity.CENTER, + false, + {}, + { + viewModel.updateCommentTop( + comment.id + ?: "", top = false, isAgain = false + ) { isSuccess, errorCode -> if (isSuccess) { viewModel.load(LoadType.REFRESH) } } }) - } } + } + } + }) + } + private fun showVideoCommentOptions( + view: View, + binding: ItemArticleDetailCommentBinding, + comment: CommentEntity, + viewModel: BaseCommentViewModel, + path: String, + deleteCallBack: ((comment: CommentEntity) -> Unit)? + ) { + CommentHelper.showVideoCommentOptions(view, + comment, + false, + viewModel.videoId, + comment.me?.isContentOwner == true, + path == PATH_VIDEO_DETAIL, + object : OnCommentOptionClickListener { + override fun onCommentOptionClick(entity: CommentEntity, option: String) { + when (option) { + "删除评论" -> { + DialogUtils.showNewAlertDialog( + binding.moreIv.context, + "提示", + "删除评论后,评论下所有的回复都将被删除", + "取消", + "删除", + null, + { + viewModel.deleteComment(comment) { + deleteCallBack?.invoke(comment) + } + }) + } + } + } + }) + } + + private fun showCommunityArticleCommentOptions( + view: View, + binding: ItemArticleDetailCommentBinding, + comment: CommentEntity, + viewModel: BaseCommentViewModel, + path: String, + deleteCallBack: ((comment: CommentEntity) -> Unit)? + ) { + CommentHelper.showCommunityArticleCommentOptions( + view, + comment, + false, + viewModel.articleId, + viewModel.communityId, + isShowTop = path == PATH_ARTICLE_DETAIL, + ignoreModerator = true, + listener = object : OnCommentOptionClickListener { + override fun onCommentOptionClick(entity: CommentEntity, option: String) { + when (option) { + "删除评论" -> { + DialogUtils.showNewAlertDialog( + binding.moreIv.context, + "提示", + "删除评论后,评论下所有的回复都将被删除", + "取消", + "删除", + null, + { + viewModel.deleteComment(comment) { + deleteCallBack?.invoke(comment) + } + }) + } + "置顶" -> { + DialogUtils.showNewAlertDialog( + binding.root.context, + "提示", + "是否将此条评论置顶?", + "取消", + "确认", + null, + Gravity.CENTER, + false, + {}, + { + commentTop( + binding.root.context, + viewModel, + comment, + false + ) + }) + } + "取消置顶" -> { + DialogUtils.showNewAlertDialog( + binding.root.context, + "提示", + "是否将此条评论取消置顶?", + "取消", + "确认", + null, + Gravity.CENTER, + false, + {}, + { + viewModel.updateCommentTop( + comment.id + ?: "", top = false, isAgain = false + ) { isSuccess, errorCode -> + if (isSuccess) { + viewModel.load(LoadType.REFRESH) + } + } + }) + } } - }) + } + + }) if (viewModel is ArticleDetailViewModel) { MtaHelper.onEvent("帖子详情", "全部评论", "更多") @@ -584,16 +940,33 @@ abstract class BaseCommentAdapter(context: Context, } } - private fun commentTop(context: Context, viewModel: BaseCommentViewModel, comment: CommentEntity, isAgain: Boolean) { - viewModel.updateCommentTop(comment.id - ?: "", top = true, isAgain = isAgain) { isSuccess, errorCode -> + private fun commentTop( + context: Context, + viewModel: BaseCommentViewModel, + comment: CommentEntity, + isAgain: Boolean + ) { + viewModel.updateCommentTop( + comment.id + ?: "", top = true, isAgain = isAgain + ) { isSuccess, errorCode -> if (isSuccess) { viewModel.load(LoadType.REFRESH) } else { if (errorCode == 403095) { - DialogUtils.showNewAlertDialog(context, "提示", "当前已有置顶评论,\n是否将此条评论覆盖展示?", "取消", "确认", null, Gravity.CENTER, false, {}, { - commentTop(context, viewModel, comment, true) - }) + DialogUtils.showNewAlertDialog( + context, + "提示", + "当前已有置顶评论,\n是否将此条评论覆盖展示?", + "取消", + "确认", + null, + Gravity.CENTER, + false, + {}, + { + commentTop(context, viewModel, comment, true) + }) } } } @@ -612,6 +985,12 @@ abstract class BaseCommentAdapter(context: Context, const val PATH_ARTICLE_DETAIL = "帖子详情" const val PATH_ARTICLE_DETAIL_COMMENT = "帖子评论详情" + + const val PATH_QUESTION_DETAIL = "问题详情" + const val PATH_QUESTION_DETAIL_COMMENT = "问题评论详情" + + const val PATH_VIDEO_DETAIL = "视频详情" + const val PATH_VIDEO_DETAIL_COMMENT = "视频评论详情" } enum class AdapterType { diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentViewModel.kt index c89da3ade4..a50560f7eb 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentViewModel.kt @@ -26,8 +26,13 @@ import okhttp3.ResponseBody import org.json.JSONObject import retrofit2.HttpException -abstract class BaseCommentViewModel(application: Application, var articleId: String, var videoId: String, var questionId: String, var communityId: String) - : ListViewModel(application) { +abstract class BaseCommentViewModel( + application: Application, + var articleId: String, + var videoId: String, + var questionId: String, + var communityId: String +) : ListViewModel(application) { protected val mApi: ApiService = RetrofitManager.getInstance(application).api var currentSortType: SortType = SortType.OLDEST @@ -77,7 +82,11 @@ abstract class BaseCommentViewModel(application: Application, var articleId: Str } } - fun mergeListData(commentList: List?, displayFloor: Boolean = false, hasFilter: Boolean = true) { + fun mergeListData( + commentList: List?, + displayFloor: Boolean = false, + hasFilter: Boolean = true + ) { topItemData?.let { val mergedList = arrayListOf().apply { if (hasFilter) { @@ -132,52 +141,72 @@ abstract class BaseCommentViewModel(application: Application, var articleId: Str } fun like(comment: CommentEntity) { - PostCommentUtils.likeComment(getApplication(), null, articleId, communityId, videoId, questionId, comment.id, - object : PostCommentUtils.PostCommentListener { - override fun postSuccess(response: JSONObject?) { - val cloneComment = comment.clone() - if (cloneComment.me == null) { - cloneComment.me = MeEntity() - } - cloneComment.me?.isCommentVoted = true - cloneComment.vote++ - updateComment(cloneComment) - - comment.id?.let { - SyncPageRepository.postSyncData(SyncDataEntity(it, - SyncFieldConstants.ARTICLE_COMMENT_VOTE_COUNT, - comment.vote + 1)) - SyncPageRepository.postSyncData(SyncDataEntity(it, - SyncFieldConstants.ARTICLE_COMMENT_VOTE, - true, - checkFieldEntity = true)) - } + PostCommentUtils.likeComment(getApplication(), + null, + articleId, + communityId, + videoId, + questionId, + comment.id, + object : PostCommentUtils.PostCommentListener { + override fun postSuccess(response: JSONObject?) { + val cloneComment = comment.clone() + if (cloneComment.me == null) { + cloneComment.me = MeEntity() } + cloneComment.me?.isCommentVoted = true + cloneComment.vote++ + updateComment(cloneComment) - override fun postFailed(e: Throwable) { - if (e is HttpException) { - if (e.code() == 403) { - try { - val detail = JSONObject(e.response().errorBody()!!.string()).getString("detail") - if ("voted" == detail) { - ToastUtils.showToast("已经点过赞啦!") - } - } catch (ex: Exception) { - ex.printStackTrace() + comment.id?.let { + SyncPageRepository.postSyncData( + SyncDataEntity( + it, + SyncFieldConstants.ARTICLE_COMMENT_VOTE_COUNT, + comment.vote + 1 + ) + ) + SyncPageRepository.postSyncData( + SyncDataEntity( + it, + SyncFieldConstants.ARTICLE_COMMENT_VOTE, + true, + checkFieldEntity = true + ) + ) + } + } + + override fun postFailed(e: Throwable) { + if (e is HttpException) { + if (e.code() == 403) { + try { + val detail = JSONObject( + e.response().errorBody()!!.string() + ).getString("detail") + if ("voted" == detail) { + ToastUtils.showToast("已经点过赞啦!") } - return + } catch (ex: Exception) { + ex.printStackTrace() } + return } - Utils.toast(getApplication(), "网络异常,点赞失败") } - }) + Utils.toast(getApplication(), "网络异常,点赞失败") + } + }) } @SuppressLint("CheckResult") fun deleteComment(entity: CommentEntity, callback: () -> Unit) { val observable = when { videoId.isNotEmpty() -> { - mApi.deleteVideoComment(videoId, entity.id).toObservable() + if (entity.me?.isModerator == true) { + mApi.moderatorsHideVideoComment(communityId, videoId, entity.id).toObservable() + } else { + mApi.deleteVideoComment(videoId, entity.id).toObservable() + } } questionId.isNotEmpty() -> { mApi.deleteQuestionComment(questionId, entity.id).toObservable() @@ -188,32 +217,37 @@ abstract class BaseCommentViewModel(application: Application, var articleId: Str else -> null } ?: return observable.compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - hideCommentSuccess() - callback.invoke() - } + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + hideCommentSuccess() + callback.invoke() + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - e?.let { httpException -> - if (httpException.code() == 403) { - val string = e.response().errorBody()?.string() ?: "" - val errorJson = JSONObject(string) - val errorCode = errorJson.getInt("code") - if (errorCode == 403059) { - Utils.toast(getApplication(), "权限错误,请刷新后重试") - return - } else { - Utils.toast(getApplication(), e.message()) - } + override fun onFailure(e: HttpException?) { + super.onFailure(e) + e?.let { httpException -> + if (httpException.code() == 403) { + val string = e.response().errorBody()?.string() ?: "" + val errorJson = JSONObject(string) + val errorCode = errorJson.getInt("code") + if (errorCode == 403059) { + Utils.toast(getApplication(), "权限错误,请刷新后重试") + return + } else { + Utils.toast(getApplication(), e.message()) } } } - }) + } + }) } - fun updateCommentTop(commentId: String, top: Boolean = false, isAgain: Boolean = false, callback: (isSuccess: Boolean, errorCode: Int) -> Unit) { + fun updateCommentTop( + commentId: String, + top: Boolean = false, + isAgain: Boolean = false, + callback: (isSuccess: Boolean, errorCode: Int) -> Unit + ) { val observable = if (top) { val map = hashMapOf() if (isAgain) { @@ -241,62 +275,67 @@ abstract class BaseCommentViewModel(application: Application, var articleId: Str } ?: return observable.subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - callback.invoke(true, 0) - } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + callback.invoke(true, 0) + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - e?.let { - ErrorHelper.handleErrorWithCustomizedHandler(getApplication(), e.response()?.errorBody()?.string(), false) { - if (it == 403095) { - callback.invoke(false, it) - true - } else false - } + override fun onFailure(e: HttpException?) { + super.onFailure(e) + e?.let { + ErrorHelper.handleErrorWithCustomizedHandler( + getApplication(), + e.response()?.errorBody()?.string(), + false + ) { + if (it == 403095) { + callback.invoke(false, it) + true + } else false } } - }) + } + }) } - fun acceptQuestionComment(questionId: String, comment: CommentEntity) { - val body = json { "accept" to true }.toRequestBody() + fun acceptQuestionComment(questionId: String, comment: CommentEntity, accept: Boolean) { + val body = json { "accept" to accept }.toRequestBody() mApi.acceptQuestionComment(questionId, comment.id, body) - .compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - val cloneComment = comment.clone() - cloneComment.accept = true - updateComment(cloneComment) - } + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + val cloneComment = comment.clone() + cloneComment.accept = accept + updateComment(cloneComment) + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - ToastUtils.showToast("采纳失败") - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + ToastUtils.showToast("采纳失败") + } + }) } fun highlightQuestionComment(comment: CommentEntity) { mApi.highlightAnswer(comment.id) - .compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - val cloneComment = comment.clone() - cloneComment.choiceness = true - updateComment(cloneComment) - } + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + val cloneComment = comment.clone() + cloneComment.choiceness = true + updateComment(cloneComment) + ToastUtils.showToast("加精成功") + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - ToastUtils.showToast("加精选失败") - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + ToastUtils.showToast("加精选失败") + } + }) } private fun updateComment(cloneComment: CommentEntity) { diff --git a/app/src/main/java/com/gh/gamecenter/qa/dialog/ChooseForumContainerAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/dialog/ChooseForumContainerAdapter.kt index 80036718fb..4d084ebd1a 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/dialog/ChooseForumContainerAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/dialog/ChooseForumContainerAdapter.kt @@ -65,7 +65,7 @@ class ChooseForumContainerAdapter(content: Context, val type: String, val onSele val tabType = if (type == ChooseForumContainerFragment.ChooseForumType.SEARCH.value) "论坛tab" else "" val bbsType = if (forumEntity.type == "official_bbs") "综合论坛" else "游戏论坛" NewLogUtils.logForumSearchResultClick(tabType, forumEntity.id, bbsType, "", "", "", position + 1) - onSelectCallback?.invoke(CommunityEntity(forumEntity.id, HtmlUtils.stripHtml(forumEntity.name), + onSelectCallback?.invoke(CommunityEntity(forumEntity.id, HtmlUtils.stripHtml(forumEntity.name), type = forumEntity.type, game = forumEntity.game, icon = icon, iconSubscript = forumEntity.game.iconSubscript)) } } else if (holder is FooterViewHolder) { diff --git a/app/src/main/java/com/gh/gamecenter/qa/dialog/InputUrlDialogFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/dialog/InputUrlDialogFragment.kt index 27d070417c..09d81212cb 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/dialog/InputUrlDialogFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/dialog/InputUrlDialogFragment.kt @@ -58,7 +58,6 @@ class InputUrlDialogFragment : BaseDialogFragment() { createDialog.setCanceledOnTouchOutside(true) val window = createDialog.window window?.setGravity(Gravity.BOTTOM) - window?.setWindowAnimations(R.style.community_publication_animation) return createDialog } diff --git a/app/src/main/java/com/gh/gamecenter/qa/dialog/MoreFunctionPanelDialog.kt b/app/src/main/java/com/gh/gamecenter/qa/dialog/MoreFunctionPanelDialog.kt index e6cb002437..8297b968b5 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/dialog/MoreFunctionPanelDialog.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/dialog/MoreFunctionPanelDialog.kt @@ -27,9 +27,9 @@ class MoreFunctionPanelDialog : BaseDraggableDialogFragment() { var onItemClickCallback: ((menuItem: MenuItemEntity) -> Unit)? = null override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? ): View { binding = DialogGameDetailMoreBinding.inflate(inflater, container, false) return binding.root @@ -82,25 +82,40 @@ class MoreFunctionPanelDialog : BaseDraggableDialogFragment() { menuItems.forEachIndexed { _, menuItemEntity -> val itemView = createItemView(menuItemEntity) itemView.setOnClickListener { - onItemClickCallback?.invoke(menuItemEntity) - dismissAllowingStateLoss() + if (menuItemEntity.isEnable) { + onItemClickCallback?.invoke(menuItemEntity) + dismissAllowingStateLoss() + } } binding.actionContainer.addView(itemView) } } private fun createItemView(itemEntity: MenuItemEntity): View { - val params = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT) + val params = LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ) params.leftMargin = 16F.dip2px() return TextView(requireContext()).apply { textSize = 11F text = itemEntity.text - setTextColor(ContextCompat.getColor(requireContext(), if (itemEntity.isEnable) R.color.text_666666 else R.color.text_999999)) + setTextColor( + ContextCompat.getColor( + requireContext(), + if (itemEntity.isEnable) R.color.text_666666 else R.color.text_999999 + ) + ) includeFontPadding = false gravity = Gravity.CENTER layoutParams = params compoundDrawablePadding = 8F.dip2px() - setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(requireContext(), itemEntity.normalIcon), null, null) + setCompoundDrawablesWithIntrinsicBounds( + null, + ContextCompat.getDrawable(requireContext(), itemEntity.normalIcon), + null, + null + ) } } @@ -109,22 +124,33 @@ class MoreFunctionPanelDialog : BaseDraggableDialogFragment() { companion object { @JvmStatic - fun showMoreDialog(activity: AppCompatActivity, menuItems: ArrayList, title: String, shareUtils: ShareUtils, onItemClickCallback: (menuItem: MenuItemEntity) -> Unit) { + fun showMoreDialog( + activity: AppCompatActivity, + menuItems: ArrayList, + title: String, + shareUtils: ShareUtils, + onItemClickCallback: (menuItem: MenuItemEntity) -> Unit + ) { if (menuItems.isNullOrEmpty()) return - var fragment = activity.supportFragmentManager.findFragmentByTag(MoreFunctionPanelDialog::class.java.name) as? MoreFunctionPanelDialog + var fragment = + activity.supportFragmentManager.findFragmentByTag(MoreFunctionPanelDialog::class.java.name) as? MoreFunctionPanelDialog if (fragment == null) { fragment = MoreFunctionPanelDialog() fragment.menuItems = menuItems fragment.title = title fragment.shareUtils = shareUtils fragment.onItemClickCallback = onItemClickCallback - fragment.show(activity.supportFragmentManager, MoreFunctionPanelDialog::class.java.name) + fragment.show( + activity.supportFragmentManager, + MoreFunctionPanelDialog::class.java.name + ) } else { fragment.menuItems = menuItems fragment.title = title fragment.shareUtils = shareUtils fragment.onItemClickCallback = onItemClickCallback - val transaction: FragmentTransaction = activity.supportFragmentManager.beginTransaction() + val transaction: FragmentTransaction = + activity.supportFragmentManager.beginTransaction() transaction.show(fragment) transaction.commit() } diff --git a/app/src/main/java/com/gh/gamecenter/qa/editor/OnLinkClickListener.kt b/app/src/main/java/com/gh/gamecenter/qa/editor/OnLinkClickListener.kt index f63dd5fdf4..ef565f6dff 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/editor/OnLinkClickListener.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/editor/OnLinkClickListener.kt @@ -62,22 +62,8 @@ class OnLinkClickListener(val context: Context, tryWithDefaultCatch { if (mtaEvent != null) MtaHelper.onEvent(mtaEvent.name, mtaEvent.key, mtaEvent.value) val videoEntity = GsonUtils.fromJson(content, MyVideoEntity::class.java) - when (videoEntity.status) { - "pass" -> { -// DirectUtils.directToVideoDetail(context, -// videoEntity.id, -// VideoDetailContainerViewModel.Location.VIDEO_HOT.value, -// showComment = false, -// entrance = entrance, -// path = "$path-视频") - FullScreenVideoActivity.start(context, title, videoEntity.url, videoEntity.poster) - } - "fail" -> { - Utils.toast(context, "视频审核未通过") - } - "pending" -> { - Utils.toast(context, "视频正在审核中") - } + clickToastByStatus(videoEntity.status){ + FullScreenVideoActivity.start(context, title, videoEntity.url, videoEntity.poster) } } } @@ -85,11 +71,8 @@ class OnLinkClickListener(val context: Context, @JavascriptInterface fun onVideoClick(url: String, poster: String) { - when (status) { - "pending" -> ToastUtils.showToast("内容审核中") - "fail" -> ToastUtils.showToast("内容审核不通过") - else -> FullScreenVideoActivity.start(context, title, url, poster) + clickToastByStatus(status){ + FullScreenVideoActivity.start(context, title, url, poster) } - } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/entity/ArticleDetailEntity.kt b/app/src/main/java/com/gh/gamecenter/qa/entity/ArticleDetailEntity.kt index 8be50ead4b..374732bdd0 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/entity/ArticleDetailEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/entity/ArticleDetailEntity.kt @@ -10,35 +10,45 @@ import kotlinx.android.parcel.Parcelize @Parcelize data class ArticleDetailEntity( - @SerializedName("_id") - val id: String = "", - var title: String = "", - var content: String = "", - var tags: List = ArrayList(), - val count: Count = Count(), - var user: UserEntity = UserEntity(), - var me: MeEntity = MeEntity(), - val time: TimeEntity = TimeEntity(), - var community: CommunityEntity = CommunityEntity(), - var commentable: Boolean? = true, - @SerializedName("is_jx") - var isHighlighted: Boolean = true, - @SerializedName("community_id") - var communityId: String = "", - var images: List = ArrayList(), - @SerializedName("images_info") - var imagesInfo: List = ArrayList(), - var videos: List = ArrayList(), - @SerializedName("tag_activity_id") - var tagActivityId: String = "", - @SerializedName("tag_activity_name") - var tagActivityName: String = "", - var type: String = "", - var gameEntity: GameEntity? = null, - @SerializedName("choiceness_status") - val choicenessStatus: String = "",// 精选状态 null, apply(申请), cancel(不予精选或未精选), pass(已精选) - var status: String = "pass",//pass通过,fail未通过,pending审核中 - var original: String = "" -) : Parcelable + @SerializedName("_id") + val id: String = "", + var title: String = "", + var content: String = "", + var tags: List = ArrayList(), + val count: Count = Count(), + var user: UserEntity = UserEntity(), + var me: MeEntity = MeEntity(), + val time: TimeEntity = TimeEntity(), + var community: CommunityEntity = CommunityEntity(), + var commentable: Boolean? = true, + @SerializedName("is_jx") + var isHighlighted: Boolean = true, + @SerializedName("community_id") + var communityId: String = "", + var images: List = ArrayList(), + @SerializedName("images_info") + var imagesInfo: List = ArrayList(), + var videos: List = ArrayList(), + @SerializedName("tag_activity_id") + var tagActivityId: String = "", + @SerializedName("tag_activity_name") + var tagActivityName: String = "", + var type: String = "", + @SerializedName("game") + var gameEntity: GameEntity? = null, + @SerializedName("choiceness_status") + var choicenessStatus: String = "",// 精选状态 apply(申请), pass already(已精选) cancel not_yet(未精选) + var status: String = "pass",//pass通过,fail未通过,pending审核中 + var original: String = "" +) : Parcelable { + + fun getSimplifyChoicenessStatus(): String { + return when (choicenessStatus) { + "already" -> "pass" + "not_yet" -> "cancel" + else -> choicenessStatus + } + } +} diff --git a/app/src/main/java/com/gh/gamecenter/qa/entity/QuestionsDetailEntity.kt b/app/src/main/java/com/gh/gamecenter/qa/entity/QuestionsDetailEntity.kt index 3033dceb1d..ecdd361cf7 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/entity/QuestionsDetailEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/entity/QuestionsDetailEntity.kt @@ -43,10 +43,10 @@ data class QuestionsDetailEntity( @SerializedName("tag_activity_name") var tagActivityName: String = "", var type: String = "", + @SerializedName("game") var gameEntity: GameEntity? = null, var time: TimeEntity = TimeEntity(), var count: Count = Count(), - val choicenessStatus: String = "",// 精选状态 null, apply(申请), cancel(不予精选或未精选), pass(已精选) var status: String = "pass",//pass通过,fail未通过,pending审核中 var finish: Boolean = false, //提交问题用 diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/detail/QuestionsDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/detail/QuestionsDetailFragment.kt index 3831831ec0..9ca00dd2ea 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/questions/detail/QuestionsDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/questions/detail/QuestionsDetailFragment.kt @@ -40,7 +40,7 @@ import com.gh.gamecenter.eventbus.EBDeleteDetail import com.gh.gamecenter.eventbus.EBReuse import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.mvvm.Status -import com.gh.gamecenter.personal.PersonalFragment.LOGIN_TAG +import com.gh.gamecenter.personal.PersonalFragment import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity import com.gh.gamecenter.qa.answer.edit.AnswerEditActivity import com.gh.gamecenter.qa.answer.fold.AnswerFoldActivity @@ -651,7 +651,7 @@ class QuestionsDetailFragment : // 登录事件 @Subscribe(threadMode = ThreadMode.MAIN) fun onEventMainThread(reuse: EBReuse) { - if (reuse.type == LOGIN_TAG) { // 登入 + if (reuse.type == PersonalFragment.LOGIN_TAG) { // 登入 onRefresh() } } diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditActivity.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditActivity.kt index 0718f5d519..ce0278aec5 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditActivity.kt @@ -48,7 +48,8 @@ import org.json.JSONObject /** * Created by khy on 28/04/18. */ -class QuestionEditActivity : BaseRichEditorActivity(), KeyboardHeightObserver { +class QuestionEditActivity : BaseRichEditorActivity(), + KeyboardHeightObserver { private lateinit var mBinding: ActivityQuestionsEditBinding @@ -74,14 +75,16 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke super.onActivityResult(requestCode, resultCode, data) if (data == null || resultCode != Activity.RESULT_OK) return if (requestCode == QUESTION_DRAFT_REQUEST_CODE) { - val draftEntity = data.getParcelableExtra(QuestionDraftEntity::class.java.simpleName) + val draftEntity = + data.getParcelableExtra(QuestionDraftEntity::class.java.simpleName) if (draftEntity != null) { mViewModel.questionDraftEntity = draftEntity setQuestionDraft(draftEntity) mViewModel.getQuestionDraftContent(draftEntity.id) } } else if (requestCode == ChooseForumActivity.CHOOSE_FORUM_REQUEST) { - val community = data.getParcelableExtra(EntranceUtils.KEY_COMMUNITY_DATA) + val community = + data.getParcelableExtra(EntranceUtils.KEY_COMMUNITY_DATA) mViewModel.communityEntity = community mViewModel.type = community?.type ?: "" if (mViewModel.questionEntity != null) { @@ -106,7 +109,8 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke super.handleMessage(msg) if (msg.what == 1) { if (!mViewModel.title.isNullOrEmpty() - && !mViewModel.content.isNullOrEmpty()) { + && !mViewModel.content.isNullOrEmpty() + ) { mViewModel.title = mBinding.questionseditTitle.text.toString() mViewModel.content = getReplaceRealContent() mViewModel.saveQuestionDraft(SaveDraftType.AUTO) @@ -148,7 +152,11 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke // TitleTip if (mViewModel.questionEntity == null) { - val titleTipAdapter = QuestionTitleTipAdapter(this, mBinding.questionseditTitle, mViewModel.communityEntity?.id) + val titleTipAdapter = QuestionTitleTipAdapter( + this, + mBinding.questionseditTitle, + mViewModel.communityEntity?.id + ) mBinding.questionseditTitle.setAdapter(titleTipAdapter) } @@ -179,11 +187,14 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke mBinding.questionseditTitle.requestFocus() mBinding.backBtn.setOnClickListener { - val bbsType = if (mViewModel.type.isNotEmpty()) if (mViewModel.type == "game_bbs") "游戏论坛" else "综合论坛" else "" - NewLogUtils.logQuestionEditClick("click_question_cancel", mViewModel.communityEntity?.id + val bbsType = + if (mViewModel.type.isNotEmpty()) if (mViewModel.type == "game_bbs") "游戏论坛" else "综合论坛" else "" + NewLogUtils.logQuestionEditClick( + "click_question_cancel", mViewModel.communityEntity?.id ?: "", - bbsType, mViewModel.selectActivityLabelEntity?.name - ?: "", mViewModel.quoteCountEntity) + bbsType, mViewModel.selectActivityLabelEntity?.name + ?: "", mViewModel.quoteCountEntity + ) onBackPressed() } mBinding.chooseForumTv.setOnClickListener { @@ -195,8 +206,10 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke 200L } else 0L AppExecutor.uiExecutor.executeWithDelay(Runnable { - ChooseActivityDialogFragment.show(this, ChooseActivityDialogFragment.ActivityLabelLocation.BBS_QUESTION, - mViewModel.selectActivityLabelEntity?.id) { + ChooseActivityDialogFragment.show( + this, ChooseActivityDialogFragment.ActivityLabelLocation.BBS_QUESTION, + mViewModel.selectActivityLabelEntity?.id + ) { mViewModel.selectActivityLabelEntity = it mBinding.activityTitle.text = it?.name mBinding.activityTitle.setTextColor(if (it != null) R.color.text_FA8500.toColor() else R.color.text_333333.toColor()) @@ -210,9 +223,12 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke }, 50) if (intent != null) { - val communityEntity = intent.getParcelableExtra(CommunityEntity::class.java.simpleName) - val detailEntity = intent.getParcelableExtra(QuestionsDetailEntity::class.java.simpleName) - val draftEntity = intent.getParcelableExtra(QuestionDraftEntity::class.java.simpleName) + val communityEntity = + intent.getParcelableExtra(CommunityEntity::class.java.simpleName) + val detailEntity = + intent.getParcelableExtra(QuestionsDetailEntity::class.java.simpleName) + val draftEntity = + intent.getParcelableExtra(QuestionDraftEntity::class.java.simpleName) when { detailEntity != null -> { // 问题编辑 setPatchContent(detailEntity) @@ -226,9 +242,11 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke else -> { // 新增问题 var searchKey = intent.getStringExtra(EntranceUtils.KEY_QUESTIONS_SEARCH_KEY) if (!searchKey.isNullOrEmpty() && searchKey.length > QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH) - searchKey = searchKey.substring(0, QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH) + searchKey = + searchKey.substring(0, QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH) if (mViewModel.title.isNullOrEmpty()) mViewModel.title = searchKey - mViewModel.isFromSearch = intent.getBooleanExtra(QuestionEditViewModel.QUESTION_FORM_SEARCH, false) + mViewModel.isFromSearch = + intent.getBooleanExtra(QuestionEditViewModel.QUESTION_FORM_SEARCH, false) mViewModel.type = intent?.getStringExtra(BbsType::class.java.simpleName) ?: "" mBaseHandler.sendEmptyMessageDelayed(1, SAVE_DRAFTS_INTERVAL_TIME.toLong()) if (communityEntity != null) { @@ -236,7 +254,12 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke setForumName() if (mViewModel.type == BbsType.GAME_BBS.value) { mBinding.chooseForumTv.isEnabled = false - mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null) + mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds( + null, + null, + null, + null + ) } } showUploadVideoGuide() @@ -261,13 +284,18 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke mViewModel.communityEntity?.iconSubscript = detailEntity.community.game?.iconSubscript mViewModel.gameEntity = detailEntity.gameEntity if (detailEntity.tagActivityId.isNotEmpty() && detailEntity.tagActivityName.isNotEmpty()) { - mViewModel.selectActivityLabelEntity = ActivityLabelEntity(detailEntity.tagActivityId, detailEntity.tagActivityName) + mViewModel.selectActivityLabelEntity = + ActivityLabelEntity(detailEntity.tagActivityId, detailEntity.tagActivityName) mBinding.activityTitle.text = detailEntity.tagActivityName mBinding.activityTitle.setTextColor(R.color.text_FA8500.toColor()) } + setForumName() mBinding.chooseActivityContainer.isEnabled = false + mBinding.chooseForumTv.isEnabled = false + mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null) - mViewModel.isModeratorPatch = intent.getBooleanExtra(EntranceUtils.KEY_QUESTION_MODERATOR_PATCH, false) + mViewModel.isModeratorPatch = + intent.getBooleanExtra(EntranceUtils.KEY_QUESTION_MODERATOR_PATCH, false) // 编辑问题时可能存在草稿 if (mViewModel.questionDraftEntity != null) { @@ -279,8 +307,6 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke mBinding.questionseditTitle.setText(detailEntity.title) setEditHtml(detailEntity.description) } - - setForumName() } private fun setQuestionDraft(draftEntity: QuestionDraftEntity) { @@ -289,7 +315,8 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke mViewModel.communityEntity?.iconSubscript = draftEntity.bbs?.game?.iconSubscript mViewModel.type = draftEntity.type if (draftEntity.tagActivityId.isNotEmpty() && draftEntity.tagActivityName.isNotEmpty()) { - mViewModel.selectActivityLabelEntity = ActivityLabelEntity(draftEntity.tagActivityId, draftEntity.tagActivityName) + mViewModel.selectActivityLabelEntity = + ActivityLabelEntity(draftEntity.tagActivityId, draftEntity.tagActivityName) mBinding.activityTitle.text = draftEntity.tagActivityName mBinding.activityTitle.setTextColor(R.color.text_FA8500.toColor()) } @@ -309,7 +336,10 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke } else { toast("操作成功") val data = Intent() - data.putExtra(QuestionsDetailEntity::class.java.simpleName, mViewModel.questionEntity) + data.putExtra( + QuestionsDetailEntity::class.java.simpleName, + mViewModel.questionEntity + ) setResult(Activity.RESULT_OK, data) } finish() @@ -323,11 +353,13 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke val errorJson = JSONObject(string) val errorCode = errorJson.getInt("code") if (errorCode == 403059) { - DialogUtils.showAlertDialog(this, "提交失败", "权限错误,请刷新后重试", - "确定", null, DialogUtils.ConfirmListener { - setResult(Activity.RESULT_CANCELED) - finish() - }, null) + DialogUtils.showAlertDialog( + this, "提交失败", "权限错误,请刷新后重试", + "确定", null, DialogUtils.ConfirmListener { + setResult(Activity.RESULT_CANCELED) + finish() + }, null + ) return@Observer } } @@ -341,7 +373,10 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke if (pair.second) { if (mViewModel.questionDraftEntity != null) { val intent = Intent() - intent.putExtra(QuestionDraftEntity::class.java.simpleName, mViewModel.questionDraftEntity) + intent.putExtra( + QuestionDraftEntity::class.java.simpleName, + mViewModel.questionDraftEntity + ) setResult(Activity.RESULT_OK, intent) if (mViewModel.checkIsAllUploadedAndToast()) { Utils.toast(this, "已保存!") @@ -351,7 +386,8 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke Utils.toast(this, "问题已保存到草稿箱") } } - EventBus.getDefault().post(EBReuse(ArticleEditActivity.ARTICLE_DRAFT_CHANGE_TAG)) + EventBus.getDefault() + .post(EBReuse(ArticleEditActivity.ARTICLE_DRAFT_CHANGE_TAG)) finish() } } @@ -368,7 +404,10 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke SaveDraftType.SKIP -> { if (pair.second) { Utils.toast(this, "问题已保存到草稿箱") - startActivityForResult(ArticleDraftActivity.getIntent(this), ArticleEditActivity.ARTICLE_DRAFT_REQUEST_CODE) + startActivityForResult( + ArticleDraftActivity.getIntent(this), + ArticleEditActivity.ARTICLE_DRAFT_REQUEST_CODE + ) } else { Utils.toast(this, "问题草稿保存失败") } @@ -392,13 +431,19 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke mProcessingDialog = WaitingDialogFragment.newInstance(it.msg, false) mProcessingDialog?.show(supportFragmentManager, null) { if (mViewModel.uploadImageSubscription != null && !mViewModel.uploadImageSubscription!!.isDisposed) { - mUploadImageCancelDialog = DialogUtils.showAlertDialog(this, "提示" - , "图片正在上传中,确定取消吗?" - , "确定", "取消", { - mViewModel.uploadImageSubscription!!.dispose() - mUploadImageCancelDialog?.dismiss() - mProcessingDialog?.dismiss() - }, null) + mUploadImageCancelDialog = DialogUtils.showAlertDialog( + this, + "提示", + "图片正在上传中,确定取消吗?", + "确定", + "取消", + { + mViewModel.uploadImageSubscription!!.dispose() + mUploadImageCancelDialog?.dismiss() + mProcessingDialog?.dismiss() + }, + null + ) } } } @@ -427,28 +472,41 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke if (checkSameFromQuestionData()) { toast("内容没有变化") } else { + //版主不是作者时,仅能修改用户的标题内容,正文不能修改 + if (mViewModel.questionEntity?.user?.id != UserManager.getInstance().userId && mViewModel.questionEntity?.description != mViewModel.content) { + toast("不能修改正文") + return true + } mViewModel.selectedTags.addAll(mViewModel.questionEntity?.tags!!) - DialogUtils.showAlertDialog(this, "修改问题", - if (mViewModel.questionEntity!!.me.moderatorPermissions.updateQuestion == Permissions.REPORTER) - "你的操作将提交给小编审核,确定提交吗?" else "你的操作将立即生效,确定提交吗?(你的管理权限为:高级)", - "确定", "取消", DialogUtils.ConfirmListener { - mViewModel.uploadPicAndPatchQuestion(false) - }, null) + DialogUtils.showAlertDialog( + this, "修改问题", + if (mViewModel.questionEntity!!.me.moderatorPermissions.updateQuestion == Permissions.REPORTER) + "你的操作将提交给小编审核,确定提交吗?" else "你的操作将立即生效,确定提交吗?", + "确定", "取消", DialogUtils.ConfirmListener { + mViewModel.uploadPicAndPatchQuestion(false) + }, null + ) } } else { if (mViewModel.checkTitleAndLoadTitleTag(mIsKeyBoardShow)) { mTagsSelectFragment?.postQuestion() } } - val bbsType = if (mViewModel.type.isNotEmpty()) if (mViewModel.type == "game_bbs") "游戏论坛" else "综合论坛" else "" - NewLogUtils.logQuestionEditClick("click_question_post_button", mViewModel.communityEntity?.id + val bbsType = + if (mViewModel.type.isNotEmpty()) if (mViewModel.type == "game_bbs") "游戏论坛" else "综合论坛" else "" + NewLogUtils.logQuestionEditClick( + "click_question_post_button", mViewModel.communityEntity?.id ?: "", - bbsType, mViewModel.selectActivityLabelEntity?.name - ?: "", mViewModel.quoteCountEntity) + bbsType, mViewModel.selectActivityLabelEntity?.name + ?: "", mViewModel.quoteCountEntity + ) } else if (menuItem?.itemId == R.id.menu_draft) { if (checkDraft(SaveDraftType.SKIP)) { NewLogUtils.logQuestionDraftClick() - startActivityForResult(QuestionDraftActivity.getIntent(this), QUESTION_DRAFT_REQUEST_CODE) + startActivityForResult( + QuestionDraftActivity.getIntent(this), + QUESTION_DRAFT_REQUEST_CODE + ) } } @@ -476,7 +534,10 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke private fun showSelectGameDialog() { if (mViewModel.type == BbsType.OFFICIAL_BBS.value) { - startActivityForResult(GameActivity.getIntent(this, GameActivity.SELECT_GAME_TITLE), VideoPublishFragment.REQUEST_GAME_CODE) + startActivityForResult( + GameActivity.getIntent(this, GameActivity.SELECT_GAME_TITLE), + VideoPublishFragment.REQUEST_GAME_CODE + ) } else { val delayTime = if (mIsKeyBoardShow) { Util_System_Keyboard.hideSoftKeyboard(this) @@ -534,22 +595,31 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke if (checkSameFromQuestionData()) { return false } - DialogUtils.showCancelAlertDialog(this, "提示" - , "确定退出修改?已编辑的内容将丢失" - , "继续编辑", " 退出", null) { finish() } + DialogUtils.showCancelAlertDialog( + this, "提示", "确定退出修改?已编辑的内容将丢失", "继续编辑", " 退出", null + ) { finish() } return true } //问题发布 if (mViewModel.questionEntity == null && mViewModel.questionDraftEntity == null) { if (!mBinding.questionseditTitle.text.isNullOrEmpty() || !mBinding.richEditor.html.isNullOrEmpty()) { - DialogUtils.showNewAlertDialog(this, "提示", "是否保存内容再退出?", "不保存", "保存并退出", Gravity.CENTER, true, { - finish() - }, { - mViewModel.title = mBinding.questionseditTitle.text.toString() - mViewModel.content = getReplaceRealContent() - mViewModel.saveQuestionDraft(SaveDraftType.EXIT) - }) + DialogUtils.showNewAlertDialog( + this, + "提示", + "是否保存内容再退出?", + "不保存", + "保存并退出", + Gravity.CENTER, + true, + { + finish() + }, + { + mViewModel.title = mBinding.questionseditTitle.text.toString() + mViewModel.content = getReplaceRealContent() + mViewModel.saveQuestionDraft(SaveDraftType.EXIT) + }) return true } } @@ -557,7 +627,8 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke //问题编辑,需要判断是否修改过 if (mViewModel.questionEntity != null && mViewModel.questionDraftEntity == null) { return if (mViewModel.questionEntity?.title != mBinding.questionseditTitle.text.toString() - || mViewModel.questionEntity?.description != mBinding.richEditor.html) { + || mViewModel.questionEntity?.description != mBinding.richEditor.html + ) { showBackDialog() true } else false @@ -572,7 +643,8 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke if (saveType == SaveDraftType.SKIP) { //判断是否修改了草稿,修改了需自动保存无需提示 if (draftEntity.title != mBinding.questionseditTitle.text.toString() - || draftEntity.description != mBinding.richEditor.html) { + || draftEntity.description != mBinding.richEditor.html + ) { mViewModel.title = mBinding.questionseditTitle.text.toString() mViewModel.content = getReplaceRealContent() mViewModel.saveQuestionDraft(SaveDraftType.AUTO) @@ -581,7 +653,8 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke } else if (saveType == SaveDraftType.EXIT) { //退出页面需判断是否修改了草稿,修改了需弹窗提示 if (draftEntity.title != mBinding.questionseditTitle.text.toString() - || draftEntity.description != mBinding.richEditor.html) { + || draftEntity.description != mBinding.richEditor.html + ) { showBackDialog() return false } @@ -590,13 +663,22 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke } private fun showBackDialog() { - DialogUtils.showNewAlertDialog(this, "提示", "是否保存修改内容用于下次编辑?", "不保存", "保存并退出", Gravity.CENTER, true, { - finish() - }, { - mViewModel.title = mBinding.questionseditTitle.text.toString() - mViewModel.content = getReplaceRealContent() - mViewModel.saveQuestionDraft(SaveDraftType.EXIT) - }) + DialogUtils.showNewAlertDialog( + this, + "提示", + "是否保存修改内容用于下次编辑?", + "不保存", + "保存并退出", + Gravity.CENTER, + true, + { + finish() + }, + { + mViewModel.title = mBinding.questionseditTitle.text.toString() + mViewModel.content = getReplaceRealContent() + mViewModel.saveQuestionDraft(SaveDraftType.EXIT) + }) } private fun checkSameFromQuestionData(): Boolean { @@ -616,14 +698,21 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke if (mViewModel.communityEntity != null) { if (mViewModel.type == BbsType.GAME_BBS.value) { mBinding.chooseForumTv.text = mViewModel.communityEntity?.name - mBinding.forumIconView.displayGameIcon(mViewModel.communityEntity?.icon, mViewModel.communityEntity?.iconSubscript) + mBinding.forumIconView.displayGameIcon( + mViewModel.communityEntity?.icon, + mViewModel.communityEntity?.iconSubscript + ) setForumUI() } else if (mViewModel.type == BbsType.OFFICIAL_BBS.value) { if (mViewModel.gameEntity == null) { mBinding.chooseForumTv.text = "选择游戏" + mBinding.forumIconView.visibility = View.GONE } else { mBinding.chooseForumTv.text = mViewModel.gameEntity?.name - mBinding.forumIconView.displayGameIcon(mViewModel.gameEntity?.icon, mViewModel.gameEntity?.iconSubscript) + mBinding.forumIconView.displayGameIcon( + mViewModel.gameEntity?.icon, + mViewModel.gameEntity?.iconSubscript + ) setForumUI() } } @@ -637,7 +726,11 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke val beginTransaction = supportFragmentManager.beginTransaction() mTagsSelectFragment = TagsSelectFragment.getInstance() - beginTransaction.replace(R.id.tagsContainer, mTagsSelectFragment!!, TagsSelectFragment::javaClass.name) + beginTransaction.replace( + R.id.tagsContainer, + mTagsSelectFragment!!, + TagsSelectFragment::javaClass.name + ) beginTransaction.commitAllowingStateLoss() mViewModel.selectedTags.clear() mViewModel.selectedTagsChange.postValue(true) @@ -646,8 +739,14 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke private fun setForumUI() { mBinding.forumIconView.visibility = View.VISIBLE - mBinding.forumContainer.background = ContextCompat.getDrawable(this, R.drawable.bg_shape_f5_radius_999) - mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds(null, null, ContextCompat.getDrawable(this, R.drawable.ic_article_edit_choose_forum_arrow_gray), null) + mBinding.forumContainer.background = + ContextCompat.getDrawable(this, R.drawable.bg_shape_f5_radius_999) + mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds( + null, + null, + ContextCompat.getDrawable(this, R.drawable.ic_article_edit_choose_forum_arrow_gray), + null + ) mBinding.chooseForumTv.setTextColor(ContextCompat.getColor(this, R.color.text_333333)) } @@ -691,7 +790,11 @@ class QuestionEditActivity : BaseRichEditorActivity(), Ke return intent } - fun getIntent(context: Context, communityEntity: CommunityEntity, type: String = ""): Intent { + fun getIntent( + context: Context, + communityEntity: CommunityEntity, + type: String = "" + ): Intent { val intent = Intent(context, QuestionEditActivity::class.java) intent.putExtra(CommunityEntity::class.java.simpleName, communityEntity) intent.putExtra(BbsType::class.java.simpleName, type) diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditViewModel.kt index 77a5ef4941..70ef6ed91a 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditViewModel.kt @@ -219,14 +219,15 @@ class QuestionEditViewModel(application: Application) : BaseRichEditorViewModel( postLiveData.postValue(Resource.success(data)) EventBus.getDefault().post(EBReuse(QuestionEditActivity.QUESTION_POSTED_TAG)) + if (!questionDraftEntity?.id.isNullOrEmpty()) { + EventBus.getDefault().post(EBReuse(QuestionEditActivity.QUESTION_DRAFT_CHANGE_TAG)) + } + if (questionEntity == null) { tryWithDefaultCatch { EnergyTaskHelper.postEnergyTask("post_question", JSONObject(data).optString("_id")) } } - if (!questionDraftEntity?.id.isNullOrEmpty()) { - EventBus.getDefault().post(EBReuse(QuestionEditActivity.QUESTION_DRAFT_CHANGE_TAG)) - } } override fun onFailure(e: HttpException?) { diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/newdetail/NewQuestionDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/newdetail/NewQuestionDetailFragment.kt index 0d3e37b7e2..e5f9b9b733 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/questions/newdetail/NewQuestionDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/questions/newdetail/NewQuestionDetailFragment.kt @@ -39,7 +39,8 @@ import org.greenrobot.eventbus.EventBus import java.util.* import kotlin.collections.ArrayList -class NewQuestionDetailFragment : BaseCommentFragment() { +class NewQuestionDetailFragment : + BaseCommentFragment() { private var mScrollToCommentArea: Boolean = false private var mIsRecommendsContent: Boolean = false private lateinit var mViewModel: NewQuestionDetailViewModel @@ -51,7 +52,11 @@ class NewQuestionDetailFragment : BaseCommentFragment(QuestionsDetailEntity::class.java.simpleName)?.let { - mViewModel.questionDetail = it - mAdapter?.questionDetailVH?.bindView(it) - updateView() - } + data.getParcelableExtra(QuestionsDetailEntity::class.java.simpleName) + ?.let { + mViewModel.questionDetail = it + mAdapter?.questionDetailVH?.bindView(it) + updateView() + } mReuseNoConn?.performClick() //重新刷新 } else if (requestCode == ImageViewerActivity.REQUEST_FOR_VIEWED_IMAGE && resultCode == Activity.RESULT_OK) { val imageSet = data.extras?.get(ImageViewerActivity.VIEWED_IMAGE) as HashSet @@ -105,11 +112,14 @@ class NewQuestionDetailFragment : BaseCommentFragment - (mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = insets.systemWindowInsetTop + (mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = + insets.systemWindowInsetTop insets.consumeSystemWindowInsets() } - mSkeletonScreen = Skeleton.bind(skeletonView).shimmer(false).load(R.layout.fragment_article_detail_skeleton).show() + mSkeletonScreen = Skeleton.bind(skeletonView).shimmer(false) + .load(R.layout.fragment_article_detail_skeleton).show() val bbsType = if (mViewModel.questionDetail?.type == "game_bbs") "游戏论坛" else "综合论坛" mBinding.inputContainer.replyTv.text = "说点什么吧" mBinding.inputContainer.replyTv.setRoundedColorBackground(R.color.text_F5F5F5, 19F) mBinding.inputContainer.replyTv.setDebouncedClickListener { - startCommentActivity() - NewLogUtils.logCommentClick("click_comment_area_comment_input_box", mViewModel.questionDetail?.user?.id - ?: "", "提问帖", mViewModel.questionDetail?.id - ?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType) + clickToastByStatus(mViewModel.questionDetail?.status ?: "") { + startCommentActivity() + NewLogUtils.logCommentClick( + "click_comment_area_comment_input_box", mViewModel.questionDetail?.user?.id + ?: "", "提问帖", mViewModel.questionDetail?.id + ?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType + ) + } } mBinding.inputContainer.bottomCommentTv.text = "回答" mBinding.inputContainer.bottomLikeTv.text = "邀请" @@ -159,17 +175,29 @@ class NewQuestionDetailFragment : BaseCommentFragment 56F.dip2px()) { mBinding.forumGameIv.visibility = View.GONE mBinding.userAvatar.visibility = View.VISIBLE - mAttentionMenu?.isVisible = questionDetail.user.id != UserManager.getInstance().userId + mAttentionMenu?.isVisible = + questionDetail.user.id != UserManager.getInstance().userId mBinding.forumTitleTv.text = questionDetail.user.name mIsToolbarUserShow = true } else if (mIsToolbarUserShow && mListRv.computeVerticalScrollOffset() <= 56F.dip2px()) { @@ -321,8 +373,10 @@ class NewQuestionDetailFragment : BaseCommentFragment 0) + NewLogUtils.logSlideArticleOrQuestionDetail( + "提问帖详情", "slide_question_detail_page", + (filterView?.top ?: 0) > 0 + ) if ((filterView?.top ?: 0) > 0) { NewLogUtils.logCommentAreaEnter("提问帖") } @@ -355,12 +409,12 @@ class NewQuestionDetailFragment : BaseCommentFragment(EntranceUtils.KEY_COMMUNITY_DATA)?.id - ?: "", - arguments?.getString(EntranceUtils.KEY_ANSWER_ID) ?: "")) + NewQuestionDetailViewModel.Factory( + HaloApp.getInstance().application, + arguments?.getString(EntranceUtils.KEY_QUESTIONS_ID) ?: "", + arguments?.getParcelable(EntranceUtils.KEY_COMMUNITY_DATA)?.id + ?: "", + arguments?.getString(EntranceUtils.KEY_ANSWER_ID) ?: "" + ) + ) } override fun provideListAdapter(): ListAdapter<*> { return mAdapter - ?: NewQuestionDetailAdapter(requireContext(), mViewModel, BaseCommentAdapter.AdapterType.COMMENT, mEntrance).apply { - mAdapter = this - } + ?: NewQuestionDetailAdapter( + requireContext(), + mViewModel, + BaseCommentAdapter.AdapterType.COMMENT, + mEntrance + ).apply { + mAdapter = this + } } override fun onBackPressed(): Boolean { - if (SyncDataBetweenPageHelper.setResultAndFinish(requireContext(), mViewModel.questionDetail)) { + if (SyncDataBetweenPageHelper.setResultAndFinish( + requireContext(), + mViewModel.questionDetail + ) + ) { return true } @@ -404,13 +469,22 @@ class NewQuestionDetailFragment : BaseCommentFragment { ifLogin("提问贴") { - BbsReportHelper.showReportDialog(mViewModel.questionDetail?.id - ?: "") + BbsReportHelper.showReportDialog( + mViewModel.questionDetail?.id + ?: "" + ) } - NewLogUtils.logSharePanelClick("click_report", mViewModel.questionDetail?.user?.id + NewLogUtils.logSharePanelClick( + "click_report", mViewModel.questionDetail?.user?.id ?: "", "提问帖", mViewModel.questionDetail?.id ?: "", mViewModel.questionDetail?.community?.id - ?: "", bbsType) + ?: "", bbsType + ) } "编辑" -> { val intent = if (questionEntity.me.isModerator) { - QuestionEditActivity.getManagerIntent(requireContext(), questionEntity) + QuestionEditActivity.getManagerIntent( + requireContext(), + questionEntity + ) } else { QuestionEditActivity.getIntent(requireContext(), questionEntity) } - startActivityForResult(intent, QuestionsDetailFragment.QUESTIONS_EDIT_REQUEST) - NewLogUtils.logSharePanelClick("click_modification_question", mViewModel.questionDetail?.user?.id + startActivityForResult( + intent, + QuestionsDetailFragment.QUESTIONS_EDIT_REQUEST + ) + NewLogUtils.logSharePanelClick( + "click_modification_question", mViewModel.questionDetail?.user?.id ?: "", "提问帖", mViewModel.questionDetail?.id - ?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType) + ?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType + ) } - "删除" -> { - DialogUtils.showNewAlertDialog(requireContext(), "提示", "删除问题后,其中的所有回答都将被删除", "取消", "删除", {}, { - mListViewModel.moderatorsHideQuestion() - }) - NewLogUtils.logSharePanelClick("click_delete", mViewModel.questionDetail?.user?.id + "删除", "隐藏" -> { + DialogUtils.showNewAlertDialog( + requireContext(), + "提示", + "${it.text}问题后,其中的所有回答都将被${it.text}", + "取消", + it.text, + {}, + { + mListViewModel.moderatorsHideQuestion() + }) + NewLogUtils.logSharePanelClick( + "click_delete", mViewModel.questionDetail?.user?.id ?: "", "提问帖", mViewModel.questionDetail?.id - ?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType) + ?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType + ) } "解决", "已解决" -> { - val content = if (!questionEntity.finish) "该问题确定标记已解决?" else "该问题确定标记未解决?" + val content = + if (!questionEntity.finish) "该问题确定标记已解决?" else "该问题确定标记未解决?" DialogHelper.showDialog(requireContext(), "提示", content, "确定", "取消", { mListViewModel.postSolveQuestion(!questionEntity.finish) }) - NewLogUtils.logSharePanelClick(if (!questionEntity.finish) "click_solve" else "click_resolved", mViewModel.questionDetail?.user?.id - ?: "", "提问帖", mViewModel.questionDetail?.id - ?: "", mViewModel.questionDetail?.community?.id ?: "", bbsType) + NewLogUtils.logSharePanelClick( + if (!questionEntity.finish) "click_solve" else "click_resolved", + mViewModel.questionDetail?.user?.id + ?: "", + "提问帖", + mViewModel.questionDetail?.id + ?: "", + mViewModel.questionDetail?.community?.id ?: "", + bbsType + ) } } } @@ -488,8 +598,10 @@ class NewQuestionDetailFragment : BaseCommentFragment() var questionPageFinishedLiveData = MutableLiveData() val moderatorsHideLiveData = MutableLiveData() @@ -42,28 +55,28 @@ class NewQuestionDetailViewModel(application: Application, questionId: String = fun getQuestionDetail() { mApi.getQuestionsById(questionId) - .compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: QuestionsDetailEntity?) { - super.onResponse(response) - questionDetail = response - topItemData = CommentItemData(questionDetail = response) - commentCount = response?.count?.answer ?: 0 - loadResultLiveData.postValue(LoadResult.SUCCESS) - mergeListData(mListLiveData.value, displayFloor = true) + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: QuestionsDetailEntity?) { + super.onResponse(response) + questionDetail = response + topItemData = CommentItemData(questionDetail = response) + commentCount = response?.count?.answer ?: 0 + loadResultLiveData.postValue(LoadResult.SUCCESS) + mergeListData(mListLiveData.value, displayFloor = true) - NewLogUtils.logForumContentBrowser(questionId, "bbs_question") - } + NewLogUtils.logForumContentBrowser(questionId, "bbs_question") + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - if (e?.code().toString().startsWith("404")) { - loadResultLiveData.postValue(LoadResult.DELETED) - } else { - loadResultLiveData.postValue(LoadResult.NETWORK_ERROR) - } + override fun onFailure(e: HttpException?) { + super.onFailure(e) + if (e?.code().toString().startsWith("404")) { + loadResultLiveData.postValue(LoadResult.DELETED) + } else { + loadResultLiveData.postValue(LoadResult.NETWORK_ERROR) } - }) + } + }) } override fun provideDataObservable(page: Int): Observable>? { @@ -98,62 +111,67 @@ class NewQuestionDetailViewModel(application: Application, questionId: String = mApi.deleteFollowing(targetUserId) } observable - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - if (isFollow) { - // 关注成功 - mFollowLiveData.postValue(true) - } else { - // 取消关注成功 - mFollowLiveData.postValue(false) - } - - SyncPageRepository.postSyncData(SyncDataEntity(questionDetail?.id ?: "", - SyncFieldConstants.IS_FOLLOWER, - isFollow, - checkFieldEntity = true)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + if (isFollow) { + // 关注成功 + mFollowLiveData.postValue(true) + } else { + // 取消关注成功 + mFollowLiveData.postValue(false) } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - Utils.toast(getApplication(), R.string.loading_failed_hint) - } - }) + SyncPageRepository.postSyncData( + SyncDataEntity( + questionDetail?.id ?: "", + SyncFieldConstants.IS_FOLLOWER, + isFollow, + checkFieldEntity = true + ) + ) + EventBus.getDefault().post(EBUserFollow(targetUserId, isFollow)) + } + + override fun onFailure(e: HttpException?) { + super.onFailure(e) + Utils.toast(getApplication(), R.string.loading_failed_hint) + } + }) } fun moderatorsHideQuestion() { val me = questionDetail?.me ?: return mApi.moderatorsHideQuestion(UserManager.getInstance().userId, questionId) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - if (me.moderatorPermissions.hideQuestion == Permissions.REPORTER) { - Utils.toast(getApplication(), "提交成功") - } else { - Utils.toast(getApplication(), "操作成功") - moderatorsHideLiveData.postValue(true) - mLoadStatusLiveData.setValue(LoadStatus.INIT_EMPTY) - } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + if (me.isModerator) { + Utils.toast(getApplication(), "已隐藏") + } else { + Utils.toast(getApplication(), "已删除") } + moderatorsHideLiveData.postValue(true) + mLoadStatusLiveData.value = LoadStatus.INIT_EMPTY + } - override fun onFailure(e: HttpException?) { - if (e != null && e.code() == 403) { - val string = e.response().errorBody()?.string() - val errorJson = JSONObject(string) - val errorCode = errorJson.getInt("code") - if (errorCode == 403059) { - Utils.toast(getApplication(), "权限错误,请刷新后重试") - load(LoadType.REFRESH) - return - } + override fun onFailure(e: HttpException?) { + if (e != null && e.code() == 403) { + val string = e.response().errorBody()?.string() + val errorJson = JSONObject(string) + val errorCode = errorJson.getInt("code") + if (errorCode == 403059) { + Utils.toast(getApplication(), "权限错误,请刷新后重试") + load(LoadType.REFRESH) + return } - Utils.toast(getApplication(), R.string.post_failure_hint) } - }) + Utils.toast(getApplication(), R.string.post_failure_hint) + } + }) } @SuppressLint("CheckResult") @@ -165,51 +183,55 @@ class NewQuestionDetailViewModel(application: Application, questionId: String = mApi.favoriteQuestion(UserManager.getInstance().userId, questionId) } single.compose(singleToMain()) - .subscribe(object : BiResponse() { - override fun onSuccess(data: ResponseBody) { - if (questionDetail?.me?.isQuestionFavorite == true) { - ToastUtils.showToast("取消收藏") - } else { - ToastUtils.showToast("收藏成功") - } - questionDetail?.me?.isQuestionFavorite = questionDetail?.me?.isQuestionFavorite != true - favoriteLiveData.postValue(true) + .subscribe(object : BiResponse() { + override fun onSuccess(data: ResponseBody) { + if (questionDetail?.me?.isQuestionFavorite == true) { + ToastUtils.showToast("取消收藏") + } else { + ToastUtils.showToast("收藏成功") } - }) + questionDetail?.me?.isQuestionFavorite = + questionDetail?.me?.isQuestionFavorite != true + favoriteLiveData.postValue(true) + } + }) } fun postSolveQuestion(isSolve: Boolean) { if (questionDetail == null) return val body = json { "finish" to isSolve }.toRequestBody() mApi.solveQuestion(questionDetail?.id ?: "", body) - .compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - questionDetail?.apply { - finish = isSolve - updateDetailLiveData.postValue(this) - } + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + questionDetail?.apply { + finish = isSolve + updateDetailLiveData.postValue(this) } + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - ToastUtils.showToast("操作失败") - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + ToastUtils.showToast("操作失败") + } + }) } - class Factory(private val application: Application, - private val questionId: String = "", - private val communityId: String = "", - private val answerId: String = "") : ViewModelProvider.NewInstanceFactory() { + class Factory( + private val application: Application, + private val questionId: String = "", + private val communityId: String = "", + private val answerId: String = "" + ) : ViewModelProvider.NewInstanceFactory() { override fun create(modelClass: Class): T { return NewQuestionDetailViewModel( - application = application, - questionId = questionId, - communityId = communityId, - answerId = answerId) as T + application = application, + questionId = questionId, + communityId = communityId, + answerId = answerId + ) as T } } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/newdetail/QuestionDetailContentViewHolder.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/newdetail/QuestionDetailContentViewHolder.kt index 75a8833600..deb2d257d4 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/questions/newdetail/QuestionDetailContentViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/questions/newdetail/QuestionDetailContentViewHolder.kt @@ -5,6 +5,7 @@ import android.app.Activity import android.view.View import android.webkit.JavascriptInterface import android.webkit.WebView +import android.widget.LinearLayout import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import com.gh.common.DefaultUrlHandler @@ -19,8 +20,10 @@ import com.gh.gamecenter.qa.editor.OnLinkClickListener import com.gh.gamecenter.qa.entity.QuestionsDetailEntity import java.util.* -class QuestionDetailContentViewHolder(var binding: ItemArticleDetailContentBinding, var viewModel: NewQuestionDetailViewModel) - : RecyclerView.ViewHolder(binding.root) { +class QuestionDetailContentViewHolder( + var binding: ItemArticleDetailContentBinding, + var viewModel: NewQuestionDetailViewModel +) : RecyclerView.ViewHolder(binding.root) { private var mEntrance = "" val questionImgUrlList = ArrayList() @@ -31,8 +34,12 @@ class QuestionDetailContentViewHolder(var binding: ItemArticleDetailContentBindi richEditor.setInputEnabled(false) richEditor.setPadding(20, 20, 20, 15) richEditor.addJavascriptInterface(JsInterface(question.status), "imagelistener") - richEditor.addJavascriptInterface(OnLinkClickListener(root.context, question.title - ?: "", question.status, mEntrance, "问题详情"), "OnLinkClickListener") + richEditor.addJavascriptInterface( + OnLinkClickListener( + root.context, question.title + ?: "", question.status, mEntrance, "问题详情" + ), "OnLinkClickListener" + ) richEditor.setLayoutCallback(object : EmptyCallback { override fun onCallback() { viewModel.questionRenderedLiveData.postValue(true) @@ -63,6 +70,13 @@ class QuestionDetailContentViewHolder(var binding: ItemArticleDetailContentBindi approvalStatusTv.background = R.drawable.bg_approval_status_fail.toDrawable() } } + if (question.status != "pass") { + (statusContainer.layoutParams as LinearLayout.LayoutParams).apply { + topMargin = 7f.dip2px() + statusContainer.layoutParams = this + } + titleTv.setPadding(20f.dip2px(), 16f.dip2px(), 20f.dip2px(), 5f.dip2px()) + } val bbsType = if (question.type == "game_bbs") "游戏论坛" else "综合论坛" followBtn.setOnClickListener { @@ -70,33 +84,54 @@ class QuestionDetailContentViewHolder(var binding: ItemArticleDetailContentBindi if (followBtn.text == "关注") { viewModel.follow() } else { - DialogUtils.showAlertDialog(root.context, - "取消关注", - "确定要取消关注 ${question.user.name} 吗?", - "确定取消", - "暂不取消", - DialogUtils.ConfirmListener { - viewModel.unFollow() - }, null) + DialogUtils.showAlertDialog( + root.context, + "取消关注", + "确定要取消关注 ${question.user.name} 吗?", + "确定取消", + "暂不取消", + DialogUtils.ConfirmListener { + viewModel.unFollow() + }, null + ) } - NewLogUtils.logQuestionDetailClick("click_question_detail_follow", question.user.id - ?: "", "提问帖", question.community.id, bbsType) + NewLogUtils.logQuestionDetailClick( + "click_question_detail_follow", question.user.id + ?: "", "提问帖", question.community.id, bbsType + ) } } userNameTv.setOnClickListener { - DirectUtils.directToHomeActivity(root.context, question.user.id, 1, mEntrance, "问题详情") - NewLogUtils.logQuestionDetailClick("click_question_detail_nickname", question.user.id - ?: "", "提问帖", question.community.id, bbsType) + DirectUtils.directToHomeActivity( + root.context, + question.user.id, + 1, + mEntrance, + "问题详情" + ) + NewLogUtils.logQuestionDetailClick( + "click_question_detail_nickname", question.user.id + ?: "", "提问帖", question.community.id, bbsType + ) } userIconIv.setOnClickListener { - DirectUtils.directToHomeActivity(root.context, question.user.id, 1, mEntrance, "问题详情") - NewLogUtils.logQuestionDetailClick("click_question_detail_profile_photo", question.user.id - ?: "", "提问帖", question.community.id, bbsType) + DirectUtils.directToHomeActivity( + root.context, + question.user.id, + 1, + mEntrance, + "问题详情" + ) + NewLogUtils.logQuestionDetailClick( + "click_question_detail_profile_photo", question.user.id + ?: "", "提问帖", question.community.id, bbsType + ) } - titleTv.text = if (question.finish){ - SpanBuilder(" ${question.title}").image(0, 1, R.drawable.ic_ask_solved_label).build() - }else{ + titleTv.text = if (question.finish) { + SpanBuilder(" ${question.title}").image(0, 1, R.drawable.ic_ask_solved_label) + .build() + } else { SpanBuilder(" ${question.title}").image(0, 1, R.drawable.ic_ask_label).build() } userNameTv.text = question.user.name @@ -107,20 +142,31 @@ class QuestionDetailContentViewHolder(var binding: ItemArticleDetailContentBindi richEditor.setHtml(question.description, true) } if (question.time.create == question.time.edit) { - releaseTimeTv.text = String.format("发布于%s", NewsUtils.getFormattedTime(question.time.create)) + releaseTimeTv.text = + String.format("发布于%s", NewsUtils.getFormattedTime(question.time.create)) } else { - releaseTimeTv.text = String.format("发布于%s 最后编辑于%s", NewsUtils.getFormattedTime(question.time.create), NewsUtils.getFormattedTime(question.time.edit)) + releaseTimeTv.text = String.format( + "发布于%s 最后编辑于%s", + NewsUtils.getFormattedTime(question.time.create), + NewsUtils.getFormattedTime(question.time.edit) + ) } richEditor.visibility = View.VISIBLE question.community.let { entity -> gameName.text = entity.name val icon = if (!entity.icon.isNullOrEmpty()) entity.icon else entity.game?.getIcon() - val iconSubscript = if (!entity.iconSubscript.isNullOrEmpty()) entity.iconSubscript else entity.game?.iconSubscript + val iconSubscript = + if (!entity.iconSubscript.isNullOrEmpty()) entity.iconSubscript else entity.game?.iconSubscript forumIconView.displayGameIcon(icon, iconSubscript) forumContainer.setOnClickListener { DirectUtils.directForumDetail(forumContainer.context, entity.id, "问题详情") LogUtils.uploadAccessToBbs(entity.id, "文章内所属论坛") - NewLogUtils.logArticleOrQuestionDetailForumClick("提问帖详情", "click_question_detail_forum", entity.id, bbsType) + NewLogUtils.logArticleOrQuestionDetailForumClick( + "提问帖详情", + "click_question_detail_forum", + entity.id, + bbsType + ) } } @@ -140,12 +186,17 @@ class QuestionDetailContentViewHolder(var binding: ItemArticleDetailContentBindi } badgeIv.goneIf(question.user.badge == null) - badgeTv.goneIf(question.user.badge == null) +// badgeTv.goneIf(question.user.badge == null) badgeTv.text = question.user.badge?.name ImageUtils.display(badgeIv, question.user.badge?.icon) badgeIv.setOnClickListener { DialogUtils.showViewBadgeDialog(root.context, question.user.badge) { - DirectUtils.directToBadgeWall(root.context, question.user.id, question.user.name, question.user.icon) + DirectUtils.directToBadgeWall( + root.context, + question.user.id, + question.user.name, + question.user.icon + ) } } badgeTv.setOnClickListener { badgeIv.performClick() } @@ -179,25 +230,25 @@ class QuestionDetailContentViewHolder(var binding: ItemArticleDetailContentBindi runOnUiThread { binding.richEditor.replaceDfImageByUrl(url) } } else -> { - if (status == "pending") { - ToastUtils.showToast("内容审核中") - return - } else if (status == "fail") { - ToastUtils.showToast("内容审核不通过") - return - } - var current = 0 - var i = 0 - val size = questionImgUrlList.size - while (i < size) { - if (url.contains(questionImgUrlList.get(i))) { - current = i + clickToastByStatus(status) { + var current = 0 + var i = 0 + val size = questionImgUrlList.size + while (i < size) { + if (url.contains(questionImgUrlList.get(i))) { + current = i + } + i++ } - i++ + val intent = ImageViewerActivity.getIntent( + binding.root.context, questionImgUrlList, current, + mEntrance + "+(问题详情[" + binding.titleTv.text.toString() + "])" + ) + (binding.root.context as Activity).startActivityForResult( + intent, + ImageViewerActivity.REQUEST_FOR_VIEWED_IMAGE + ) } - val intent = ImageViewerActivity.getIntent(binding.root.context, questionImgUrlList, current, - mEntrance + "+(问题详情[" + binding.titleTv.text.toString() + "])") - (binding.root.context as Activity).startActivityForResult(intent, ImageViewerActivity.REQUEST_FOR_VIEWED_IMAGE) } } } diff --git a/app/src/main/java/com/gh/gamecenter/qa/search/user/UserViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/search/user/UserViewModel.kt index 0697158c09..541a2f508d 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/search/user/UserViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/search/user/UserViewModel.kt @@ -8,6 +8,7 @@ import com.gh.gamecenter.R import com.gh.gamecenter.baselist.ListViewModel import com.gh.gamecenter.baselist.OnDataObservable import com.gh.gamecenter.entity.FollowersOrFansEntity +import com.gh.gamecenter.eventbus.EBUserFollow import com.gh.gamecenter.retrofit.Response import com.gh.gamecenter.retrofit.RetrofitManager import com.lightgame.utils.Utils @@ -15,6 +16,7 @@ import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody +import org.greenrobot.eventbus.EventBus import retrofit2.HttpException class UserViewModel(application: Application, @@ -53,6 +55,7 @@ class UserViewModel(application: Application, } followingLiveData.postValue(position) + EventBus.getDefault().post(EBUserFollow(targetUserId, isFollow)) } override fun onFailure(e: HttpException?) { diff --git a/app/src/main/java/com/gh/gamecenter/qa/select/VotingViewModel.java b/app/src/main/java/com/gh/gamecenter/qa/select/VotingViewModel.java index 48f43f3251..03b61e18d2 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/select/VotingViewModel.java +++ b/app/src/main/java/com/gh/gamecenter/qa/select/VotingViewModel.java @@ -67,7 +67,7 @@ public class VotingViewModel extends ListViewModel params = new HashMap<>(); params.put("message", "问答社区推荐收录:" + entity.getGameName() + "(" + entity.getPackageName() + ", " + entity.getGameVersion() + ")"); params.put("from", ""); - params.put("ghversion", PackageUtils.getVersionName()); + params.put("ghversion", PackageUtils.getGhVersionName()); params.put("channel", HaloApp.getInstance().getChannel()); params.put("type", android.os.Build.MODEL); params.put("sdk", String.valueOf(android.os.Build.VERSION.SDK_INT)); diff --git a/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumTopVideoView.kt b/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumTopVideoView.kt index 2f342f29c6..e366c6b6f6 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumTopVideoView.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumTopVideoView.kt @@ -39,7 +39,7 @@ class ForumTopVideoView @JvmOverloads constructor(context: Context, attrs: Attri var viewModel: ForumVideoDetailViewModel? = null var uuid = UUID.randomUUID().toString() var thumbImage: SimpleDraweeView = findViewById(R.id.thumbImage) - var pendingView: View = findViewById(R.id.pendingView) + var pendingView: TextView = findViewById(R.id.pendingView) var titleTv: TextView = findViewById(R.id.title) init { @@ -411,8 +411,9 @@ class ForumTopVideoView @JvmOverloads constructor(context: Context, attrs: Attri uploadVideoStreamingPlaying("暂停播放") } - fun setPendingStatus(isPending: Boolean) { - if (isPending) { + fun setVideoStatus(status: String) { + if (status == "pending" || status == "fail") { + pendingView.text = if (status == "pending") "审核中...请耐心等待" else "审核不通过" pendingView.visibility = View.VISIBLE mBottomContainer?.visibility = View.GONE mStartButton?.visibility = View.GONE diff --git a/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailActivity.kt b/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailActivity.kt index f82c1b6f03..3bb98439f0 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailActivity.kt @@ -39,13 +39,14 @@ class ForumVideoDetailActivity : BaseActivity() { companion object { const val VIDEO_PATCH_REQUEST = 100 - fun getIntent(context: Context, videoId: String): Intent { - return getIntent(context, videoId, false) + fun getIntent(context: Context, videoId: String, bbsId: String): Intent { + return getIntent(context, videoId, bbsId, false) } - fun getIntent(context: Context, videoId: String, scrollToComment: Boolean = false): Intent { + fun getIntent(context: Context, videoId: String, bbsId: String, scrollToComment: Boolean = false): Intent { val intent = Intent(context, ForumVideoDetailActivity::class.java) intent.putExtra(EntranceUtils.KEY_VIDEO_ID, videoId) + intent.putExtra(EntranceUtils.KEY_BBS_ID, bbsId) if (scrollToComment) { intent.putExtra(PAGE_INDEX, 1) } diff --git a/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailFragment.kt index 1873680225..08291f9a38 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailFragment.kt @@ -68,6 +68,7 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { private var mMoreMenuItem: MenuItem? = null private var mForumVideoEntity: ForumVideoEntity? = null private var mVideoId = "" + private var mBbsId = "" private var mVideoDescFragment: VideoDescFragment? = null private var mVideoCommentFragment: VideoCommentFragment? = null private var mIsPortrait = false @@ -83,7 +84,11 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { override fun getLayoutId(): Int = 0 override fun getInflatedLayout(): View { - mBinding = FragmentForumVideoDetailBinding.inflate(LayoutInflater.from(requireContext()), null, false) + mBinding = FragmentForumVideoDetailBinding.inflate( + LayoutInflater.from(requireContext()), + null, + false + ) return mBinding.root } @@ -93,7 +98,8 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { mVideoDescFragment = this }) fragments.add(VideoCommentFragment().apply { - arguments = bundleOf(EntranceUtils.KEY_VIDEO_ID to mVideoId) + arguments = + bundleOf(EntranceUtils.KEY_VIDEO_ID to mVideoId, EntranceUtils.KEY_BBS_ID to mBbsId) mVideoCommentFragment = this }) } @@ -105,6 +111,7 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { override fun onCreate(savedInstanceState: Bundle?) { mVideoId = arguments?.getString(EntranceUtils.KEY_VIDEO_ID) ?: "" + mBbsId = arguments?.getString(EntranceUtils.KEY_BBS_ID) ?: "" super.onCreate(savedInstanceState) NewLogUtils.logVideoDetailClick("view_video_detail") } @@ -114,12 +121,14 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { mBinding.toolbar.inflateMenu(R.menu.menu_forum_video_detail) mMoreMenuItem = mBinding.toolbar.menu.findItem(R.id.menu_more) ViewCompat.setOnApplyWindowInsetsListener(mBinding.appbar) { _, insets -> - (mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = insets.systemWindowInsetTop + (mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = + insets.systemWindowInsetTop insets.consumeSystemWindowInsets() } mViewModel = viewModelProviderFromParent(ForumVideoDetailViewModel.Factory(mVideoId)) - mSkeleton = Skeleton.bind(mBinding.skeleton).shimmer(false).load(R.layout.fragment_video_detail_skeleton).show() + mSkeleton = Skeleton.bind(mBinding.skeleton).shimmer(false) + .load(R.layout.fragment_video_detail_skeleton).show() mBinding.toolbar.setNavigationOnClickListener { requireActivity().finish() } mOrientationUtils = OrientationUtils(requireActivity(), mBinding.topVideoView) mOrientationUtils?.isEnable = false @@ -203,6 +212,7 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { } else { updateToolbarParams(mVideoHeight / 2) } + mViewModel.addHistoryRecord(entity) } else { mBinding.container.visibility = View.GONE if (it.exception != null && it.exception.code() == 404) { @@ -215,8 +225,12 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { mBinding.reuseLoading.root.visibility = View.GONE mSkeleton?.hide() } - mViewModel.deleteLiveData.observe(viewLifecycleOwner, Observer { - ToastUtils.showToast("删除成功") + mViewModel.deleteLiveData.observe(viewLifecycleOwner, { + if (mForumVideoEntity?.me?.isModerator == true) { + ToastUtils.showToast("已隐藏") + } else { + ToastUtils.showToast("已删除") + } EventBus.getDefault().post(EBDeleteDetail(mViewModel.videoId)) requireActivity().finish() }) @@ -229,9 +243,11 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { if (isHighlighted) { if (mForumVideoEntity!!.me.moderatorPermissions.highlightVideo == Permissions.REPORTER) { toast("提交成功") + mForumVideoEntity?.choicenessStatus = "apply" } else { toast("操作成功") - requireActivity().finish() + mForumVideoEntity?.choicenessStatus = "pass" + mViewModel.updateDetailLiveData.postValue(mForumVideoEntity) } } else { toast("权限错误,请刷新后重试") @@ -240,7 +256,7 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { mViewModel.applyHighlight.observeNonNull(this) { if (it) { toast("提交成功") - requireActivity().finish() + mForumVideoEntity?.choicenessStatus = "apply" } else { toast("提交失败") } @@ -258,8 +274,10 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { mBinding.gameScoreTv.text = gameEntity.star.toString() mBinding.game = gameEntity mBinding.gameInfoContainer.setOnClickListener { - NewLogUtils.logVideoDetailGameClick("click_game", gameEntity.id, gameEntity.category - ?: "", "") + NewLogUtils.logVideoDetailGameClick( + "click_game", gameEntity.id, gameEntity.category + ?: "", "" + ) GameDetailActivity.startGameDetailActivity(requireContext(), gameEntity, "视频详情") } setDownloadButton(gameEntity) @@ -279,7 +297,12 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { mBinding.toolbar.setNavigationIcon(R.drawable.ic_bar_back_light) mMoreMenuItem?.setIcon(R.drawable.ic_menu_gamedetail_more_light) - mBinding.toolbar.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.transparent)) + mBinding.toolbar.setBackgroundColor( + ContextCompat.getColor( + requireContext(), + R.color.transparent + ) + ) } private fun updateVideoParams() { @@ -303,25 +326,25 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { private fun setUpTopVideo(entity: ForumVideoEntity) { GSYVideoOptionBuilder() - .setIsTouchWigetFull(false) - .setIsTouchWiget(false) - .setRotateViewAuto(false) - .setShowFullAnimation(false) - .setSeekRatio(1f) - .setUrl(entity.url) - .setCacheWithPlay(true) - .setVideoAllCallBack(object : GSYSampleCallBack() { - override fun onQuitFullscreen(url: String?, vararg objects: Any) { - mOrientationUtils?.backToProtVideo() - mBinding.topVideoView.uploadVideoStreamingPlaying("退出全屏") - } - }) - .build(mBinding.topVideoView) + .setIsTouchWigetFull(false) + .setIsTouchWiget(false) + .setRotateViewAuto(false) + .setShowFullAnimation(false) + .setSeekRatio(1f) + .setUrl(entity.url) + .setCacheWithPlay(true) + .setVideoAllCallBack(object : GSYSampleCallBack() { + override fun onQuitFullscreen(url: String?, vararg objects: Any) { + mOrientationUtils?.backToProtVideo() + mBinding.topVideoView.uploadVideoStreamingPlaying("退出全屏") + } + }) + .build(mBinding.topVideoView) mBinding.topVideoView.viewModel = mViewModel mBinding.topVideoView.updateThumb(entity.poster) - mBinding.topVideoView.setPendingStatus(entity.status == "pending" || entity.status == "fail") + mBinding.topVideoView.setVideoStatus(entity.status) if (entity.status == "pass" && NetworkUtils.isWifiConnected(requireContext())) { if (mViewModel.isTopVideoPartlyCached(entity.url)) { mBinding.topVideoView.startPlayLogic(isAutoPlay = true) @@ -336,7 +359,11 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { } mBinding.topVideoView.fullscreenButton.setOnClickListener { - val horizontalVideoView = mBinding.topVideoView.startWindowFullscreen(requireContext(), true, true) as? ForumTopVideoView + val horizontalVideoView = mBinding.topVideoView.startWindowFullscreen( + requireContext(), + true, + true + ) as? ForumTopVideoView if (horizontalVideoView == null) { toastInInternalRelease("全屏失败,请向技术人员提供具体的操作步骤") return@setOnClickListener @@ -355,7 +382,8 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { } override fun provideTabView(position: Int, title: String?): View { - val view = LayoutInflater.from(requireContext()).inflate(R.layout.tab_item_forum_video_detail, null) + val view = LayoutInflater.from(requireContext()) + .inflate(R.layout.tab_item_forum_video_detail, null) val tabTitle = view.findViewById(R.id.tab_title) val tabCount = view.findViewById(R.id.tab_count) if (tabTitle is CheckedTextView) { @@ -372,17 +400,20 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { private fun setDownloadButton(gameEntity: GameEntity?) { if (gameEntity == null) return DownloadItemUtils.setOnClickListener(requireContext(), mBinding.downloadBtn, - gameEntity, 0, null, - mEntrance, "视频详情", null, object : EmptyCallback { - override fun onCallback() { - NewLogUtils.logVideoDetailGameClick("click_game", gameEntity.id, gameEntity.category - ?: "", mBinding.downloadBtn.text.toString()) - } - }, object : EmptyCallback { - override fun onCallback() { - setDownloadButton(gameEntity) - } - }, null) + gameEntity, 0, null, + mEntrance, "视频详情", null, object : EmptyCallback { + override fun onCallback() { + NewLogUtils.logVideoDetailGameClick( + "click_game", gameEntity.id, gameEntity.category + ?: "", mBinding.downloadBtn.text.toString() + ) + } + }, object : EmptyCallback { + override fun onCallback() { + setDownloadButton(gameEntity) + } + }, null + ) // 显示预约 if (gameEntity.isReservable) { @@ -414,28 +445,52 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { when (offStatus) { "dialog" -> { mBinding.downloadBtn.text = "查看" - mBinding.downloadBtn.setTextColor(ContextCompat.getColor(requireContext(), R.color.white)) + mBinding.downloadBtn.setTextColor( + ContextCompat.getColor( + requireContext(), + R.color.white + ) + ) } "updating" -> { mBinding.downloadBtn.text = "更新中" - mBinding.downloadBtn.setTextColor(ContextCompat.getColor(requireContext(), R.color.white)) + mBinding.downloadBtn.setTextColor( + ContextCompat.getColor( + requireContext(), + R.color.white + ) + ) mBinding.downloadBtn.setBackgroundResource(R.drawable.download_button_updating_style) } else -> { mBinding.downloadBtn.text = "暂无" - mBinding.downloadBtn.setTextColor(ContextCompat.getColor(requireContext(), R.color.button_gray)) + mBinding.downloadBtn.setTextColor( + ContextCompat.getColor( + requireContext(), + R.color.button_gray + ) + ) mBinding.downloadBtn.setBackgroundResource(R.drawable.news_detail_comment) } } mBinding.downloadBtn.isClickable = false } } else if (gameEntity.getApk().size == 1) { - setDownloadBtnStatus(requireContext(), gameEntity, mBinding.downloadBtn, PluginLocation.only_game) - val downloadEntity = DownloadManager.getInstance(requireContext()).getDownloadEntityByUrl(gameEntity.getApk()[0].url) + setDownloadBtnStatus( + requireContext(), + gameEntity, + mBinding.downloadBtn, + PluginLocation.only_game + ) + val downloadEntity = DownloadManager.getInstance(requireContext()) + .getDownloadEntityByUrl(gameEntity.getApk()[0].url) if (downloadEntity != null) { if (downloadEntity.status == DownloadStatus.done) { if (SimulatorGameManager.isSimulatorGame(gameEntity)) { - val isInstalled = PackageUtils.isInstalled(context, gameEntity.simulator?.apk?.packageName) + val isInstalled = PackageUtils.isInstalled( + context, + gameEntity.simulator?.apk?.packageName + ) if (isInstalled) { mBinding.downloadBtn.setText(R.string.launch) } else { @@ -458,15 +513,30 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { mBinding.downloadBtn.setText(R.string.downloading) } mBinding.downloadBtn.setBackgroundResource(R.drawable.textview_concern_red_up_round) - mBinding.downloadBtn.setTextColor(ContextCompat.getColorStateList(requireContext(), R.color.white)) + mBinding.downloadBtn.setTextColor( + ContextCompat.getColorStateList( + requireContext(), + R.color.white + ) + ) } } } else { - setDownloadBtnStatus(requireContext(), gameEntity, mBinding.downloadBtn, PluginLocation.only_game) + setDownloadBtnStatus( + requireContext(), + gameEntity, + mBinding.downloadBtn, + PluginLocation.only_game + ) } } - private fun setDownloadBtnStatus(context: Context, gameEntity: GameEntity, downloadBtn: TextView, pluginLocation: PluginLocation) { + private fun setDownloadBtnStatus( + context: Context, + gameEntity: GameEntity, + downloadBtn: TextView, + pluginLocation: PluginLocation + ) { val status = GameUtils.getDownloadBtnText(context, gameEntity, pluginLocation) downloadBtn.setTextColor(Color.WHITE) downloadBtn.text = status @@ -483,8 +553,16 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { private fun showMoreItemDialog() { if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) || mForumVideoEntity != null) { val entities = ArrayList() - if (mForumVideoEntity?.user?.id == UserManager.getInstance().userId && !mForumVideoEntity?.me!!.isModerator && mForumVideoEntity?.status == "pass" && mForumVideoEntity?.choicenessStatus != "pass") { - entities.add(MenuItemEntity("申请加精", R.drawable.icon_more_panel_essence)) + if (mForumVideoEntity?.user?.id == UserManager.getInstance().userId && !mForumVideoEntity?.me!!.isModerator && mForumVideoEntity?.status == "pass") { + val isEnable = + mForumVideoEntity?.getSimplifyChoicenessStatus() != "pass" + entities.add( + MenuItemEntity( + "申请加精", if (isEnable) + R.drawable.icon_more_panel_essence else R.drawable.icon_more_panel_essence_unenable, + isEnable = isEnable + ) + ) } if (mForumVideoEntity?.user?.id == UserManager.getInstance().userId && mForumVideoEntity?.status == "pass") { entities.add(MenuItemEntity("修改", R.drawable.icon_more_panel_edit)) @@ -492,14 +570,27 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { if (mForumVideoEntity?.user?.id != UserManager.getInstance().userId) { entities.add(MenuItemEntity("投诉", R.drawable.icon_gamedetail_copyright)) } - if (mForumVideoEntity?.me!!.isModerator) { - val isEnable = mForumVideoEntity?.isHighlighted == true - entities.add(MenuItemEntity("加精选", if (isEnable) - R.drawable.icon_more_panel_essence_unenable else R.drawable.icon_more_panel_essence, isEnable = !isEnable)) + if (mForumVideoEntity?.me!!.isModerator && mForumVideoEntity?.user?.id != UserManager.getInstance().userId && mForumVideoEntity?.status == "pass") { + val isEnable = + mForumVideoEntity?.getSimplifyChoicenessStatus() != "pass" + entities.add( + MenuItemEntity( + "加精选", + if (isEnable) + R.drawable.icon_more_panel_essence else R.drawable.icon_more_panel_essence_unenable, + isEnable = isEnable + ) + ) + } + if (mForumVideoEntity?.me!!.isModerator && mForumVideoEntity?.status == "pass") { entities.add(MenuItemEntity("修改活动标签", R.drawable.icon_more_panel_modify_label)) } - if (mForumVideoEntity?.me!!.isModerator || mForumVideoEntity?.user?.id == UserManager.getInstance().userId) { - entities.add(MenuItemEntity("删除", R.drawable.icon_more_panel_delete)) + if (mForumVideoEntity?.me!!.isModerator) { + entities.add(MenuItemEntity("隐藏", R.drawable.icon_more_panel_delete)) + } else { + if (mForumVideoEntity?.user?.id == UserManager.getInstance().userId) { + entities.add(MenuItemEntity("删除", R.drawable.icon_more_panel_delete)) + } } val shareUrl = if (isPublishEnv()) { "https://m.ghzs666.com/video/${mForumVideoEntity?.id}" @@ -513,62 +604,98 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { requireContext().getString(R.string.share_ghzs_logo) } val shareUtils = ShareUtils.getInstance(requireContext()) - shareUtils.shareParamsDetail(requireActivity(), - shareUrl, - shareIcon, - mForumVideoEntity?.title ?: "", - mForumVideoEntity?.des ?: "", - ShareUtils.ShareEntrance.communityArticle, - mForumVideoEntity?.id, null) + shareUtils.shareParamsDetail( + requireActivity(), + shareUrl, + shareIcon, + mForumVideoEntity?.title ?: "", + mForumVideoEntity?.des ?: "", + ShareUtils.ShareEntrance.video, + mForumVideoEntity?.id, null + ) val bbsType = if (mForumVideoEntity?.type == "game_bbs") "游戏论坛" else "综合论坛" - MoreFunctionPanelDialog.showMoreDialog(requireActivity() as AppCompatActivity, entities, mForumVideoEntity?.title - ?: "", shareUtils) { + MoreFunctionPanelDialog.showMoreDialog( + requireActivity() as AppCompatActivity, entities, mForumVideoEntity?.title + ?: "", shareUtils + ) { when (it.text) { "修改" -> { - startActivityForResult(VideoPublishActivity.getIntent(requireContext(), mForumVideoEntity!!, mEntrance, "视频详情"), ForumVideoDetailActivity.VIDEO_PATCH_REQUEST) - NewLogUtils.logSharePanelClick("click_modification", mForumVideoEntity?.user?.id + startActivityForResult( + VideoPublishActivity.getIntent( + requireContext(), + mForumVideoEntity!!, + mEntrance, + "视频详情" + ), ForumVideoDetailActivity.VIDEO_PATCH_REQUEST + ) + NewLogUtils.logSharePanelClick( + "click_modification", mForumVideoEntity?.user?.id ?: "", "视频帖", mForumVideoEntity?.id - ?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType) + ?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType + ) } "投诉" -> { BbsReportHelper.showReportDialog(mForumVideoEntity?.id ?: "") - NewLogUtils.logSharePanelClick("click_report", mForumVideoEntity?.user?.id + NewLogUtils.logSharePanelClick( + "click_report", mForumVideoEntity?.user?.id ?: "", "视频帖", mForumVideoEntity?.id - ?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType) + ?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType + ) } "申请加精" -> { - if (mForumVideoEntity?.choicenessStatus == "apply") { + if (mForumVideoEntity?.getSimplifyChoicenessStatus() == "apply") { ToastUtils.showToast("申请加精审核中") return@showMoreDialog } mViewModel.doApplyHighlightCommunityVideo(mVideoId) - NewLogUtils.logSharePanelClick("click_apply_essence", mForumVideoEntity?.user?.id + NewLogUtils.logSharePanelClick( + "click_apply_essence", mForumVideoEntity?.user?.id ?: "", "视频帖", mForumVideoEntity?.id - ?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType) + ?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType + ) } "加精选" -> { + if (mForumVideoEntity?.getSimplifyChoicenessStatus() == "apply") { + ToastUtils.showToast("加精审核中") + return@showMoreDialog + } addEssenceForum() - NewLogUtils.logSharePanelClick("click_essence", mForumVideoEntity?.user?.id + NewLogUtils.logSharePanelClick( + "click_essence", mForumVideoEntity?.user?.id ?: "", "视频帖", mForumVideoEntity?.id - ?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType) + ?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType + ) } "修改活动标签" -> { - ChooseActivityDialogFragment.show(requireActivity() as AppCompatActivity, ChooseActivityDialogFragment.ActivityLabelLocation.BBS_ARTICLE, mForumVideoEntity?.tagActivityId) { label -> - if (label != null) { - mViewModel.modifyVideoActivityTag(mForumVideoEntity, label) - NewLogUtils.logSharePanelClick("click_modification_activity_tag", mForumVideoEntity?.user?.id - ?: "", "视频帖", mForumVideoEntity?.id - ?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType) - } + ChooseActivityDialogFragment.show( + requireActivity() as AppCompatActivity, + ChooseActivityDialogFragment.ActivityLabelLocation.BBS_ARTICLE, + mForumVideoEntity?.tagActivityId + ) { label -> + mViewModel.modifyVideoActivityTag(mForumVideoEntity, label) + NewLogUtils.logSharePanelClick( + "click_modification_activity_tag", mForumVideoEntity?.user?.id + ?: "", "视频帖", mForumVideoEntity?.id + ?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType + ) } } - "删除" -> { - DialogUtils.showNewAlertDialog(requireContext(), "提示", "删除视频后,其中的所有评论及回复都将被删除", "取消", "删除", {}, { - mViewModel.deleteVideo(mForumVideoEntity?.id ?: "") - }) - NewLogUtils.logSharePanelClick("click_delete", mForumVideoEntity?.user?.id + "删除", "隐藏" -> { + DialogUtils.showNewAlertDialog( + requireContext(), + "提示", + "${it.text}视频后,其中的所有评论及回复都将被${it.text}", + "取消", + it.text, + {}, + { + mViewModel.deleteVideo(mForumVideoEntity?.id ?: "") + }) + NewLogUtils.logSharePanelClick( + "click_delete", mForumVideoEntity?.user?.id ?: "", "视频帖", mForumVideoEntity?.id - ?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType) + ?: "", mForumVideoEntity?.bbs?.id ?: "", bbsType + ) } } } @@ -583,25 +710,24 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { highlightDialogHintContent = if (permissions.highlightVideo == Permissions.REPORTER) { "你的操作将提交给小编审核,确定提交吗?" } else { - "你的操作将立即生效,确定提交吗?(你的管理权限为:高级)" + "你的操作将立即生效,确定提交吗?" } } - if (mForumVideoEntity?.isHighlighted == true) { - toast("帖子已经加精") - } else { - DialogUtils.showAlertDialog(requireContext(), "加精视频", highlightDialogHintContent, - "确定", "取消", - { - mViewModel.doHighlightThisVideo(mForumVideoEntity?.bbsId ?: "", mVideoId) - }, null) - } + DialogUtils.showAlertDialog( + requireContext(), "加精视频", highlightDialogHintContent, + "确定", "取消", + { + mViewModel.doHighlightThisVideo(mForumVideoEntity?.bbsId ?: "", mVideoId) + }, null + ) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (data == null || resultCode != Activity.RESULT_OK) return if (requestCode == ForumVideoDetailActivity.VIDEO_PATCH_REQUEST) { - val entity = data.getParcelableExtra(ForumVideoEntity::class.java.simpleName) + val entity = + data.getParcelableExtra(ForumVideoEntity::class.java.simpleName) mForumVideoEntity?.let { it.title = entity?.title ?: "" it.des = entity?.des ?: "" @@ -638,7 +764,12 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { super.onPause() mBinding.topVideoView.onVideoPause() val currentPosition = mBinding.topVideoView.getCurrentPosition() - ForumScrollCalculatorHelper.savePlaySchedule(MD5Utils.getContentMD5(mForumVideoEntity?.url), currentPosition) + mForumVideoEntity?.let { + ForumScrollCalculatorHelper.savePlaySchedule( + MD5Utils.getContentMD5(it.url), + currentPosition + ) + } DownloadManager.getInstance(requireContext()).removeObserver(dataWatcher) } @@ -648,9 +779,11 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() { mBinding.topVideoView.disposableTimer() val stayTime = (System.currentTimeMillis() - startPageTime) / 1000 val bbsType = if (mForumVideoEntity?.type == "game_bbs") "游戏论坛" else "综合论坛" - NewLogUtils.logActivityPause("视频帖详情页", "jump_video_detail ", stayTime, - mForumVideoEntity?.bbs?.id ?: "", bbsType, "视频帖", - mForumVideoEntity?.id ?: "") + NewLogUtils.logActivityPause( + "视频帖详情页", "jump_video_detail ", stayTime, + mForumVideoEntity?.bbs?.id ?: "", bbsType, "视频帖", + mForumVideoEntity?.id ?: "" + ) } override fun onBackPressed(): Boolean { diff --git a/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailViewModel.kt index ae0de54a06..862c6020c0 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailViewModel.kt @@ -6,14 +6,19 @@ import android.net.Uri import android.text.TextUtils import androidx.lifecycle.* import com.gh.common.constant.Constants +import com.gh.common.history.HistoryDatabase import com.gh.common.json.json +import com.gh.common.runOnIoThread import com.gh.common.util.* import com.gh.gamecenter.entity.ActivityLabelEntity import com.gh.gamecenter.entity.ForumVideoEntity +import com.gh.gamecenter.entity.MyVideoEntity +import com.gh.gamecenter.entity.User import com.gh.gamecenter.mvvm.Resource import com.gh.gamecenter.retrofit.BiResponse import com.gh.gamecenter.retrofit.Response import com.gh.gamecenter.retrofit.RetrofitManager +import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel import com.google.gson.JsonObject import com.halo.assistant.HaloApp import io.reactivex.schedulers.Schedulers @@ -21,7 +26,8 @@ import okhttp3.ResponseBody import retrofit2.HttpException import tv.danmaku.ijk.media.exo2.ExoSourceManager -class ForumVideoDetailViewModel(application: Application, val videoId: String) : AndroidViewModel(application) { +class ForumVideoDetailViewModel(application: Application, val videoId: String) : + AndroidViewModel(application) { private val mApi = RetrofitManager.getInstance(getApplication()).api var videoIsMuted = SPUtils.getBoolean(Constants.SP_VIDEO_PLAY_MUTE, true) val detailLiveData = MediatorLiveData>() @@ -38,112 +44,132 @@ class ForumVideoDetailViewModel(application: Application, val videoId: String) : fun getVideoDetail() { mApi.getBbsVideoDetail(videoId) - .compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: ForumVideoEntity?) { - super.onResponse(response) - if (response != null) { - detailLiveData.postValue(Resource.success(response)) + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: ForumVideoEntity?) { + super.onResponse(response) + if (response != null) { + detailLiveData.postValue(Resource.success(response)) - NewLogUtils.logForumContentBrowser(videoId, "bbs_video") - } + NewLogUtils.logForumContentBrowser(videoId, "bbs_video") } + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - detailLiveData.postValue(Resource.error(e)) - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + detailLiveData.postValue(Resource.error(e)) + } + }) } @SuppressLint("CheckResult") fun shareVideoStatistics(videoEntity: ForumVideoEntity?) { if (videoEntity == null) return mApi.shareVideoStatistics(videoEntity.id) - .subscribeOn(Schedulers.io()) - .subscribe(object : BiResponse() { - override fun onSuccess(data: JsonObject) { - val msg = data.get("msg").asString - if ("success" == msg) { - videoEntity.let { - it.share++ - } - needToUpdateShareCount.postValue(videoEntity.share) + .subscribeOn(Schedulers.io()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: JsonObject) { + val msg = data.get("msg").asString + if ("success" == msg) { + videoEntity.let { + it.share++ } + needToUpdateShareCount.postValue(videoEntity.share) } - }) + } + }) } fun deleteVideo(videoId: String) { mApi.deleteVideo(videoId) - .compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - deleteLiveData.postValue(true) - } + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + deleteLiveData.postValue(true) + } - override fun onFailure(e: HttpException?) { - val string = e?.response()?.errorBody()?.string() ?: "" - ErrorHelper.handleError(getApplication(), string) - } - }) + override fun onFailure(e: HttpException?) { + val string = e?.response()?.errorBody()?.string() ?: "" + ErrorHelper.handleError(getApplication(), string) + } + }) } //版主加精 fun doHighlightThisVideo(bbsId: String, videoId: String) { mApi.highlightCommunityVideo(bbsId, videoId) - .compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - highlight.postValue(true) - } + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + highlight.postValue(true) + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - highlight.postValue(false) - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + highlight.postValue(false) + } + }) } //用户申请加精 fun doApplyHighlightCommunityVideo(videoId: String) { mApi.applyHighlightCommunityVideo(videoId) - .compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - applyHighlight.postValue(true) - } + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + applyHighlight.postValue(true) + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - applyHighlight.postValue(false) - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + applyHighlight.postValue(false) + } + }) } - fun modifyVideoActivityTag(videoEntity: ForumVideoEntity?, label: ActivityLabelEntity) { - val body = json { "tag_activity_id" to label.id }.toRequestBody() - mApi.modifyVideoActivityTag(videoEntity?.bbsId,videoId,body) - .compose(observableToMain()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - videoEntity?.apply { - tagActivityId = label.id - tagActivityName = label.name - updateDetailLiveData.postValue(this) - } + fun modifyVideoActivityTag(videoEntity: ForumVideoEntity?, label: ActivityLabelEntity?) { + val body = json { "tag_activity_id" to label?.id }.toRequestBody() + mApi.modifyVideoActivityTag(videoEntity?.bbsId, videoId, body) + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + videoEntity?.apply { + tagActivityId = label?.id ?: "" + tagActivityName = label?.name ?: "" + updateDetailLiveData.postValue(this) + ToastUtils.showToast("修改活动标签成功") } + } - override fun onFailure(e: HttpException?) { - super.onFailure(e) - ToastUtils.showToast("修改活动标签失败") - } - }) + override fun onFailure(e: HttpException?) { + super.onFailure(e) + ToastUtils.showToast("修改活动标签失败") + } + }) + } + + fun addHistoryRecord(videoEntity: ForumVideoEntity) { + val videoHistory = MyVideoEntity().apply { + id = videoEntity.id + poster = videoEntity.poster + url = videoEntity.url + vote = videoEntity.count.vote + length = videoEntity.length + time = System.currentTimeMillis() + title = videoEntity.title + user = User( + videoEntity.user.id, videoEntity.user.name, videoEntity.user.icon + ) + commentCount = videoEntity.count.comment + videoStreamRecord = 0 + } + + runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.videoHistoryDao().addVideo(videoHistory) } } } fun isTopVideoPartlyCached(topVideoUrl: String): Boolean { diff --git a/app/src/main/java/com/gh/gamecenter/qa/video/detail/comment/VideoCommentFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/video/detail/comment/VideoCommentFragment.kt index be3fb9c021..e2d58a6bc0 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/video/detail/comment/VideoCommentFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/video/detail/comment/VideoCommentFragment.kt @@ -30,6 +30,7 @@ class VideoCommentFragment : LazyListFragment { return mAdapter ?: VideoCommentAdapter(requireContext(), mListViewModel, mEntrance).apply { @@ -40,14 +41,16 @@ class VideoCommentFragment : LazyListFragment() @@ -42,9 +43,10 @@ class VideoCommentViewModel(application: Application, videoId: String) : BaseCom deleteCommentLiveData.postValue(true) } - class Factory(private val videoId: String) : ViewModelProvider.NewInstanceFactory() { + class Factory(private val videoId: String, private val bbsId: String) : + ViewModelProvider.NewInstanceFactory() { override fun create(modelClass: Class): T { - return VideoCommentViewModel(HaloApp.getInstance().application, videoId) as T + return VideoCommentViewModel(HaloApp.getInstance().application, videoId, bbsId) as T } } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/video/detail/desc/VideoDescAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/video/detail/desc/VideoDescAdapter.kt index 0e2a9db2b1..9c15e1a682 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/video/detail/desc/VideoDescAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/video/detail/desc/VideoDescAdapter.kt @@ -83,7 +83,7 @@ class VideoDescAdapter(context: Context, val mVideoDetailViewModel: ForumVideoDe holder.binding.video = recommendVideo holder.binding.root.setOnClickListener { recommendVideo?.let { - mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, it.id)) + mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, it.id,it.bbs?.id ?: "")) } val bbsType = if (mViewModel.topVideoDetail?.bbs?.type == "game_bbs") "游戏论坛" else "综合论坛" NewLogUtils.logVideoDetailClick("click_video_detail_for_you_video", diff --git a/app/src/main/java/com/gh/gamecenter/qa/video/detail/desc/VideoDescFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/video/detail/desc/VideoDescFragment.kt index e8fb2fd061..f93d7730af 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/video/detail/desc/VideoDescFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/video/detail/desc/VideoDescFragment.kt @@ -4,6 +4,7 @@ import android.view.View import androidx.lifecycle.Observer import androidx.recyclerview.widget.RecyclerView import com.gh.common.util.NewLogUtils +import com.gh.common.util.ShareUtils import com.gh.common.util.observeNonNull import com.gh.common.util.viewModelProviderFromParent import com.gh.gamecenter.R @@ -11,8 +12,11 @@ import com.gh.gamecenter.baselist.LazyListFragment import com.gh.gamecenter.baselist.ListAdapter import com.gh.gamecenter.entity.ForumVideoEntity import com.gh.gamecenter.entity.VideoDescItemEntity +import com.gh.gamecenter.eventbus.EBShare import com.gh.gamecenter.mvvm.Status import com.gh.gamecenter.qa.video.detail.ForumVideoDetailViewModel +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode class VideoDescFragment : LazyListFragment() { @@ -68,4 +72,13 @@ class VideoDescFragment : LazyListFragment(binding.root) { +class VideoDescTopViewHolder( + val binding: ItemVideoDescTopBinding, + var mIsExpand: Boolean, + var mShrinkHeight: Int, + var mExpandHeight: Int, + val mVideoDetailViewModel: ForumVideoDetailViewModel, + val mViewModel: VideoDescViewModel +) : BaseRecyclerViewHolder(binding.root) { private var mIsAnimationFinish = true fun bindData(entity: ForumVideoEntity) { binding.entity = entity @@ -26,53 +33,89 @@ class VideoDescTopViewHolder(val binding: ItemVideoDescTopBinding, var mIsExpand binding.executePendingBindings() if (entity.original == "yes") { binding.originalTv.visibility = View.VISIBLE - binding.activityNameTv.layoutParams = (binding.activityNameTv.layoutParams as ConstraintLayout.LayoutParams).apply { - leftMargin = 8f.dip2px() - } + binding.activityNameTv.layoutParams = + (binding.activityNameTv.layoutParams as ConstraintLayout.LayoutParams).apply { + leftMargin = 8f.dip2px() + } } - if (entity.choicenessStatus == "pass") { - binding.titleTv.text = SpanBuilder(" ${entity.title}").image(0, 1, R.drawable.ic_essence).build() + if (entity.getSimplifyChoicenessStatus() == "pass") { + binding.titleTv.text = + SpanBuilder(" ${entity.title}").image(0, 1, R.drawable.ic_essence).build() } initAnimation(entity) val bbsType = if (entity.bbs?.type == "game_bbs") "游戏论坛" else "综合论坛" binding.userAvatar.setOnClickListener { DirectUtils.directToHomeActivity(binding.root.context, entity.user.id, "视频详情", "") - NewLogUtils.logVideoDetailClick("click_detail_tab_profile_photo", entity.user.id, - "视频贴", entity.bbs?.id ?: "", bbsType) + NewLogUtils.logVideoDetailClick( + "click_detail_tab_profile_photo", entity.user.id, + "视频贴", entity.bbs?.id ?: "", bbsType + ) } binding.userNameTv.setOnClickListener { DirectUtils.directToHomeActivity(binding.root.context, entity.user.id, "视频详情", "") - NewLogUtils.logVideoDetailClick("click_detail_tab_nickname", entity.user.id, - "视频贴", entity.bbs?.id ?: "", bbsType) + NewLogUtils.logVideoDetailClick( + "click_detail_tab_nickname", entity.user.id, + "视频贴", entity.bbs?.id ?: "", bbsType + ) } binding.likeContainer.setOnClickListener { debounceActionWithInterval(it.id, 2000) { mViewModel.postVote() - NewLogUtils.logVideoDetailClick("click_detail_tab_like", entity.user.id, - "视频贴", entity.bbs?.id ?: "", bbsType, entity.id) + NewLogUtils.logVideoDetailClick( + "click_detail_tab_like", entity.user.id, + "视频贴", entity.bbs?.id ?: "", bbsType, entity.id + ) } } binding.collectContainer.setOnClickListener { debounceActionWithInterval(it.id) { mViewModel.postFavorite() - NewLogUtils.logVideoDetailClick("click_detail_tab_collect", entity.user.id, - "视频贴", entity.bbs?.id ?: "", bbsType, entity.id) + NewLogUtils.logVideoDetailClick( + "click_detail_tab_collect", entity.user.id, + "视频贴", entity.bbs?.id ?: "", bbsType, entity.id + ) } } binding.concernBtn.setOnClickListener { if (entity.user.id != UserManager.getInstance().userId) { debounceActionWithInterval(it.id) { - mViewModel.followCommand() - NewLogUtils.logVideoDetailClick("click_detail_tab_follow", entity.user.id, - "视频贴", entity.bbs?.id ?: "", bbsType) + if (!entity.me.isFollower) { + mViewModel.followCommand() + } else { + DialogHelper.showDialog( + binding.concernBtn.context, + "提示", + "确定要取消关注 ${entity.user.name} 吗?", + "确定取消", + "暂不取消", + { + mViewModel.followCommand() + }) + } + NewLogUtils.logVideoDetailClick( + "click_detail_tab_follow", entity.user.id, + "视频贴", entity.bbs?.id ?: "", bbsType + ) } } } binding.shareContainer.setOnClickListener { share(entity) - NewLogUtils.logVideoDetailClick("click_detail_tab_share", entity.user.id, - "视频贴", entity.bbs?.id ?: "", bbsType, entity.id) + NewLogUtils.logVideoDetailClick( + "click_detail_tab_share", entity.user.id, + "视频贴", entity.bbs?.id ?: "", bbsType, entity.id + ) + } + binding.badgeIv.setOnClickListener { + DialogUtils.showViewBadgeDialog(binding.root.context, entity.user.badge) { + DirectUtils.directToBadgeWall( + binding.root.context, + entity.user.id, + entity.user.name, + entity.user.badge?.icon + ) + } } } @@ -83,9 +126,17 @@ class VideoDescTopViewHolder(val binding: ItemVideoDescTopBinding, var mIsExpand } else mShrinkHeight mExpandHeight = if (mExpandHeight == 0) { - getTextViewHeight(binding.titleTv) + getTextViewHeight(binding.desTv) + getTextViewHeight(binding.activityNameTv) + + var height = getTextViewHeight(binding.titleTv) + + getTextViewHeight(binding.desTv) + (if (binding.desTv.visibility == View.VISIBLE) binding.desTv.marginTop else 0) + - (if (binding.activityNameTv.visibility == View.VISIBLE) binding.activityNameTv.marginTop else 0) + (if (binding.activityNameTv.visibility == View.VISIBLE || binding.originalTv.visibility == View.VISIBLE) binding.activityNameTv.marginTop else 0) + if (binding.activityNameTv.visibility == View.VISIBLE || binding.originalTv.visibility == View.VISIBLE) { + height += max( + getTextViewHeight(binding.activityNameTv), + binding.originalTv.measuredHeight + ) + } + height } else mExpandHeight if (mIsExpand) { @@ -96,9 +147,10 @@ class VideoDescTopViewHolder(val binding: ItemVideoDescTopBinding, var mIsExpand updateTitleContainerHeight(mShrinkHeight) } - //若标题未超过一行或无描述内容和活动标签,箭头不显示 - val ellipsisCount = binding.titleTv.layout.getEllipsisCount(binding.titleTv.lineCount - 1) - binding.expandMoreIv.goneIf(entity.des.isEmpty() && entity.tagActivityName.isEmpty() && ellipsisCount == 0) + //若标题未超过一行或无描述内容、活动标签、原创标签,箭头不显示 + val ellipsisCount = + binding.titleTv.layout.getEllipsisCount(binding.titleTv.lineCount - 1) + binding.expandMoreIv.goneIf(entity.des.isEmpty() && entity.tagActivityName.isEmpty() && entity.original != "yes" && ellipsisCount == 0) } binding.expandMoreIv.setOnClickListener { NewLogUtils.logVideoDetailClick(if (!mIsExpand) "click_detail_tab_down" else "click_detail_tab_up") @@ -139,20 +191,23 @@ class VideoDescTopViewHolder(val binding: ItemVideoDescTopBinding, var mIsExpand } else { "https://resource.ghzs.com/page/video_play/video/video.html?video=${entity.id}" } - ShareUtils.getInstance(binding.root.context).showShareWindowsCallback(binding.root.context as Activity, + ShareUtils.getInstance(binding.root.context) + .showShareWindowsCallback(binding.root.context as Activity, (binding.root.context as Activity).window.decorView, shareUrl, shareIcon, entity.title, entity.des, ShareUtils.ShareEntrance.video, entity.id, object : ShareUtils.ShareCallBack { - override fun onSuccess(label: String) { - if ("短信" == label || "复制链接" == label) mVideoDetailViewModel.shareVideoStatistics(entity) - } + override fun onSuccess(label: String) { + if ("短信" == label || "复制链接" == label) mVideoDetailViewModel.shareVideoStatistics( + entity + ) + } - override fun onCancel() { - } - }) + override fun onCancel() { + } + }) } private fun updateTitleContainerHeight(newHeight: Int) { diff --git a/app/src/main/java/com/gh/gamecenter/qa/video/detail/desc/VideoDescViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/video/detail/desc/VideoDescViewModel.kt index d180c2bd3c..0cd66822b0 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/video/detail/desc/VideoDescViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/video/detail/desc/VideoDescViewModel.kt @@ -12,23 +12,30 @@ import com.gh.common.util.* import com.gh.gamecenter.baselist.ListViewModel import com.gh.gamecenter.entity.ForumVideoEntity import com.gh.gamecenter.entity.VideoDescItemEntity +import com.gh.gamecenter.eventbus.EBUserFollow import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.retrofit.BiResponse import com.gh.gamecenter.retrofit.Response import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp import com.lightgame.utils.Utils import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody +import org.greenrobot.eventbus.EventBus import retrofit2.HttpException -class VideoDescViewModel(application: Application) : ListViewModel(application) { +class VideoDescViewModel(application: Application) : + ListViewModel(application) { var topVideoDetail: ForumVideoEntity? = null var handleSuccessLiveData = MutableLiveData() override fun provideDataObservable(page: Int): Observable>? { - return RetrofitManager.getInstance(getApplication()).api.getRecommendVideo(topVideoDetail?.id, page) + return RetrofitManager.getInstance(getApplication()).api.getRecommendVideo( + topVideoDetail?.id, + page + ) } override fun mergeResultLiveData() { @@ -60,10 +67,8 @@ class VideoDescViewModel(application: Application) : ListViewModel() { - override fun onSuccess(data: ResponseBody) { - topVideoDetail?.let { - it.me.isVoted = true - it.count.vote = it.count.vote + 1 - handleSuccessLiveData.postValue(true) - ToastUtils.showToast("点赞爆棚,视频能让更多人看见!") - SyncPageRepository.postSyncData(SyncDataEntity(videoId, SyncFieldConstants.ARTICLE_VOTE, true, checkFieldEntity = true)) - SyncPageRepository.postSyncData(SyncDataEntity(videoId, SyncFieldConstants.ARTICLE_VOTE_COUNT, it.count.vote, checkFieldEntity = true)) - } + .api.voteVideo(videoId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: ResponseBody) { + topVideoDetail?.let { + it.me.isVoted = true + it.count.vote = it.count.vote + 1 + handleSuccessLiveData.postValue(true) + ToastUtils.showToast("点赞爆棚,视频能让更多人看见!") + SyncPageRepository.postSyncData( + SyncDataEntity( + videoId, + SyncFieldConstants.ARTICLE_VOTE, + true, + checkFieldEntity = true + ) + ) + SyncPageRepository.postSyncData( + SyncDataEntity( + videoId, + SyncFieldConstants.ARTICLE_VOTE_COUNT, + it.count.vote, + checkFieldEntity = true + ) + ) } + } - override fun onFailure(exception: Exception) { - super.onFailure(exception) + override fun onFailure(exception: Exception) { + super.onFailure(exception) + if (exception is HttpException) { + ErrorHelper.handleError( + HaloApp.getInstance(), + exception.response()?.errorBody()?.string() + ) } - }) + } + }) } @SuppressLint("CheckResult") private fun undoVoteVideo(videoId: String) { RetrofitManager.getInstance(getApplication()) - .api.undoVoteVideo(videoId) - .subscribeOn(Schedulers.io()) - .subscribe(object : BiResponse() { - override fun onSuccess(data: ResponseBody) { - topVideoDetail?.let { - it.me.isVoted = false - it.count.vote = it.count.vote - 1 - handleSuccessLiveData.postValue(true) - SyncPageRepository.postSyncData(SyncDataEntity(videoId, SyncFieldConstants.ARTICLE_VOTE, false, checkFieldEntity = true)) - SyncPageRepository.postSyncData(SyncDataEntity(videoId, SyncFieldConstants.ARTICLE_VOTE_COUNT, it.count.vote, checkFieldEntity = true)) - } + .api.undoVoteVideo(videoId) + .subscribeOn(Schedulers.io()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: ResponseBody) { + topVideoDetail?.let { + it.me.isVoted = false + it.count.vote = it.count.vote - 1 + handleSuccessLiveData.postValue(true) + SyncPageRepository.postSyncData( + SyncDataEntity( + videoId, + SyncFieldConstants.ARTICLE_VOTE, + false, + checkFieldEntity = true + ) + ) + SyncPageRepository.postSyncData( + SyncDataEntity( + videoId, + SyncFieldConstants.ARTICLE_VOTE_COUNT, + it.count.vote, + checkFieldEntity = true + ) + ) } + } - override fun onFailure(exception: Exception) { - super.onFailure(exception) + override fun onFailure(exception: Exception) { + super.onFailure(exception) + if (exception is HttpException) { + ErrorHelper.handleError( + HaloApp.getInstance(), + exception.response()?.errorBody()?.string() + ) } - }) + } + }) } fun postFavorite() { @@ -123,10 +168,8 @@ class VideoDescViewModel(application: Application) : ListViewModel() { - override fun onSuccess(data: ResponseBody) { - topVideoDetail?.let { - it.me.isVideoFavorite = true - it.count.favorite++ - handleSuccessLiveData.postValue(true) - } - ToastUtils.toast("收藏成功") + .api.collectVideo(UserManager.getInstance().userId, videoId) + .compose(singleToMain()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: ResponseBody) { + topVideoDetail?.let { + it.me.isVideoFavorite = true + it.count.favorite++ + handleSuccessLiveData.postValue(true) } + ToastUtils.toast("收藏成功") + } - override fun onFailure(exception: Exception) { - super.onFailure(exception) - Utils.toast(getApplication(), exception.localizedMessage) - } - }) + override fun onFailure(exception: Exception) { + super.onFailure(exception) + Utils.toast(getApplication(), exception.localizedMessage) + } + }) } @SuppressLint("CheckResult") private fun undoFavoriteVideo(videoId: String) { RetrofitManager.getInstance(getApplication()) - .api.undoCollectVideo(UserManager.getInstance().userId, videoId) - .compose(singleToMain()) - .subscribe(object : BiResponse() { - override fun onSuccess(data: ResponseBody) { - topVideoDetail?.let { - it.me.isVideoFavorite = false - it.count.favorite-- - handleSuccessLiveData.postValue(true) - } - ToastUtils.toast("取消收藏") + .api.undoCollectVideo(UserManager.getInstance().userId, videoId) + .compose(singleToMain()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: ResponseBody) { + topVideoDetail?.let { + it.me.isVideoFavorite = false + it.count.favorite-- + handleSuccessLiveData.postValue(true) } + ToastUtils.toast("取消收藏") + } - override fun onFailure(exception: Exception) { - super.onFailure(exception) - Utils.toast(getApplication(), exception.localizedMessage) - } - }) + override fun onFailure(exception: Exception) { + super.onFailure(exception) + Utils.toast(getApplication(), exception.localizedMessage) + } + }) } fun followCommand() { @@ -187,30 +230,35 @@ class VideoDescViewModel(application: Application) : ListViewModel() { - override fun onResponse(response: ResponseBody?) { - super.onResponse(response) - topVideoDetail?.let { - if (!it.me.isFollower) { - ToastUtils.showToast("关注成功") - } - it.me.isFollower = !it.me.isFollower - } - handleSuccessLiveData.postValue(true) - - topVideoDetail?.run { - SyncPageRepository.postSyncData(SyncDataEntity(id, - SyncFieldConstants.IS_FOLLOWER, - me.isFollower, - checkFieldEntity = true)) + .compose(observableToMain()) + .subscribe(object : Response() { + override fun onResponse(response: ResponseBody?) { + super.onResponse(response) + topVideoDetail?.let { + if (!it.me.isFollower) { + ToastUtils.showToast("关注成功") } + it.me.isFollower = !it.me.isFollower } + handleSuccessLiveData.postValue(true) - override fun onFailure(e: HttpException?) { - super.onFailure(e) - ToastUtils.showToast("加载失败,请检查网络状态") + topVideoDetail?.run { + SyncPageRepository.postSyncData( + SyncDataEntity( + id, + SyncFieldConstants.IS_FOLLOWER, + me.isFollower, + checkFieldEntity = true + ) + ) + EventBus.getDefault().post(EBUserFollow(user.id, me.isFollower)) } - }) + } + + override fun onFailure(e: HttpException?) { + super.onFailure(e) + ToastUtils.showToast("加载失败,请检查网络状态") + } + }) } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/video/publish/VideoPublishFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/video/publish/VideoPublishFragment.kt index e259483ded..ac6d8052d3 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/video/publish/VideoPublishFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/video/publish/VideoPublishFragment.kt @@ -59,7 +59,8 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { override fun getLayoutId(): Int = 0 override fun getInflatedLayout(): View { - mBinding = FragmentVideoPublishBinding.inflate(LayoutInflater.from(requireContext()), null, false) + mBinding = + FragmentVideoPublishBinding.inflate(LayoutInflater.from(requireContext()), null, false) return mBinding.root } @@ -72,8 +73,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { mViewModel = viewModelProvider() mViewModel.videoDraft = arguments?.getParcelable(VideoDraftEntity::class.java.simpleName) mViewModel.videoPatch = arguments?.getParcelable(ForumVideoEntity::class.java.simpleName) - mViewModel.communityEntity = arguments?.getParcelable(CommunityEntity::class.java.simpleName) - mViewModel.selectActivityLabelEntity = arguments?.getParcelable(ActivityLabelEntity::class.java.simpleName) + mViewModel.communityEntity = + arguments?.getParcelable(CommunityEntity::class.java.simpleName) + mViewModel.selectActivityLabelEntity = + arguments?.getParcelable(ActivityLabelEntity::class.java.simpleName) mViewModel.type = arguments?.getString(BbsType::class.java.simpleName) ?: "" mIsForumSelectionDisabled = arguments?.getBoolean(IS_FORUM_SELECTION_DISABLED) ?: false @@ -102,17 +105,31 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { } mBinding.uploadButton.setOnClickListener { - PermissionHelper.checkStoragePermissionBeforeAction(requireActivity(), object : EmptyCallback { - override fun onCallback() { - startActivityForResult(LocalMediaActivity.getIntent(requireContext(), LocalMediaActivity.ChooseType.VIDEO, 1, "发视频帖"), BaseRichEditorActivity.INSERT_VIDEO_CODE) - NewLogUtils.logChooseMedia("view_media", "视频帖", "视频") - } - }) + PermissionHelper.checkStoragePermissionBeforeAction( + requireActivity(), + object : EmptyCallback { + override fun onCallback() { + startActivityForResult( + LocalMediaActivity.getIntent( + requireContext(), + LocalMediaActivity.ChooseType.VIDEO, + 1, + "发视频帖" + ), BaseRichEditorActivity.INSERT_VIDEO_CODE + ) + NewLogUtils.logChooseMedia("view_media", "视频帖", "视频") + } + }) } mBinding.videoPosterPatchHint.setOnClickListener { startMediaStore() } mBinding.forumContainer.setOnClickListener { if (mViewModel.type == BbsType.OFFICIAL_BBS.value) { - startActivityForResult(GameActivity.getIntent(requireContext(), GameActivity.SELECT_GAME_TITLE), REQUEST_GAME_CODE) + startActivityForResult( + GameActivity.getIntent( + requireContext(), + GameActivity.SELECT_GAME_TITLE + ), REQUEST_GAME_CODE + ) } else { ChooseForumActivity.startChooseForumActivity(requireActivity()) NewLogUtils.logChooseForumPanelEnter("发视频帖") @@ -125,9 +142,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { } else 0L AppExecutor.uiExecutor.executeWithDelay(Runnable { ChooseActivityDialogFragment.show( - requireActivity() as AppCompatActivity, - ChooseActivityDialogFragment.ActivityLabelLocation.BBS_VIDEO, - mViewModel.selectActivityLabelEntity?.id) { + requireActivity() as AppCompatActivity, + ChooseActivityDialogFragment.ActivityLabelLocation.BBS_VIDEO, + mViewModel.selectActivityLabelEntity?.id + ) { mViewModel.selectActivityLabelEntity = it mBinding.activityTitle.text = it?.name mBinding.activityTitle.setTextColor(if (it != null) R.color.text_FA8500.toColor() else R.color.text_333333.toColor()) @@ -156,7 +174,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { } } mBinding.reprintUrlTv.setOnClickListener { - InputUrlDialogFragment.show(requireActivity() as AppCompatActivity, mBinding.reprintUrlTv.text.toString()) { + InputUrlDialogFragment.show( + requireActivity() as AppCompatActivity, + mBinding.reprintUrlTv.text.toString() + ) { mBinding.reprintUrlTv.text = it } } @@ -180,7 +201,12 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { setForumName() if (mIsForumSelectionDisabled && mViewModel.type == BbsType.GAME_BBS.value) { mBinding.forumContainer.isEnabled = false - mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null) + mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds( + null, + null, + null, + null + ) } } if (mViewModel.selectActivityLabelEntity != null) { @@ -188,11 +214,20 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { mBinding.activityTitle.setTextColor(if (mViewModel.selectActivityLabelEntity != null) R.color.text_FA8500.toColor() else R.color.text_333333.toColor()) } - PermissionHelper.checkStoragePermissionBeforeAction(requireActivity(), object : EmptyCallback { - override fun onCallback() { - startActivityForResult(LocalMediaActivity.getIntent(requireContext(), LocalMediaActivity.ChooseType.VIDEO, 1, "发视频帖"), BaseRichEditorActivity.INSERT_VIDEO_CODE) - } - }) + PermissionHelper.checkStoragePermissionBeforeAction( + requireActivity(), + object : EmptyCallback { + override fun onCallback() { + startActivityForResult( + LocalMediaActivity.getIntent( + requireContext(), + LocalMediaActivity.ChooseType.VIDEO, + 1, + "发视频帖" + ), BaseRichEditorActivity.INSERT_VIDEO_CODE + ) + } + }) } } } @@ -215,7 +250,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { toast("保存成功") requireActivity().finish() } else if (it.status == Status.ERROR) { - ErrorHelper.handleError(requireContext(), it.exception?.response()?.errorBody()?.string()) + ErrorHelper.handleError( + requireContext(), + it.exception?.response()?.errorBody()?.string() + ) } } mViewModel.postLiveData.observeNonNull(this) { @@ -233,7 +271,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { }, 1000) UploadManager.deleteUploadData(mVideoFileEntity?.path) } else if (it.status == Status.ERROR) { - ErrorHelper.handleError(requireContext(), it.exception?.response()?.errorBody()?.string()) + ErrorHelper.handleError( + requireContext(), + it.exception?.response()?.errorBody()?.string() + ) } } } @@ -248,7 +289,8 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { super.onActivityResult(requestCode, resultCode, data) if (data == null || resultCode != Activity.RESULT_OK) return if (requestCode == BaseRichEditorActivity.INSERT_VIDEO_CODE) { - val localVideoList = data.getParcelableArrayListExtra(LocalVideoEntity::class.java.name) + val localVideoList = + data.getParcelableArrayListExtra(LocalVideoEntity::class.java.name) ?: arrayListOf() if (localVideoList.isNotEmpty()) { initUpload(localVideoList[0].filePath, localVideoList[0].poster) @@ -258,7 +300,8 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { mBinding.videoPoster.setImageURI("file://$imagePath") mUpdatedPosterPath = imagePath ?: "" } else if (requestCode == ChooseForumActivity.CHOOSE_FORUM_REQUEST) { - val community = data.getParcelableExtra(EntranceUtils.KEY_COMMUNITY_DATA) + val community = + data.getParcelableExtra(EntranceUtils.KEY_COMMUNITY_DATA) mViewModel.communityEntity = community mViewModel.type = community?.type ?: "" if (mViewModel.type == BbsType.GAME_BBS.value) { @@ -272,7 +315,8 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { setForumName() } } else if (requestCode == REQUEST_CHOOSE_DRAFT) { - val draftEntity = data.getParcelableExtra(VideoDraftEntity::class.java.simpleName) + val draftEntity = + data.getParcelableExtra(VideoDraftEntity::class.java.simpleName) if (draftEntity != null) { mViewModel.videoDraft = draftEntity setVideoDraft() @@ -304,7 +348,14 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { mBinding.reprintUrlTv.isEnabled = false } if (mVideoFileEntity == null) { - mVideoFileEntity = VideoFileEntity("", videoPatch.url, videoPatch.poster, videoPatch.length, videoPatch.length, videoPatch.format) + mVideoFileEntity = VideoFileEntity( + "", + videoPatch.url, + videoPatch.poster, + videoPatch.length, + videoPatch.length, + videoPatch.format + ) } handleUploadSuccess(videoPatch.url) mBinding.deleteVideoIv.visibility = View.GONE @@ -314,8 +365,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { private fun setVideoDraft() { mViewModel.videoDraft?.let { if (it.bbsId.isNotEmpty() && it.game != null) { - mViewModel.communityEntity = CommunityEntity(it.bbsId, it.game?.name - ?: "", icon = it.game?.icon, iconSubscript = it.game?.iconSubscript) + mViewModel.communityEntity = CommunityEntity( + it.bbsId, it.game?.name + ?: "", icon = it.game?.icon, iconSubscript = it.game?.iconSubscript + ) mViewModel.gameEntity = it.game } mViewModel.gameEntity = it.game @@ -325,7 +378,8 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { if (it.tagActivityId.isNotEmpty() && it.tagActivityName.isNotEmpty()) { mBinding.activityTitle.text = it.tagActivityName mBinding.activityTitle.setTextColor(R.color.text_FA8500.toColor()) - mViewModel.selectActivityLabelEntity = ActivityLabelEntity(it.tagActivityId, it.tagActivityName) + mViewModel.selectActivityLabelEntity = + ActivityLabelEntity(it.tagActivityId, it.tagActivityName) } if (it.url.isNotEmpty()) { ImageUtils.display(mBinding.videoPoster, it.poster) @@ -350,7 +404,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { if (poster.isNotEmpty()) { ImageUtils.display(mBinding.videoPoster, poster) } else { - val thumbnail = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Images.Thumbnails.MINI_KIND) + val thumbnail = ThumbnailUtils.createVideoThumbnail( + videoPath, + MediaStore.Images.Thumbnails.MINI_KIND + ) mBinding.videoPoster.setImageBitmap(thumbnail) } @@ -400,20 +457,31 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { } } - mVideoFileEntity = VideoFileEntity(videoPath, null, poster, timeInSecond, videoFile.length(), format) + mVideoFileEntity = + VideoFileEntity(videoPath, null, poster, timeInSecond, videoFile.length(), format) createUploadTask(videoPath) } private fun createUploadTask(videoPath: String) { mBinding.uploadStatus.text = "视频上传中..." UploadManager.createUploadTask(videoPath, object : OnUploadListener { - override fun onProgressChanged(uploadFilePath: String, currentSize: Long, totalSize: Long, speed: Long) { + override fun onProgressChanged( + uploadFilePath: String, + currentSize: Long, + totalSize: Long, + speed: Long + ) { runOnUiThread { mBinding.uploadInfoContainer.visibility = View.VISIBLE mBinding.uploadStatus.text = "视频上传中..." mBinding.uploadSpeed.visibility = View.VISIBLE mBinding.pauseButton.visibility = View.VISIBLE - mBinding.uploadSpeed.text = (SpeedUtils.getSpeed(speed) + "预计还需" + SpeedUtils.getRemainTime(totalSize, currentSize, speed)) + mBinding.uploadSpeed.text = + (SpeedUtils.getSpeed(speed) + "预计还需" + SpeedUtils.getRemainTime( + totalSize, + currentSize, + speed + )) mBinding.uploadProgress.update(((360 * currentSize) / totalSize).toInt(), "") } } @@ -471,14 +539,21 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { if (mViewModel.communityEntity != null) { if (mViewModel.type == BbsType.GAME_BBS.value) { mBinding.chooseForumTv.text = mViewModel.communityEntity?.name - mBinding.forumIconView.displayGameIcon(mViewModel.communityEntity?.icon, mViewModel.communityEntity?.iconSubscript) + mBinding.forumIconView.displayGameIcon( + mViewModel.communityEntity?.icon, + mViewModel.communityEntity?.iconSubscript + ) setForumUI() } else if (mViewModel.type == BbsType.OFFICIAL_BBS.value) { if (mViewModel.gameEntity == null) { mBinding.chooseForumTv.text = "选择游戏" + mBinding.forumIconView.visibility = View.GONE } else { mBinding.chooseForumTv.text = mViewModel.gameEntity?.name - mBinding.forumIconView.displayGameIcon(mViewModel.gameEntity?.icon, mViewModel.gameEntity?.iconSubscript) + mBinding.forumIconView.displayGameIcon( + mViewModel.gameEntity?.icon, + mViewModel.gameEntity?.iconSubscript + ) setForumUI() } } @@ -495,7 +570,12 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { private fun setForumUI() { mBinding.forumIconView.visibility = View.VISIBLE mBinding.forumContainer.background = R.drawable.bg_shape_f5_radius_999.toDrawable() - mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds(null, null, R.drawable.ic_article_edit_choose_forum_arrow_gray.toDrawable(), null) + mBinding.chooseForumTv.setCompoundDrawablesWithIntrinsicBounds( + null, + null, + R.drawable.ic_article_edit_choose_forum_arrow_gray.toDrawable(), + null + ) mBinding.chooseForumTv.setTextColor(R.color.text_333333.toColor()) } @@ -510,7 +590,7 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { val title = mBinding.title.text.toString() val des = mBinding.videoDes.text.toString() if (mVideoFileEntity?.url.isNullOrEmpty()) return false - if (mViewModel.communityEntity == null) return false + if (mViewModel.videoPatch == null && mViewModel.communityEntity == null) return false if (title.isEmpty()) return false if (mViewModel.videoPatch != null && mViewModel.videoPatch?.title == title && mViewModel.videoPatch?.des == des) return false return true @@ -525,7 +605,10 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { } R.id.menu_draft -> { NewLogUtils.logVideoDraftClick() - startActivityForResult(VideoDraftActivity.getIntent(requireContext()), REQUEST_CHOOSE_DRAFT) + startActivityForResult( + VideoDraftActivity.getIntent(requireContext()), + REQUEST_CHOOSE_DRAFT + ) } } } @@ -546,26 +629,35 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { private fun startMediaStore() { try { - PermissionHelper.checkStoragePermissionBeforeAction(requireContext(), object : EmptyCallback { - override fun onCallback() { - var intent: Intent? = null - when { - mVideoFileEntity?.url?.isNotEmpty() == true -> { - val videoEntity = VideoEntity(length = mVideoFileEntity?.length - ?: 0, url = mVideoFileEntity?.url ?: "") - intent = PosterEditActivity.getIntentByVideo(requireContext(), videoEntity) - } - mVideoFileEntity?.path?.isNotEmpty() == true -> { - intent = PosterEditActivity.getIntentByPath(requireContext(), mVideoFileEntity?.url - ?: "") - } - else -> { - throwExceptionInDebug("video not found") + PermissionHelper.checkStoragePermissionBeforeAction( + requireContext(), + object : EmptyCallback { + override fun onCallback() { + var intent: Intent? = null + when { + mVideoFileEntity?.url?.isNotEmpty() == true -> { + val videoEntity = VideoEntity( + length = mVideoFileEntity?.length + ?: 0, url = mVideoFileEntity?.url ?: "" + ) + intent = PosterEditActivity.getIntentByVideo( + requireContext(), + videoEntity + ) + } + mVideoFileEntity?.path?.isNotEmpty() == true -> { + intent = PosterEditActivity.getIntentByPath( + requireContext(), mVideoFileEntity?.url + ?: "" + ) + } + else -> { + throwExceptionInDebug("video not found") + } } + startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP) } - startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP) - } - }) + }) } catch (e: Exception) { toast(R.string.media_image_hint) e.printStackTrace() @@ -578,18 +670,28 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { if (mViewModel.videoPatch == null && mViewModel.videoDraft == null) { if (mBinding.title.text.isNotEmpty() || mBinding.videoDes.text.isNotEmpty()) { - DialogUtils.showNewAlertDialog(requireContext(), "提示", "是否保存内容再退出?", "不保存", "保存并退出", Gravity.CENTER, true, { - requireActivity().finish() - }, { - verifyData(true) - }) + DialogUtils.showNewAlertDialog( + requireContext(), + "提示", + "是否保存内容再退出?", + "不保存", + "保存并退出", + Gravity.CENTER, + true, + { + requireActivity().finish() + }, + { + verifyData(true) + }) return true } } if (mViewModel.videoPatch != null && mViewModel.videoDraft == null) { return if (mViewModel.videoPatch?.title != mBinding.title.text.toString() || - mViewModel.videoPatch?.des != mBinding.videoDes.text.toString()) { + mViewModel.videoPatch?.des != mBinding.videoDes.text.toString() + ) { showBackDialog() true } else false @@ -600,7 +702,8 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { } private fun logButtonClick(event: String) { - val bbsType = if (mViewModel.type.isNotEmpty()) if (mViewModel.type == "game_bbs") "游戏论坛" else "综合论坛" else "" + val bbsType = + if (mViewModel.type.isNotEmpty()) if (mViewModel.type == "game_bbs") "游戏论坛" else "综合论坛" else "" val originalType = if (mBinding.originalTv.isChecked && !mBinding.reprintTv.isChecked) { "原创" } else if (!mBinding.originalTv.isChecked && mBinding.reprintTv.isChecked) { @@ -608,14 +711,17 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { } else { "未勾选" } - NewLogUtils.logPublishVideoClick(event, mViewModel.communityEntity?.id + NewLogUtils.logPublishVideoClick( + event, mViewModel.communityEntity?.id ?: "", bbsType, mViewModel.selectActivityLabelEntity?.name - ?: "", mBinding.videoDes.text.toString().count(), originalType) + ?: "", mBinding.videoDes.text.toString().count(), originalType + ) } private fun checkDraft(): Boolean { if (mViewModel.videoDraft != null && (mViewModel.videoDraft?.title != mBinding.title.text.toString() - || mViewModel.videoDraft?.des != mBinding.videoDes.text.toString())) { + || mViewModel.videoDraft?.des != mBinding.videoDes.text.toString()) + ) { showBackDialog() return true } @@ -623,18 +729,28 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { } private fun showBackDialog() { - DialogUtils.showNewAlertDialog(requireContext(), "提示", "是否保存修改内容用于下次编辑?", "不保存", "保存并退出", Gravity.CENTER, true, { - requireActivity().finish() - }, { - verifyData(true) - }) + DialogUtils.showNewAlertDialog( + requireContext(), + "提示", + "是否保存修改内容用于下次编辑?", + "不保存", + "保存并退出", + Gravity.CENTER, + true, + { + requireActivity().finish() + }, + { + verifyData(true) + }) } private fun verifyData(isDraft: Boolean) { if (ClickUtils.isFastDoubleClick()) return if (mViewModel.videoPatch == null) { if (!isDraft && mVideoFileEntity != null && - !File(mVideoFileEntity?.path ?: "").exists()) { + !File(mVideoFileEntity?.path ?: "").exists() + ) { toast("提交失败,视频文件不存在") handleFileNotFound() return @@ -655,18 +771,17 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { toast("请填写标题") return } - - if (!isDraft && !mBinding.originalTv.isChecked && !mBinding.reprintTv.isChecked) { + if (!isDraft && mViewModel.videoPatch == null && !mBinding.originalTv.isChecked && !mBinding.reprintTv.isChecked) { toast("请选择内容来源") return } - if (!isDraft && mViewModel.selectActivityLabelEntity != null && !mBinding.originalTv.isChecked) { + if (!isDraft && mViewModel.videoPatch == null && mViewModel.selectActivityLabelEntity != null && !mBinding.originalTv.isChecked) { toast("本次活动内容要求原创") return } - if (!isDraft && mBinding.reprintTv.isChecked && mBinding.reprintUrlTv.text.isEmpty()) { + if (!isDraft && mViewModel.videoPatch == null && mBinding.reprintTv.isChecked && mBinding.reprintUrlTv.text.isEmpty()) { toast("请填写转载来源") return } @@ -680,22 +795,21 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { mViewModel.videoPatch!! } else { ForumVideoEntity( - id = mViewModel.videoDraft?.id ?: "", - title = title.toString(), - des = des.toString(), - url = mVideoFileEntity?.url ?: "", - size = mVideoFileEntity?.size ?: 0, - format = mVideoFileEntity?.format ?: "", - length = mVideoFileEntity?.length ?: 0, - poster = mViewModel.videoDraft?.poster ?: "", - bbsId = mViewModel.communityEntity?.id ?: "", - type = mViewModel.type, - gameId = mViewModel.gameEntity?.id ?: mViewModel.communityEntity?.game?.id - ?: "", - original = if (mBinding.originalTv.isChecked) "yes" else if (mBinding.reprintTv.isChecked) "no" else "", - source = if (mBinding.reprintTv.isChecked) mBinding.reprintUrlTv.text.toString() else "", - tagActivityId = mViewModel.selectActivityLabelEntity?.id ?: "", - tagActivityName = mViewModel.selectActivityLabelEntity?.name ?: "" + id = mViewModel.videoDraft?.id ?: "", + title = title.toString(), + des = des.toString(), + url = mVideoFileEntity?.url ?: "", + size = mVideoFileEntity?.size ?: 0, + format = mVideoFileEntity?.format ?: "", + length = mVideoFileEntity?.length ?: 0, + poster = mViewModel.videoDraft?.poster ?: "", + bbsId = mViewModel.communityEntity?.id ?: "", + type = mViewModel.type, + gameId = mViewModel.gameEntity?.id ?: mViewModel.communityEntity?.game?.id ?: "", + original = if (mBinding.originalTv.isChecked) "yes" else if (mBinding.reprintTv.isChecked) "no" else "", + source = if (mBinding.reprintTv.isChecked) mBinding.reprintUrlTv.text.toString() else "", + tagActivityId = mViewModel.selectActivityLabelEntity?.id ?: "", + tagActivityName = mViewModel.selectActivityLabelEntity?.name ?: "" ) } if (mUpdatedPosterPath.isEmpty() && videoData.poster.isNotEmpty()) { @@ -709,10 +823,13 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { val posterPath = if (mUpdatedPosterPath.isNotEmpty()) { mUpdatedPosterPath } else { - val localVideoPoster = requireActivity().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".jpg" + val localVideoPoster = + requireActivity().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".jpg" try { - val bmp = ThumbnailUtils.createVideoThumbnail(mVideoFileEntity?.path - ?: "", MediaStore.Images.Thumbnails.MINI_KIND) + val bmp = ThumbnailUtils.createVideoThumbnail( + mVideoFileEntity?.path + ?: "", MediaStore.Images.Thumbnails.MINI_KIND + ) // bmp 可能为空 FileOutputStream(localVideoPoster).use { out -> bmp?.compress(Bitmap.CompressFormat.PNG, 100, out) @@ -724,7 +841,12 @@ class VideoPublishFragment : NormalFragment(), KeyboardHeightObserver { } localVideoPoster } - mViewModel.postVideoPosterAndContent(isDraft, videoData, posterPath, mVideoFileEntity?.path) + mViewModel.postVideoPosterAndContent( + isDraft, + videoData, + posterPath, + mVideoFileEntity?.path + ) } } diff --git a/app/src/main/java/com/gh/gamecenter/qa/video/publish/VideoPublishViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/video/publish/VideoPublishViewModel.kt index a3006c0d3e..04ca2fb5b5 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/video/publish/VideoPublishViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/video/publish/VideoPublishViewModel.kt @@ -62,14 +62,14 @@ class VideoPublishViewModel(application: Application) : AndroidViewModel(applica fun postContent(isDraft: Boolean, videoEntity: ForumVideoEntity, videoPath: String?) { when { - videoPatch != null -> { - patchVideo(JSONObject(GsonUtils.toJson(videoEntity)), videoEntity.id) - } isDraft -> { val draftData = JSONObject(videoEntity.toJson()).put("local_path", videoPath).toString() val body = RequestBody.create(MediaType.parse("application/json"), draftData) postDraft(body) } + videoPatch != null -> { + patchVideo(JSONObject(GsonUtils.toJson(videoEntity)), videoEntity.id) + } else -> { val requestJson = JSONObject(GsonUtils.toJson(videoEntity)) var videoHeight = 0 diff --git a/app/src/main/java/com/gh/gamecenter/receiver/InstallAndUninstallReceiver.java b/app/src/main/java/com/gh/gamecenter/receiver/InstallAndUninstallReceiver.java index e021a88405..e1bee7eed5 100644 --- a/app/src/main/java/com/gh/gamecenter/receiver/InstallAndUninstallReceiver.java +++ b/app/src/main/java/com/gh/gamecenter/receiver/InstallAndUninstallReceiver.java @@ -36,7 +36,7 @@ public class InstallAndUninstallReceiver extends BroadcastReceiver { InstallUtils.getInstance(context).removeInstall(packageName); PackageHelper.refreshLocalPackageList(); - String versionName = PackageUtils.getVersionByPackage(packageName); + String versionName = PackageUtils.getVersionNameByPackageName(packageName); EBPackage installEb = new EBPackage("安装", packageName, versionName); if (PackageUtils.isAppOnForeground(context)) { PackageObserver.onPackageChanged(installEb); @@ -71,7 +71,7 @@ public class InstallAndUninstallReceiver extends BroadcastReceiver { if (packageName.equals(context.getPackageName())) { DataUtils.onEvent(context, "软件更新", "更新完成"); } - String versionName = PackageUtils.getVersionByPackage(packageName); + String versionName = PackageUtils.getVersionNameByPackageName(packageName); EBPackage updateEb = new EBPackage("替换", packageName, versionName); EventBus.getDefault().post(new EBPackage("替换", packageName, versionName)); diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/OkHttpCacheInterceptor.java b/app/src/main/java/com/gh/gamecenter/retrofit/OkHttpCacheInterceptor.java index b74c2b3854..10c25999b6 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/OkHttpCacheInterceptor.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/OkHttpCacheInterceptor.java @@ -115,7 +115,7 @@ class OkHttpCacheInterceptor implements Interceptor { request = request.newBuilder() .addHeader("JNFJ", MetaUtil.getBase64EncodedIMEI()) .addHeader("CHANNEL", HaloApp.getInstance().getChannel()) - .addHeader("VERSION", PackageUtils.getVersionName()) + .addHeader("VERSION", PackageUtils.getGhVersionName()) .addHeader("OAID", HaloApp.getInstance().getOAID()) .removeHeader("User-Agent") .addHeader("User-Agent", HaloApp.getInstance().getUserAgent()) diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java index b8061e8ce6..c9f7977534 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java @@ -34,6 +34,8 @@ import com.gh.gamecenter.entity.GameColumnCollection; import com.gh.gamecenter.entity.GameDetailEntity; import com.gh.gamecenter.entity.GameDigestEntity; import com.gh.gamecenter.entity.GameEntity; +import com.gh.gamecenter.entity.GameGuidePopupEntity; +import com.gh.gamecenter.entity.ServerPublishEntity; import com.gh.gamecenter.entity.GameVideoInfo; import com.gh.gamecenter.entity.HelpCategoryEntity; import com.gh.gamecenter.entity.HelpEntity; @@ -386,14 +388,7 @@ public interface ApiService { * 获取开服表数据 */ @GET("games/servers") - Observable> getKaiFuData(@Query("filter") String type, @Query("page") int page); - - - /** - * 获取开服表数据 - */ - @GET("games/servers") - Observable> getGameServers(@Query("filter") String type, @Query("page") int page); + Single getGameServers(@Query("filter") String type); /** * 获取开测表信息 @@ -2605,6 +2600,12 @@ public interface ApiService { @POST("videos/{video_id}/comments/{comment_id}:inactivate") Single deleteVideoComment(@Path("video_id") String videoId, @Path("comment_id") String commentId); + /** + * 版主删除视频评论 + */ + @POST("communities/{community_id}/videos/{video_id}/comments/{comment_id}:hide") + Single moderatorsHideVideoComment(@Path("community_id") String communityId, @Path("video_id") String videoId, @Path("comment_id") String commentId); + /** * 获取已经预约成功的手机号码 */ @@ -3271,4 +3272,20 @@ public interface ApiService { @POST("bbses/activities/explore/tasks/explore:finish") Single postExplorerFinish(); + /** + * 获取引导浮窗 + */ + @GET("api_go/games/guide_popup") + Single getGameGuidePopup( + @Query("manufacture") String manufacture, + @Query("android_version") String systemVersion, + @Query("model") String model, + @Query("channel") String channel, + @Query("api_version") String apiVersion); + + /** + * 获取论坛热门搜索列表 + */ + @GET("bbses/hot_searches") + Observable> getHotSearches(); } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchDefaultHotAdapter.kt b/app/src/main/java/com/gh/gamecenter/search/SearchDefaultHotAdapter.kt index c3795e8f68..2e0106b3ce 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchDefaultHotAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchDefaultHotAdapter.kt @@ -15,10 +15,11 @@ import com.halo.assistant.HaloApp import com.lightgame.adapter.BaseRecyclerAdapter import kotlinx.android.synthetic.main.dialog_notification_hint.* -class SearchDefaultHotAdapter(context: Context, - val hotList: List?, - val callBack: (SettingsEntity.HotSearch) -> Unit) - : BaseRecyclerAdapter(context) { +class SearchDefaultHotAdapter( + context: Context, + val hotList: List?, + val callBack: (SettingsEntity.HotSearch) -> Unit +) : BaseRecyclerAdapter(context) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchDefaultHotViewHolder { val view = mLayoutInflater.inflate(R.layout.search_default_hot_item, parent, false) @@ -40,7 +41,8 @@ class SearchDefaultHotAdapter(context: Context, name.postDelayed({ name.isSelected = true }, 500) } val drawableRes = "ic_search_no_${position + 1}" - val drawableId = mContext.resources.getIdentifier(drawableRes, "drawable", mContext.packageName) + val drawableId = + mContext.resources.getIdentifier(drawableRes, "drawable", mContext.packageName) index.setImageDrawable(drawableId.toDrawable()) val textColor = when (position) { 0 -> R.color.text_ff5151.toColor() @@ -52,7 +54,7 @@ class SearchDefaultHotAdapter(context: Context, val labelIcon = when (hotSearch.recommendType) { "hot" -> R.drawable.ic_search_hot "new" -> R.drawable.ic_search_new - "surge" -> R.drawable.ic_search_surge + "surge", "rise" -> R.drawable.ic_search_surge else -> -1 } if (labelIcon != -1) { @@ -74,4 +76,5 @@ class SearchDefaultHotAdapter(context: Context, } } -class SearchDefaultHotViewHolder(val binding: SearchDefaultHotItemBinding) : BaseRecyclerViewHolder(binding.root) \ No newline at end of file +class SearchDefaultHotViewHolder(val binding: SearchDefaultHotItemBinding) : + BaseRecyclerViewHolder(binding.root) \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/security/BindPhoneViewModel.kt b/app/src/main/java/com/gh/gamecenter/security/BindPhoneViewModel.kt index 2473e3ed66..1c922aa1d7 100644 --- a/app/src/main/java/com/gh/gamecenter/security/BindPhoneViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/security/BindPhoneViewModel.kt @@ -109,7 +109,7 @@ class BindPhoneViewModel(application: Application) : AndroidViewModel(applicatio 400302 -> finishLiveData.postValue(false) - 403092 -> ToastUtils.showToast("邀请码错误") + 403092 -> ToastUtils.showToast("填写邀请码错误") else -> LoginUtils.outputErrorHint(context, code) } @@ -201,7 +201,7 @@ class BindPhoneViewModel(application: Application) : AndroidViewModel(applicatio 400302 -> finishLiveData.postValue(false) - 403092 -> ToastUtils.showToast("邀请码错误") + 403092 -> ToastUtils.showToast("填写邀请码错误") else -> LoginUtils.outputErrorHint(context, code) } diff --git a/app/src/main/java/com/gh/gamecenter/servers/GameServerTimeViewHolder.java b/app/src/main/java/com/gh/gamecenter/servers/GameServerTimeViewHolder.java index c919125fb7..a533cdcadc 100644 --- a/app/src/main/java/com/gh/gamecenter/servers/GameServerTimeViewHolder.java +++ b/app/src/main/java/com/gh/gamecenter/servers/GameServerTimeViewHolder.java @@ -21,6 +21,8 @@ public class GameServerTimeViewHolder extends BaseRecyclerViewHolder { public ImageView header; @BindView(R.id.kaifu_item_time_tv) public TextView time; + @BindView(R.id.emptyView) + public View emptyView; public GameServerTimeViewHolder(View itemView) { super(itemView); diff --git a/app/src/main/java/com/gh/gamecenter/servers/GameServersContentAdapter.java b/app/src/main/java/com/gh/gamecenter/servers/GameServersContentAdapter.java deleted file mode 100644 index 8d9dd8fa6b..0000000000 --- a/app/src/main/java/com/gh/gamecenter/servers/GameServersContentAdapter.java +++ /dev/null @@ -1,553 +0,0 @@ -package com.gh.gamecenter.servers; - -import android.content.Context; -import android.text.TextUtils; -import android.util.SparseArray; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.Nullable; -import androidx.collection.ArrayMap; -import androidx.recyclerview.widget.RecyclerView; - -import com.gh.base.OnRequestCallBackListener; -import com.gh.common.databind.BindingAdapters; -import com.gh.common.exposure.ExposureEvent; -import com.gh.common.exposure.ExposureSource; -import com.gh.common.exposure.ExposureType; -import com.gh.common.exposure.IExposable; -import com.gh.common.filter.RegionSettingHelper; -import com.gh.common.util.ApkActiveUtils; -import com.gh.common.util.DisplayUtils; -import com.gh.common.util.DownloadItemUtils; -import com.gh.common.util.EntranceUtils; -import com.gh.common.util.ExtensionsKt; -import com.gh.common.util.StringUtils; -import com.gh.common.util.UrlFilterUtils; -import com.gh.common.view.DrawableView; -import com.gh.download.DownloadManager; -import com.gh.gamecenter.GameDetailActivity; -import com.gh.gamecenter.R; -import com.gh.gamecenter.adapter.viewholder.FooterViewHolder; -import com.gh.gamecenter.adapter.viewholder.GameTestViewHolder; -import com.gh.gamecenter.entity.ApkEntity; -import com.gh.gamecenter.entity.GameEntity; -import com.gh.gamecenter.entity.ServerCalendarEntity; -import com.gh.gamecenter.retrofit.Response; -import com.gh.gamecenter.retrofit.RetrofitManager; -import com.lightgame.adapter.BaseRecyclerAdapter; -import com.lightgame.download.DownloadEntity; - - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import retrofit2.HttpException; - -/** - * Created by khy on 18/08/17. - */ -public class GameServersContentAdapter extends BaseRecyclerAdapter implements IExposable { - - private OnRequestCallBackListener mOnCallBackListener; - - private List mEntityList; - private ArrayMap> mLocationMap; - - private FooterCallback mFooterCallback; - - private String mDay; - private String mHour; - private String mTag; - private String mType; - - private String mEntrance; - - private List mExposureSourceList; - - private int mPage; - - private boolean mIsRemove; - private boolean mIsNetworkError; - private boolean mIsLoaded; - - public static final int VIEW_TYPE_TOP = 0; - public static final int VIEW_TYPE_ITEM = 1; - public static final int VIEW_TYPE_FOOTER = 2; - - private int mRealIndex = 0; - - private SparseArray mExposureEventArray = new SparseArray<>(); - - public GameServersContentAdapter(Context context, - OnRequestCallBackListener onCallBackListener, - FooterCallback footerCallback, - List exposureSources, - String entrance, - String type, - String day, - String hour, - String tag) { - super(context); - - mDay = day; - mHour = hour; - mType = type; - mTag = tag; - mPage = 1; - mEntrance = entrance; - - mOnCallBackListener = onCallBackListener; - mLocationMap = new ArrayMap<>(); - mEntityList = new ArrayList<>(); - - mFooterCallback = footerCallback; - - mExposureSourceList = exposureSources; - addList(); - } - - public void addList() { - mIsLoaded = false; - notifyItemChanged(getItemCount() - 1); - String filterQuery = UrlFilterUtils.getFilterQuery("day", mDay, "hour", mHour, "type", mType, "tag", mTag); - RetrofitManager.getInstance(mContext).getSensitiveApi() - .getGameServers(filterQuery, mPage) - .map(RegionSettingHelper.filterGame) - .map(ApkActiveUtils.filterMapperList) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Response>() { - @Override - public void onResponse(List response) { - for (int i = 0; i < response.size(); i++) { - // 初始化游戏状态 - GameEntity entity = response.get(i); - if (entity.getServerRemaining() != null) { - for (GameEntity remainingGame : entity.getServerRemaining()) { - remainingGame.setSequence(mRealIndex++); - } - } - entity.setSequence(mRealIndex++); - entity.setEntryMap(DownloadManager.getInstance(mContext).getEntryMap(entity.getName())); - ApkActiveUtils.filterHideApk(entity); // 过滤隐藏apk - - GameEntity fixedTopItem = null; - - // 当页面是由启动弹窗过来的第一或第二个页面的时候添加启动弹窗信息 - if (mEntrance.contains(EntranceUtils.ENTRANCE_WELCOME) - && ExtensionsKt.countOccurrences(mEntrance, "+") <= 1) { - entity.setWelcomeDialogInfoIfAvailable(); - } - - // 设置置顶部分 - if (i == 0) { - // 列表顶部,若有设置置顶应用就增加置顶头部 - if (mEntityList.size() == 0 && entity.getFixedTop()) { - fixedTopItem = new GameEntity(); - fixedTopItem.setFixedTopHint(true); - fixedTopItem.setFixedTop(true); - response.add(i, fixedTopItem); - i++; - } - } - - // 归零置顶游戏的开服时间避免找当前开服游戏时找到 - if (entity.getFixedTop()) { - if (entity.getServerEntity() == null) { - ServerCalendarEntity emptyCalendarEntity = new ServerCalendarEntity(); - emptyCalendarEntity.setTime(0); - entity.setServerEntity(emptyCalendarEntity); - } - entity.getServerEntity().setTime(0); - } - - // 设置时间断点 - if (i == 0) { - if (mEntityList.size() == 0) { // 列表page == 0 && position=0 默认添加时间断点 - GameEntity kaiFuTimeEntity = new GameEntity(); - kaiFuTimeEntity.setKaifuTimeHint(entity.getServerEntity().getTime()); - response.add(i, kaiFuTimeEntity); - i++; - } else { // 列表 page > 0 && position=0 与上一页最后一条对比 - GameEntity gameEntity = mEntityList.get(mEntityList.size() - 1); - ServerCalendarEntity serverEntity = gameEntity.getServerEntity(); - ServerCalendarEntity nextServerEntity = entity.getServerEntity(); - if (serverEntity == null || nextServerEntity == null) continue; - - long time = serverEntity.getTime(); - long nextTime = nextServerEntity.getTime(); - if (time != nextTime) { - GameEntity kaiFuTimeEntity = new GameEntity(); - kaiFuTimeEntity.setKaifuTimeHint(nextTime); - response.add(i, kaiFuTimeEntity); - i++; - } - } - } - - if (i < response.size() - 1) { - // 为置顶的项目添加第一个存在时间的游戏的开服时间 - if (fixedTopItem != null && fixedTopItem.getKaifuTimeHint() == null) { - fixedTopItem.setKaifuTimeHint(entity.getServerEntity().getTime()); - } - - ServerCalendarEntity serverEntity = entity.getServerEntity(); - ServerCalendarEntity nextServerEntity = response.get(i + 1).getServerEntity(); - if (serverEntity == null || nextServerEntity == null) continue; - - long time = serverEntity.getTime(); - long nextTime = nextServerEntity.getTime(); - - if (time != nextTime) { - GameEntity kaiFuTimeEntity = new GameEntity(); - kaiFuTimeEntity.setKaifuTimeHint(nextTime); - response.add(i + 1, kaiFuTimeEntity); - i++; - } - } - } - - mEntityList.addAll(response); - notifyItemRangeInserted(mEntityList.size() - response.size(), response.size()); - - if (response.size() < 20) { - mOnCallBackListener.loadDone(null); - mIsRemove = true; - notifyItemChanged(getItemCount() - 1); - } - - initLocationMap(); - - if (mEntityList.size() == 0) { - mOnCallBackListener.loadEmpty(); - } else { - mOnCallBackListener.loadDone(); - } - - mPage++; - mIsLoaded = true; - } - - - @Override - public void onFailure(HttpException e) { - super.onFailure(e); - mIsLoaded = true; - mRealIndex = 0; - if (mEntityList.size() == 0) { - mOnCallBackListener.loadError(); - } else { - mIsNetworkError = true; - notifyItemChanged(getItemCount() - 1); - } - } - }); - } - - private void initLocationMap() { - ArrayList list; - GameEntity gameEntity; - for (int i = 0, size = mEntityList.size(); i < size; i++) { - gameEntity = mEntityList.get(i); - if (gameEntity.getApk().size() != 0) { - for (ApkEntity apkEntity : gameEntity.getApk()) { - list = mLocationMap.get(apkEntity.getPackageName()); - if (list == null) { - list = new ArrayList<>(); - mLocationMap.put(apkEntity.getPackageName(), list); - } - list.add(i); - } - } - } - } - - @Override - public int getItemViewType(int position) { - if (mEntityList.size() == position) { - return VIEW_TYPE_FOOTER; - } - - GameEntity gameEntity = mEntityList.get(position); - if ((gameEntity.getKaifuTimeHint() != null && gameEntity.getKaifuTimeHint() != 0) || gameEntity.getFixedTopHint()) { - return VIEW_TYPE_TOP; - } - return VIEW_TYPE_ITEM; - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - if (viewType == VIEW_TYPE_FOOTER) { - return new FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)); - } else if (viewType == VIEW_TYPE_TOP) { - return new GameServerTimeViewHolder(mLayoutInflater.inflate(R.layout.kaifu_item_time, parent, false)); - } else { - return new GameTestViewHolder(mLayoutInflater.inflate(R.layout.game_test_item, parent, false)); - } - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - if (holder instanceof GameTestViewHolder) { - GameEntity gameEntity = mEntityList.get(position); - GameTestViewHolder viewHolder = (GameTestViewHolder) holder; - - String fixedTop = ""; - if (gameEntity.getServerEntity() != null && - gameEntity.getServerEntity().getTime() == 0) { - fixedTop = "热门开服"; - } - - ArrayList exposureSources = new ArrayList<>(); - mExposureSourceList.addAll(exposureSources); - - // 热门开服与其它的曝光路径区分开 - if (!TextUtils.isEmpty(fixedTop)) { - exposureSources.add(new ExposureSource(mType, fixedTop)); - } else { - String exposureSourceValue = getExposureSourceValue(); - - String displayType; - if ("开服".equals(mType)) { - displayType = "开服"; - } else { - displayType = "开测"; - } - exposureSources.add(new ExposureSource(displayType, exposureSourceValue)); - } - ExposureEvent exposureEvent = ExposureEvent.Companion.createEvent(gameEntity, - mExposureSourceList, - null, - ExposureType.EXPOSURE); - mExposureEventArray.put(position, exposureEvent); - - List serverRemaining = gameEntity.getServerRemaining(); - if (serverRemaining != null) { - viewHolder.extendContainer.setVisibility(View.VISIBLE); - viewHolder.extendContent.setText(("展开剩余" + serverRemaining.size() + "条开服信息")); - viewHolder.extendContent.setOnClickListener(v -> { - mergerRemainingData(gameEntity, position); - notifyItemChanged(position); - }); - } else { - viewHolder.extendContainer.setVisibility(View.GONE); - } - - if (position != 0 && getItemViewType(position - 1) == VIEW_TYPE_TOP) { - viewHolder.contentContainer.setPadding( - DisplayUtils.dip2px(16), DisplayUtils.dip2px(4), - DisplayUtils.dip2px(18), DisplayUtils.dip2px(8)); - } else if (getItemViewType(position + 1) == VIEW_TYPE_TOP) { - viewHolder.contentContainer.setPadding( - DisplayUtils.dip2px(16), DisplayUtils.dip2px(8), - DisplayUtils.dip2px(18), DisplayUtils.dip2px(16)); - } else { - viewHolder.contentContainer.setPadding( - DisplayUtils.dip2px(16), DisplayUtils.dip2px(8), - DisplayUtils.dip2px(18), DisplayUtils.dip2px(8)); - } - initGameTestViewHolder(gameEntity, viewHolder); - } else if (holder instanceof GameServerTimeViewHolder) { - GameEntity gameEntity = mEntityList.get(position); - if (gameEntity.getFixedTopHint()) { - ((GameServerTimeViewHolder) holder).header.setImageResource(R.drawable.ic_kaifu_hot); - ((GameServerTimeViewHolder) holder).time.setText("热门开服"); - } else { - SimpleDateFormat dateFm = new SimpleDateFormat("yyyy-MM-dd (EEEE) HH:mm", Locale.CHINA); - ((GameServerTimeViewHolder) holder).header.setImageResource(R.drawable.kaifu_time_icon); - ((GameServerTimeViewHolder) holder).time.setText(dateFm.format(gameEntity.getKaifuTimeHint() * 1000)); - } - } else if (holder instanceof FooterViewHolder) { - FooterViewHolder viewHolder = (FooterViewHolder) holder; - initFooterViewHolder(viewHolder); - } - } - - @Override - public int getItemCount() { - if (mEntityList.size() == 0) { - return 0; - } - return mEntityList.size() + 1; - } - - private String getExposureSourceValue() { - StringBuilder sb = new StringBuilder(); - if ("开服".equals(mType)) { - if ("today".equals(mDay)) { - sb.append("今日"); - sb.append(mType); - } else if ("after".equals(mDay)) { - sb.append("后续"); - sb.append(mType); - } else if ("tomorrow".equals(mDay)) { - sb.append("明日"); - sb.append(mType); - } else { - sb.append("全部"); - sb.append(mType); - } - if (mHour != null) { - sb.append(mHour); - sb.append("时"); - } - if (mTag != null) { - sb.append("+"); - sb.append(mTag.replace("-", "+")); - } - } else { - if ("today".equals(mDay)) { - sb.append("今日开测"); - } else if ("after".equals(mDay)) { - sb.append("后续开测"); - } else if ("tomorrow".equals(mDay)) { - sb.append("明日开测"); - } else { - sb.append("全部开测"); - } - sb.append("+"); - if ("开测".equals(mType)) { - sb.append("全部"); - } else { - sb.append(mType); - } - } - return sb.toString(); - } - - void initGameTestViewHolder(final GameEntity gameEntity, final GameTestViewHolder viewHolder) { - viewHolder.gameName.setText(gameEntity.getName()); - BindingAdapters.setGame(viewHolder.gameThumb, gameEntity); - - if (gameEntity.getServerEntity() == null || TextUtils.isEmpty(gameEntity.getServerEntity().getRemark())) { - viewHolder.gameTestTime.setVisibility(View.GONE); - } else { - viewHolder.gameTestTime.setVisibility(View.VISIBLE); - viewHolder.gameTestTime.setText(gameEntity.getServerEntity().getRemark()); - viewHolder.gameTestType.setBackground(DrawableView.getServerDrawableBySource(R.color.tag_orange)); - } - - if (gameEntity.getFixedTop()) { - String tag = "今日开服"; - viewHolder.gameTestType.setVisibility(View.VISIBLE); - viewHolder.gameTestType.setText(tag); - viewHolder.gameTestType.setBackground(DrawableView.getServerDrawableBySource(R.color.tag_yellow)); - } else { - String type = gameEntity.getServerEntity().getType(); - if (TextUtils.isEmpty(type)) { - viewHolder.gameTestType.setVisibility(View.GONE); - } else if (("不删档内测".equals(type) || "删档内测".equals(type) || "公测".equals(type)) - && TextUtils.isEmpty(gameEntity.getServerEntity().getNote())) { - if (!TextUtils.isEmpty(gameEntity.getServerEntity().getNote())) { - String testType; - if ("公测".equals(type)) { - testType = gameEntity.getServerEntity().getType() + ":" + gameEntity.getServerEntity().getNote(); - } else { - testType = gameEntity.getServerEntity().getNote(); - } - viewHolder.gameTestType.setText(testType); - viewHolder.gameTestType.setBackground(DrawableView.getServerDrawableBySource(R.color.tag_yellow)); - viewHolder.gameTestType.setVisibility(View.VISIBLE); - } else { - viewHolder.gameTestType.setVisibility(View.GONE); - } - } else { - viewHolder.gameTestType.setText(gameEntity.getServerEntity().getNote()); - viewHolder.gameTestType.setBackground(DrawableView.getServerDrawableBySource(R.color.tag_yellow)); - viewHolder.gameTestType.setVisibility(View.VISIBLE); - } - } - - gameEntity.getApk(); - if (gameEntity.getApk().isEmpty()) { - viewHolder.gameDes.setText(gameEntity.getBrief()); - } else { - viewHolder.gameDes.setText(String.format("%s %s", gameEntity.getApk().get(0).getSize(), gameEntity.getBrief())); - } - - DownloadItemUtils.setOnClickListener(mContext, - viewHolder.gameDownloadBtn, gameEntity, viewHolder.getAdapterPosition(), GameServersContentAdapter.this, - StringUtils.buildString(mEntrance, "+(开服表[", String.valueOf(viewHolder.getAdapterPosition()), "])"), - StringUtils.buildString("开服表:", gameEntity.getName()), - mExposureEventArray.get(viewHolder.getAdapterPosition())); - - DownloadItemUtils.updateItem(mContext, gameEntity, viewHolder, true); - - if (gameEntity.getFixedTop()) { - viewHolder.itemView.setOnClickListener(v -> - GameDetailActivity.startGameDetailActivity(mContext, - gameEntity, - StringUtils.buildString(mEntrance, "+(开服表[", String.valueOf(viewHolder.getAdapterPosition()), "])"), - mExposureEventArray.get(viewHolder.getAdapterPosition()))); - } else { - viewHolder.itemView.setOnClickListener(v -> { - GameDetailActivity.startGameDetailActivity(mContext, gameEntity, - StringUtils.buildString(mEntrance, "+(开服表[", String.valueOf(viewHolder.getAdapterPosition()), "])"), - mExposureEventArray.get(viewHolder.getAdapterPosition())); - - }); - } - } - - private void mergerRemainingData(GameEntity entity, int position) { - List serverRemaining = entity.getServerRemaining(); - if (serverRemaining == null) return; - ArrayMap entryMap = entity.getEntryMap(); - if (entryMap.size() > 0) { - for (GameEntity gameEntity : serverRemaining) gameEntity.setEntryMap(entryMap); - } - mEntityList.addAll(position + 1, serverRemaining); - entity.setServerRemaining(null); - initLocationMap(); - notifyItemRangeInserted(position + 1, serverRemaining.size()); - } - - private void initFooterViewHolder(FooterViewHolder viewHolder) { - viewHolder.initFooterViewHolder(!mIsLoaded, mIsNetworkError, mIsRemove, R.string.load_over_with_click_hint, v -> { - if (mIsNetworkError) { - mIsNetworkError = false; - notifyItemChanged(getItemCount() - 1); - addList(); - } else { - mFooterCallback.onClick(); - } - }); - } - - public boolean isLoaded() { - return mIsLoaded; - } - - public boolean isRemove() { - return mIsRemove; - } - - public List getDataList() { - return mEntityList; - } - - public ArrayMap> getLocationMap() { - return mLocationMap; - } - - @Nullable - @Override - public ExposureEvent getEventByPosition(int pos) { - return mExposureEventArray.get(pos); - } - - @Nullable - @Override - public List getEventListByPosition(int pos) { - return null; - } - - interface FooterCallback { - void onClick(); - } -} diff --git a/app/src/main/java/com/gh/gamecenter/servers/GameServersContentAdapter.kt b/app/src/main/java/com/gh/gamecenter/servers/GameServersContentAdapter.kt new file mode 100644 index 0000000000..45ad2b3981 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/servers/GameServersContentAdapter.kt @@ -0,0 +1,382 @@ +package com.gh.gamecenter.servers + +import android.content.Context +import android.text.TextUtils +import android.util.SparseArray +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.databind.BindingAdapters +import com.gh.common.exposure.ExposureEvent +import com.gh.common.exposure.ExposureEvent.Companion.createEvent +import com.gh.common.exposure.ExposureSource +import com.gh.common.exposure.ExposureType +import com.gh.common.exposure.IExposable +import com.gh.common.util.DisplayUtils +import com.gh.common.util.DownloadItemUtils +import com.gh.common.util.StringUtils +import com.gh.common.util.toColor +import com.gh.common.view.DrawableView.getServerDrawableBySource +import com.gh.gamecenter.GameDetailActivity +import com.gh.gamecenter.R +import com.gh.gamecenter.adapter.viewholder.FooterViewHolder +import com.gh.gamecenter.adapter.viewholder.GameTestViewHolder +import com.gh.gamecenter.baselist.LoadStatus +import com.gh.gamecenter.entity.GameEntity +import com.lightgame.adapter.BaseRecyclerAdapter +import java.text.SimpleDateFormat +import java.util.* + +class GameServersContentAdapter(context: Context, + private val mViewModel: GameServersContentViewModel, + private val mEntrance: String) + : BaseRecyclerAdapter(context), IExposable { + + var mDataList = arrayListOf() + private val mExposureEventArray: SparseArray = SparseArray() + private val mExposureSourceList = arrayListOf() + private var mPrevIsOver = false + private var mPrevIsNetworkError = false + private var mPrevIsLoading = false + private var mNextIsOver = false + private var mNextIsNetworkError = false + private var mNextIsLoading = false + private var mIsShowPullDownTip = false + + fun submitList(updateData: ArrayList, isShowPullDownTip: Boolean, isDown: Boolean = false, downSize: Int = 0) { + mDataList = updateData + mIsShowPullDownTip = isShowPullDownTip + if (isDown) { + notifyItemRangeInserted(0, downSize) + } else { + notifyDataSetChanged() + } + } + + fun resetStatus() { + mPrevIsOver = false + mPrevIsNetworkError = false + mPrevIsLoading = false + mNextIsOver = false + mNextIsNetworkError = false + mNextIsLoading = false + } + + fun loadChange(pair: Pair) { + if (pair.first == "down") { + when (pair.second) { + LoadStatus.INIT -> { + mPrevIsLoading = true + mPrevIsOver = false + mPrevIsNetworkError = false + } + LoadStatus.INIT_OVER -> { + mPrevIsLoading = false + mPrevIsOver = true + mPrevIsNetworkError = false + } + LoadStatus.INIT_LOADED, LoadStatus.INIT_EMPTY -> { + mPrevIsLoading = false + mPrevIsOver = false + mPrevIsNetworkError = false + } + LoadStatus.INIT_FAILED -> { + mPrevIsLoading = false + mPrevIsOver = false + mPrevIsNetworkError = true + } + else -> {} + } + notifyItemChanged(0) + } else { + when (pair.second) { + LoadStatus.INIT -> { + mNextIsLoading = true + mNextIsOver = false + mNextIsNetworkError = false + } + LoadStatus.INIT_OVER -> { + mNextIsLoading = false + mNextIsOver = true + mNextIsNetworkError = false + } + LoadStatus.INIT_LOADED, LoadStatus.INIT_EMPTY -> { + mNextIsLoading = false + mNextIsOver = false + mNextIsNetworkError = false + } + LoadStatus.INIT_FAILED -> { + mNextIsLoading = false + mNextIsOver = false + mNextIsNetworkError = true + } + else -> {} + } + notifyItemChanged(itemCount - 1) + } + } + + override fun getItemCount() = if (mDataList.size == 0) 0 else mDataList.size + 2 + + override fun getItemViewType(position: Int): Int { + if (position == mDataList.size + 1 || position == 0) { + return VIEW_TYPE_FOOTER + } + + val gameEntity = mDataList[position - 1] + return if (gameEntity.kaifuTimeHint != null && gameEntity.kaifuTimeHint != 0L || gameEntity.fixedTopHint!!) { + VIEW_TYPE_TOP + } else VIEW_TYPE_ITEM + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return when (viewType) { + VIEW_TYPE_FOOTER -> FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)) + VIEW_TYPE_TOP -> GameServerTimeViewHolder(mLayoutInflater.inflate(R.layout.kaifu_item_time, parent, false)) + else -> GameTestViewHolder(mLayoutInflater.inflate(R.layout.game_test_item, parent, false)) + } + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (holder) { + is GameTestViewHolder -> { + val gameEntity = mDataList[position - 1] + + var fixedTop = "" + if (gameEntity.serverEntity != null && gameEntity.serverEntity!!.getTime() == 0L) { + fixedTop = "热门开服" + } + + val exposureSources = ArrayList() + mExposureSourceList.addAll(exposureSources) + + // 热门开服与其它的曝光路径区分开 + if (!TextUtils.isEmpty(fixedTop)) { + exposureSources.add(ExposureSource("开服", fixedTop)) + } else { + val exposureSourceValue: String = getExposureSourceValue() + exposureSources.add(ExposureSource("开服", exposureSourceValue)) + } + val exposureEvent = createEvent(gameEntity, + mExposureSourceList, + null, + ExposureType.EXPOSURE) + mExposureEventArray.put(position, exposureEvent) + + val serverRemaining = gameEntity.serverRemaining + if (serverRemaining != null) { + holder.extendContainer.visibility = View.VISIBLE + holder.extendContent.text = "展开剩余" + serverRemaining.size + "条开服信息" + holder.extendContent.setOnClickListener { + mViewModel.mergerRemainingData(gameEntity, position) + notifyItemChanged(position) + } + } else { + holder.extendContainer.visibility = View.GONE + } + + if (position != 0 && getItemViewType(position - 1) == VIEW_TYPE_TOP) { + holder.contentContainer.setPadding( + DisplayUtils.dip2px(16f), DisplayUtils.dip2px(4f), + DisplayUtils.dip2px(18f), DisplayUtils.dip2px(8f)) + } else if (getItemViewType(position + 1) == VIEW_TYPE_TOP) { + holder.contentContainer.setPadding( + DisplayUtils.dip2px(16f), DisplayUtils.dip2px(8f), + DisplayUtils.dip2px(18f), DisplayUtils.dip2px(16f)) + } else { + holder.contentContainer.setPadding( + DisplayUtils.dip2px(16f), DisplayUtils.dip2px(8f), + DisplayUtils.dip2px(18f), DisplayUtils.dip2px(8f)) + } + initGameTestViewHolder(gameEntity, holder) + } + + is GameServerTimeViewHolder -> { + if (mIsShowPullDownTip && position == 1) { + holder.emptyView.visibility = View.VISIBLE + } else { + holder.emptyView.visibility = View.GONE + } + val gameEntity = mDataList[position - 1] + if (gameEntity.fixedTopHint!!) { + holder.header.setImageResource(R.drawable.ic_kaifu_hot) + holder.time.text = "热门开服" + } else { + val dateFm = SimpleDateFormat("yyyy-MM-dd (EEEE) HH:mm", Locale.CHINA) + holder.header.setImageResource(R.drawable.kaifu_time_icon) + holder.time.text = dateFm.format(gameEntity.kaifuTimeHint!! * 1000) + } + } + + is FooterViewHolder -> { + holder.run { + itemView.setBackgroundColor(R.color.text_F5F5F5.toColor()) + if (position == 0) { + when { + mPrevIsNetworkError -> { + loading.visibility = View.GONE + hint.setText(R.string.loading_failed_retry) + itemView.isClickable = true +// itemView.setOnClickListener(onClickListener) + } + mPrevIsOver -> { + loading.visibility = View.GONE + hint.setText(R.string.load_over_hint) + itemView.isClickable = true +// itemView.setOnClickListener(onClickListener) + } + else -> { + loading.visibility = View.VISIBLE + hint.setText(R.string.loading) + itemView.isClickable = false + } + } + } else { + when { + mNextIsNetworkError -> { + loading.visibility = View.GONE + hint.setText(R.string.loading_failed_retry) + itemView.isClickable = true +// itemView.setOnClickListener(onClickListener) + } + mNextIsOver -> { + loading.visibility = View.GONE + hint.setText(R.string.load_over_hint) + itemView.isClickable = true +// itemView.setOnClickListener(onClickListener) + } + else -> { + loading.visibility = View.VISIBLE + hint.setText(R.string.loading) + itemView.isClickable = false + } + } + } + } + } + } + } + + private fun initGameTestViewHolder(gameEntity: GameEntity, viewHolder: GameTestViewHolder) { + viewHolder.gameName.text = gameEntity.name + BindingAdapters.setGame(viewHolder.gameThumb, gameEntity) + + if (gameEntity.serverEntity == null || TextUtils.isEmpty(gameEntity.serverEntity!!.remark)) { + viewHolder.gameTestTime.visibility = View.GONE + } else { + viewHolder.gameTestTime.visibility = View.VISIBLE + viewHolder.gameTestTime.text = gameEntity.serverEntity!!.remark + viewHolder.gameTestType.background = getServerDrawableBySource(R.color.tag_orange) + } + + if (gameEntity.fixedTop!!) { + val tag = "今日开服" + viewHolder.gameTestType.visibility = View.VISIBLE + viewHolder.gameTestType.text = tag + viewHolder.gameTestType.background = getServerDrawableBySource(R.color.tag_yellow) + } else { + val type = gameEntity.serverEntity!!.type + if (TextUtils.isEmpty(type)) { + viewHolder.gameTestType.visibility = View.GONE + } else if (("不删档内测" == type || "删档内测" == type || "公测" == type) + && TextUtils.isEmpty(gameEntity.serverEntity!!.getNote())) { + if (!TextUtils.isEmpty(gameEntity.serverEntity!!.getNote())) { + val testType: String? = if ("公测" == type) { + gameEntity.serverEntity!!.type + ":" + gameEntity.serverEntity!!.getNote() + } else { + gameEntity.serverEntity!!.getNote() + } + viewHolder.gameTestType.text = testType + viewHolder.gameTestType.background = getServerDrawableBySource(R.color.tag_yellow) + viewHolder.gameTestType.visibility = View.VISIBLE + } else { + viewHolder.gameTestType.visibility = View.GONE + } + } else { + viewHolder.gameTestType.text = gameEntity.serverEntity!!.getNote() + viewHolder.gameTestType.background = getServerDrawableBySource(R.color.tag_yellow) + viewHolder.gameTestType.visibility = View.VISIBLE + } + } + + gameEntity.getApk() + if (gameEntity.getApk().isEmpty()) { + viewHolder.gameDes.text = gameEntity.brief + } else { + viewHolder.gameDes.text = String.format("%s %s", gameEntity.getApk()[0].size, gameEntity.brief) + } + + DownloadItemUtils.setOnClickListener(mContext, + viewHolder.gameDownloadBtn, gameEntity, viewHolder.adapterPosition, this@GameServersContentAdapter, + StringUtils.buildString(mEntrance, "+(开服表[", viewHolder.adapterPosition.toString(), "])"), + StringUtils.buildString("开服表:", gameEntity.name), + mExposureEventArray.get(viewHolder.adapterPosition)) + + DownloadItemUtils.updateItem(mContext, gameEntity, viewHolder, true) + + if (gameEntity.fixedTop!!) { + viewHolder.itemView.setOnClickListener { + GameDetailActivity.startGameDetailActivity(mContext, + gameEntity, + StringUtils.buildString(mEntrance, "+(开服表[", viewHolder.adapterPosition.toString(), "])"), + mExposureEventArray.get(viewHolder.adapterPosition)) + } + } else { + viewHolder.itemView.setOnClickListener { + GameDetailActivity.startGameDetailActivity(mContext, gameEntity, + StringUtils.buildString(mEntrance, "+(开服表[", viewHolder.adapterPosition.toString(), "])"), + mExposureEventArray.get(viewHolder.adapterPosition)) + } + } + } + + private fun getExposureSourceValue(): String { + val sb = StringBuilder() + when (mViewModel.day) { + "today" -> { + sb.append("今日") + } + "after" -> { + sb.append("后续") + } + "tomorrow" -> { + sb.append("明日") + } + else -> { + sb.append("全部") + } + } + sb.append("开服") + if (mViewModel.hour != null) { + sb.append(mViewModel.hour) + sb.append("时") + } + if (mViewModel.tags != null) { + sb.append("+") + sb.append(mViewModel.tags!!.replace("-", "+")) + } + return sb.toString() + } + + fun isPrevLoading() = mPrevIsLoading + + fun isPrevOver() = mPrevIsOver + + fun isNextLoading() = mNextIsLoading + + fun isNextOver() = mNextIsOver + + override fun getEventByPosition(pos: Int): ExposureEvent? { + return mExposureEventArray[pos] + } + + override fun getEventListByPosition(pos: Int): List? { + return null + } + + companion object { + const val VIEW_TYPE_TOP = 0 + const val VIEW_TYPE_ITEM = 1 + const val VIEW_TYPE_FOOTER = 2 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/servers/GameServersContentFragment.kt b/app/src/main/java/com/gh/gamecenter/servers/GameServersContentFragment.kt index 0e0ba38cf5..5264ec8614 100644 --- a/app/src/main/java/com/gh/gamecenter/servers/GameServersContentFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/servers/GameServersContentFragment.kt @@ -3,6 +3,7 @@ package com.gh.gamecenter.servers import android.os.Bundle import android.view.View import android.view.ViewGroup +import android.view.ViewTreeObserver import android.widget.RelativeLayout import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.LinearLayoutManager @@ -10,18 +11,15 @@ import androidx.recyclerview.widget.RecyclerView import androidx.viewpager.widget.ViewPager import com.gh.base.fragment.BaseFragment import com.gh.common.exposure.ExposureListener -import com.gh.common.exposure.ExposureSource -import com.gh.common.util.DialogUtils -import com.gh.common.util.DownloadItemUtils -import com.gh.common.util.EntranceUtils +import com.gh.common.util.* import com.gh.common.util.MtaHelper.onEvent import com.gh.common.xapk.XapkInstaller import com.gh.common.xapk.XapkUnzipStatus import com.gh.download.DownloadManager import com.gh.gamecenter.R +import com.gh.gamecenter.baselist.LoadStatus import com.gh.gamecenter.databinding.FragmentKaifuContentBinding import com.gh.gamecenter.eventbus.EBDownloadStatus -import com.gh.gamecenter.servers.GameServersContentAdapter.FooterCallback import com.lightgame.download.DataWatcher import com.lightgame.download.DownloadEntity import org.greenrobot.eventbus.Subscribe @@ -38,11 +36,10 @@ class GameServersContentFragment : BaseFragment() { private var mLayoutManager: LinearLayoutManager? = null private var mExposureListener: ExposureListener? = null private var mLlParams: RelativeLayout.LayoutParams? = null - - private var mDay: String? = null - private var mHour: String? = null - private var mTags: String? = null - private var mType: String? = null + private var mViewModel: GameServersContentViewModel? = null + private var mShowPullDownTipFlag = true + private var mHidePullDownTipFlag = true + private var mIsRefresh = false private var mIsRefreshDownload = true @@ -50,10 +47,10 @@ class GameServersContentFragment : BaseFragment() { private val dataWatcher: DataWatcher = object : DataWatcher() { override fun onDataChanged(downloadEntity: DownloadEntity) { - val locationList = mAdapter?.locationMap?.get(downloadEntity.packageName) + val locationList = mViewModel?.locationMap?.get(downloadEntity.packageName) if (locationList != null && mIsRefreshDownload) { for (location in locationList) { - mAdapter?.dataList?.get(location)?.let { gameEntity -> + mViewModel?.listLiveData?.value?.second?.safelyGetInRelease(location)?.let { gameEntity -> DownloadItemUtils.processDate(context, gameEntity, downloadEntity, mAdapter, location) } } @@ -78,50 +75,85 @@ class GameServersContentFragment : BaseFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - mType = arguments?.getString(EntranceUtils.KEY_TYPE, "开服") mLlParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) (mBinding?.recyclerView?.itemAnimator as DefaultItemAnimator?)?.supportsChangeAnimations = false mBinding?.recyclerView?.layoutManager = LinearLayoutManager(requireContext()).apply { mLayoutManager = this } - mAdapter = GameServersContentAdapter( - requireContext(), - this, - FooterCallback { scrollToTop() }, - arrayListOf().apply { - arguments?.getParcelable(EntranceUtils.KEY_EXPOSURE_SOURCE)?.let { - add(it) - } - add(ExposureSource("开服表", "")) - }, - mEntrance, - mType, - mDay, - mHour, - mTags) + mViewModel = viewModelProvider() +// mViewModel?.type = arguments?.getString(EntranceUtils.KEY_TYPE, "开服") + mViewModel?.listLiveData?.observe(this, androidx.lifecycle.Observer { + if (it.second.isEmpty()) return@Observer + + if (it.first == "down") { + mAdapter?.submitList(it.second, isShowPullDownTip = false, isDown = true, downSize = it.third) + mBinding?.kaifuTimeContainer?.kaifuItemTime?.visibility = View.VISIBLE + } else { + mAdapter?.submitList(it.second, mShowPullDownTipFlag || mBinding?.pullDownTip?.visibility == View.VISIBLE) + } + showPullDownTip() + if (mIsRefresh) { + mIsRefresh = false + handleHeaderView(it.second[0].kaifuTimeHint ?: 0L) + } + }) + mViewModel?.loadStatusLiveData?.observe(this, androidx.lifecycle.Observer { + when (it.second) { + LoadStatus.INIT_LOADED, LoadStatus.INIT_OVER -> loadDone() + LoadStatus.INIT_EMPTY -> loadEmpty() + LoadStatus.INIT_FAILED -> loadError() + else -> {} + } + mAdapter?.loadChange(it) + }) + mAdapter = GameServersContentAdapter(requireContext(), mViewModel!!, mEntrance) mExposureListener = ExposureListener(this, mAdapter!!) mBinding?.recyclerView?.addOnScrollListener(mExposureListener!!) mBinding?.recyclerView?.adapter = mAdapter mBinding?.recyclerView?.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { super.onScrollStateChanged(recyclerView, newState) - if (mLayoutManager?.findLastVisibleItemPosition() == mAdapter!!.itemCount - 1 + mBinding?.recyclerView?.run { + if (translationY != 0F) { + animate().translationY(0F).setDuration(200).start() + hidePullDownTip() + mBinding?.kaifuTimeContainer?.kaifuItemTime?.visibility = View.GONE + } + } + + if (mLayoutManager?.findFirstVisibleItemPosition() == 0 && newState == RecyclerView.SCROLL_STATE_IDLE - && !mAdapter!!.isRemove - && mAdapter!!.isLoaded) { - mAdapter?.addList() + && !mAdapter!!.isPrevOver() + && !mAdapter!!.isPrevLoading()) { + mViewModel?.run { + mAdapter?.loadChange(Pair("down", LoadStatus.INIT)) + loadData(action = "down") + } + } else if (mLayoutManager?.findLastVisibleItemPosition() == mAdapter!!.itemCount - 1 + && newState == RecyclerView.SCROLL_STATE_IDLE + && !mAdapter!!.isNextOver() + && !mAdapter!!.isNextLoading()) { + mViewModel?.run { + loadData(action = "up") + } } mIsRefreshDownload = newState == RecyclerView.SCROLL_STATE_IDLE } override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) + if (dy != 0) hidePullDownTip() + if (mLayoutManager?.findFirstVisibleItemPosition() == 0) { + mBinding?.kaifuTimeContainer?.kaifuItemTime?.visibility = View.GONE + } else if (dy != 0) { + mBinding?.kaifuTimeContainer?.kaifuItemTime?.visibility = View.VISIBLE + } val position = mLayoutManager?.findFirstVisibleItemPosition() ?: 0 - if (RecyclerView.NO_POSITION == position) return - val dataList = mAdapter?.dataList - val gameEntity = dataList?.get(position + 1) + val dataList = mViewModel?.listLiveData?.value?.second + if (position == RecyclerView.NO_POSITION || position < 1 || dataList?.isEmpty() == true) return + val gameEntity = dataList?.get(position - 1) val kaifuTimeHint = gameEntity?.kaifuTimeHint // 悬挂的文案 - val timeGameEntity = dataList?.get(position) + val timeGameEntity = dataList?.get(position - 1) val fixedTopHint = timeGameEntity?.fixedTop ?: false if (fixedTopHint) { mBinding?.kaifuTimeContainer?.kaifuItemTimeTv @@ -147,9 +179,9 @@ class GameServersContentFragment : BaseFragment() { // 悬挂界面移动 if (kaifuTimeHint != null && kaifuTimeHint != 0L) { - val buttom = mLayoutManager?.findViewByPosition(position)?.bottom ?: 0 - if (buttom <= mBinding?.kaifuTimeContainer?.kaifuItemTime?.height ?: 0) { - mLlParams?.topMargin = buttom - (mBinding?.kaifuTimeContainer?.kaifuItemTime?.height + val bottom = mLayoutManager?.findViewByPosition(position)?.bottom ?: 0 + if (bottom <= mBinding?.kaifuTimeContainer?.kaifuItemTime?.height ?: 0) { + mLlParams?.topMargin = bottom - (mBinding?.kaifuTimeContainer?.kaifuItemTime?.height ?: 0) } else { mLlParams?.topMargin = 0 @@ -170,14 +202,85 @@ class GameServersContentFragment : BaseFragment() { mBinding?.noConnectionContainer?.root?.setOnClickListener { onRefreshPage() } + + mBinding?.recyclerView?.viewTreeObserver?.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + mLayoutManager?.scrollToPosition(1) + if (mLayoutManager?.findFirstVisibleItemPosition() == 1) { + mBinding?.recyclerView?.viewTreeObserver?.removeOnGlobalLayoutListener(this) + } + } + }) + } + + + private fun handleHeaderView(responseTime: Long) { + mBinding?.run { + recyclerView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + val canScrollVertically = recyclerView.canScrollVertically(-1) + if (mViewModel?.hour != null) { + val responseHour = TimeUtils.getFormatTime(responseTime, "HH") + val tempHour = mViewModel!!.hour!!.toInt() + val requestHour = if (tempHour >= 10) tempHour.toString() else "0${tempHour}" + if (responseHour != requestHour) { + noMatchView.translationY = 0F + noMatchView.visibility = View.VISIBLE + recyclerView.translationY = if (canScrollVertically) 40F.dip2px().toFloat() else -(8F.dip2px().toFloat()) + postDelayedRunnable({ + tryCatchInRelease { + noMatchView.animate().translationY(-(40F.dip2px().toFloat())).setDuration(200).start() + recyclerView.animate().translationY(recyclerView.translationY - 40F.dip2px().toFloat()).setDuration(200).start() + } + }, 2000) + } else { + recyclerView.translationY = if (canScrollVertically) 0F else -(48F.dip2px().toFloat()) + } + } else { + recyclerView.translationY = if (canScrollVertically) 0F else -(48F.dip2px().toFloat()) + } + recyclerView.viewTreeObserver.removeOnGlobalLayoutListener(this) + } + }) + } + } + + private fun showPullDownTip() { + if (mShowPullDownTipFlag) { + postDelayedRunnable({ + tryCatchInRelease { + mBinding?.run { + mShowPullDownTipFlag = false + pullDownTip.translationY = -(8F.dip2px().toFloat()) + pullDownTip.visibility = View.VISIBLE + pullDownTip.animate().translationY(0F).setDuration(500).start() + } + } + }, 500) + } + } + + private fun hidePullDownTip() { + mBinding?.run { + if (pullDownTip.visibility == View.VISIBLE && mHidePullDownTipFlag) { + mHidePullDownTipFlag = false + pullDownTip.animate() + .translationY(-(8F.dip2px().toFloat())) + .setDuration(500) + .withEndAction { pullDownTip.visibility = View.GONE } + .start() + } + } } fun filterData(day: String?, hour: String?, type: String?, tags: String?) { - mDay = day - mHour = hour - mType = type - mTags = tags - onRefreshPage() + mViewModel?.run { + this.day = day + this.hour = hour +// this.type = type + this.tags = tags + onRefreshPage() + } } fun vpScrollState(status: Int) { @@ -202,43 +305,26 @@ class GameServersContentFragment : BaseFragment() { } private fun onRefreshPage() { + mIsRefresh = true + mAdapter?.resetStatus() mBinding?.loadingContainer?.reuseLlLoading?.visibility = View.VISIBLE mBinding?.noConnectionContainer?.reuseNoConnection?.visibility = View.GONE mBinding?.reuseNoneData?.visibility = View.GONE mBinding?.kaifuTimeContainer?.kaifuItemTime?.visibility = View.GONE - mAdapter = GameServersContentAdapter( - context, - this, - FooterCallback { scrollToTop() }, - arrayListOf().apply { - arguments?.getParcelable(EntranceUtils.KEY_EXPOSURE_SOURCE)?.let { - add(it) - } - add(ExposureSource("开服表", "")) - }, - mEntrance, - mType, - mDay, - mHour, - mTags) - mBinding?.recyclerView?.adapter = mAdapter - mBinding?.recyclerView?.removeOnScrollListener(mExposureListener!!) - mExposureListener = ExposureListener(this, mAdapter!!) - mBinding?.recyclerView?.addOnScrollListener(mExposureListener!!) + mBinding?.recyclerView?.visibility = View.GONE + mLayoutManager?.scrollToPositionWithOffset(1, 0) + mViewModel?.loadData(true) } // 下载被删除事件 @Subscribe(threadMode = ThreadMode.MAIN) fun onEventMainThread(status: EBDownloadStatus) { + DownloadManager.getInstance(context).removePlatform(status.name, status.platform) if ("delete" == status.status) { - DownloadManager.getInstance(context).removePlatform(status.name, status.platform) - val locationList = mAdapter?.locationMap?.get(status.packageName) - if (locationList != null) { - for (location in locationList) { - mAdapter?.dataList?.get(location)?.let {gameEntity -> - gameEntity.getEntryMap().remove(status.platform) - mAdapter?.notifyItemChanged(location) - } + mViewModel?.locationMap?.get(status.packageName)?.let { + for (location in it) { + mViewModel?.listLiveData?.value?.second?.safelyGetInRelease(location)?.getEntryMap()?.remove(status.platform) + mAdapter?.notifyItemChanged(location) } } } @@ -246,28 +332,38 @@ class GameServersContentFragment : BaseFragment() { override fun loadDone() { super.loadDone() - mBinding?.kaifuTimeContainer?.kaifuItemTime?.visibility = View.VISIBLE - mBinding?.noConnectionContainer?.reuseNoConnection?.visibility = View.GONE - mBinding?.reuseNoneData?.visibility = View.GONE - mBinding?.loadingContainer?.reuseLlLoading?.visibility = View.GONE +// mBinding?.kaifuTimeContainer?.kaifuItemTime?.visibility = View.VISIBLE + mBinding?.run { + recyclerView.visibility = View.VISIBLE + noConnectionContainer.reuseNoConnection.visibility = View.GONE + reuseNoneData.visibility = View.GONE + loadingContainer.reuseLlLoading.visibility = View.GONE + } +// mBinding?.refreshLayout?.finishRefresh() } override fun loadError() { if (!isAdded) return super.loadError() toast(R.string.loading_failed_hint) - mBinding?.kaifuTimeContainer?.kaifuItemTime?.visibility = View.GONE - mBinding?.noConnectionContainer?.reuseNoConnection?.visibility = View.VISIBLE - mBinding?.reuseNoneData?.visibility = View.GONE - mBinding?.loadingContainer?.reuseLlLoading?.visibility = View.GONE + mBinding?.run { + kaifuTimeContainer.kaifuItemTime.visibility = View.GONE + noConnectionContainer.reuseNoConnection.visibility = View.VISIBLE + reuseNoneData.visibility = View.GONE + loadingContainer.reuseLlLoading.visibility = View.GONE + pullDownTip.visibility = View.GONE + } } override fun loadEmpty() { super.loadEmpty() - mBinding?.kaifuTimeContainer?.kaifuItemTime?.visibility = View.GONE - mBinding?.noConnectionContainer?.reuseNoConnection?.visibility = View.GONE - mBinding?.reuseNoneData?.visibility = View.VISIBLE - mBinding?.loadingContainer?.reuseLlLoading?.visibility = View.GONE + mBinding?.run { + kaifuTimeContainer.kaifuItemTime.visibility = View.GONE + noConnectionContainer.reuseNoConnection.visibility = View.GONE + reuseNoneData.visibility = View.VISIBLE + loadingContainer.reuseLlLoading.visibility = View.GONE + pullDownTip.visibility = View.GONE + } } private fun scrollToTop() { diff --git a/app/src/main/java/com/gh/gamecenter/servers/GameServersContentViewModel.kt b/app/src/main/java/com/gh/gamecenter/servers/GameServersContentViewModel.kt new file mode 100644 index 0000000000..ce8af17fcc --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/servers/GameServersContentViewModel.kt @@ -0,0 +1,342 @@ +package com.gh.gamecenter.servers + +import android.annotation.SuppressLint +import android.app.Application +import androidx.collection.ArrayMap +import androidx.collection.arrayMapOf +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData +import com.gh.common.util.* +import com.gh.download.DownloadManager +import com.gh.gamecenter.baselist.LoadStatus +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.entity.ServerCalendarEntity +import com.gh.gamecenter.entity.ServerPublishEntity +import com.gh.gamecenter.retrofit.BiResponse +import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers + +class GameServersContentViewModel(application: Application) + : AndroidViewModel(application) { + + val locationMap: ArrayMap> = arrayMapOf() + val listLiveData: MutableLiveData, Int>> = MutableLiveData() + val loadStatusLiveData: MutableLiveData> = MutableLiveData() + var day: String? = null + var hour: String? = null + var tags: String? = null +// var type: String? = null +// var mRealIndex = 0 + var mEntrance = "" + var prevId: String? = null + var nextId: String? = null + var isInit = true + + init { + loadData() + } + + + @SuppressLint("CheckResult") + fun loadData(isRefresh: Boolean = false, action: String? = null) { + if (isRefresh) { + isInit = true + prevId = null + nextId = null + } + + loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT)) + + if ((action == "down" && prevId?.isEmpty() == true) || action == "up" && nextId?.isEmpty() == true) { + loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_OVER)) + return + } + + val filterQuery = UrlFilterUtils.getFilterQuery("day", day, "hour", hour, "tag", tags, + "action", action, "prev_server_id", prevId, "next_server_id", nextId) + RetrofitManager.getInstance(HaloApp.getInstance()).sensitiveApi + .getGameServers(filterQuery) +// .map(RegionSettingHelper.filterGame) +// .map(ApkActiveUtils.filterMapperList) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: ServerPublishEntity) { + when (action) { + null -> { + prevId = data.prevId + nextId = data.nextId + } + "down" -> prevId = data.prevId + "up" -> nextId = data.nextId + } + + if (action == "down") { + handlePrevData(data.data, action) + } else { + handleData(data.data, isRefresh, action) + } + } + + override fun onFailure(exception: Exception) { + super.onFailure(exception) + loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_FAILED)) + } + }) + } + + fun handleData(data: List, isRefresh: Boolean, action: String?) { + var i = 0 + val list = ArrayList(data) + while (i < list.size) { + + // 初始化游戏状态 + val entity = list[i] +// if (entity.serverRemaining != null) { +// for (remainingGame in entity.serverRemaining!!) { +// remainingGame.sequence = mRealIndex++ +// } +// } +// entity.sequence = mRealIndex++ + entity.setEntryMap(DownloadManager.getInstance(HaloApp.getInstance().application).getEntryMap(entity.name)) + ApkActiveUtils.filterHideApk(entity) // 过滤隐藏apk + var fixedTopItem: GameEntity? = null + + // 当页面是由启动弹窗过来的第一或第二个页面的时候添加启动弹窗信息 + if (mEntrance.contains(EntranceUtils.ENTRANCE_WELCOME) + && mEntrance.countOccurrences("+") <= 1) { + entity.setWelcomeDialogInfoIfAvailable() + } + + // 设置置顶部分 + if (i == 0) { + // 列表顶部,若有设置置顶应用就增加置顶头部 + if (isInit && entity.fixedTop!!) { + fixedTopItem = GameEntity() + fixedTopItem.fixedTopHint = true + fixedTopItem.fixedTop = true + list.add(i, fixedTopItem) + i++ + } + } + + // 归零置顶游戏的开服时间避免找当前开服游戏时找到 + if (entity.fixedTop!!) { + if (entity.serverEntity == null) { + val emptyCalendarEntity = ServerCalendarEntity() + emptyCalendarEntity.setTime(0) + entity.serverEntity = emptyCalendarEntity + } + entity.serverEntity!!.setTime(0) + } + + // + if (i == 0) { + if (isInit) { // 列表page == 0 && position=0 默认添加时间断点 + val kaiFuTimeEntity = GameEntity() + kaiFuTimeEntity.kaifuTimeHint = entity.serverEntity!!.getTime() + list.add(i, kaiFuTimeEntity) + i++ + } else { // 列表 page > 0 && position=0 与上一页最后一条对比 + val gameEntity = listLiveData.value?.second?.last() + val serverEntity = gameEntity?.serverEntity + val nextServerEntity = entity.serverEntity + if (serverEntity == null || nextServerEntity == null) { + i++ + continue + } + val time = serverEntity.getTime() + val nextTime = nextServerEntity.getTime() + if (time != nextTime) { + val kaiFuTimeEntity = GameEntity() + kaiFuTimeEntity.kaifuTimeHint = nextTime + list.add(i, kaiFuTimeEntity) + i++ + } + } + } + if (i < list.size - 1) { + // 为置顶的项目添加第一个存在时间的游戏的开服时间 + if (fixedTopItem != null && fixedTopItem.kaifuTimeHint == null) { + fixedTopItem.kaifuTimeHint = entity.serverEntity!!.getTime() + } + val serverEntity = entity.serverEntity + val nextServerEntity = list[i + 1].serverEntity + if (serverEntity == null || nextServerEntity == null) { + i++ + continue + } + val time = serverEntity.getTime() + val nextTime = nextServerEntity.getTime() + if (time != nextTime) { + val kaiFuTimeEntity = GameEntity() + kaiFuTimeEntity.kaifuTimeHint = nextTime + list.add(i + 1, kaiFuTimeEntity) + i++ + } + } + i++ + } + + val previousData = if (isRefresh) arrayListOf() else listLiveData.value?.second ?: arrayListOf() + previousData.addAll(list) + recordIndex(previousData) + listLiveData.postValue(Triple(action, previousData, -1)) + initLocationMap(previousData) + isInit = false + + when { + list.size == 0 -> loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_EMPTY)) + data.size < 10 -> loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_OVER)) + else -> loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_LOADED)) + } + } + + fun handlePrevData(data: List, action: String?) { + loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT)) + var i = 0 + val list = ArrayList(data.reversed()) + while (i < list.size) { + + // 初始化游戏状态 + val entity = list[i] +// if (entity.serverRemaining != null) { +// for (remainingGame in entity.serverRemaining!!) { +// remainingGame.sequence = mRealIndex++ +// } +// } +// entity.sequence = mRealIndex++ + entity.setEntryMap(DownloadManager.getInstance(HaloApp.getInstance().application).getEntryMap(entity.name)) + ApkActiveUtils.filterHideApk(entity) // 过滤隐藏apk + var fixedTopItem: GameEntity? = null + + // 归零置顶游戏的开服时间避免找当前开服游戏时找到 + if (entity.fixedTop!!) { + if (entity.serverEntity == null) { + val emptyCalendarEntity = ServerCalendarEntity() + emptyCalendarEntity.setTime(0) + entity.serverEntity = emptyCalendarEntity + } + entity.serverEntity!!.setTime(0) + } + + // 设置时间断点 + if (i == 0) { + // 列表 page > 0 && position=0 与下面页最开始一条对比 + val gameEntity = listLiveData.value?.second?.find { it.kaifuTimeHint != null } + val serverEntity = gameEntity?.serverEntity + val nextServerEntity = entity.serverEntity + if (serverEntity != null && nextServerEntity != null) { + val time = serverEntity.getTime() + val nextTime = nextServerEntity.getTime() + if (time != nextTime) { + val kaiFuTimeEntity = GameEntity() + kaiFuTimeEntity.kaifuTimeHint = time + list.add(i, kaiFuTimeEntity) + i++ + } + } + } + + if (i < list.size - 1) { + // 为置顶的项目添加第一个存在时间的游戏的开服时间 + if (fixedTopItem != null && fixedTopItem.kaifuTimeHint == null) { + fixedTopItem.kaifuTimeHint = entity.serverEntity!!.getTime() + } + val serverEntity = entity.serverEntity + val nextServerEntity = list[i + 1].serverEntity + if (serverEntity == null || nextServerEntity == null) { + i++ + continue + } + val time = serverEntity.getTime() + val nextTime = nextServerEntity.getTime() + if (time != nextTime) { + val kaiFuTimeEntity = GameEntity() + kaiFuTimeEntity.kaifuTimeHint = time + list.add(i + 1, kaiFuTimeEntity) + i++ + } + } + + if (i == list.size - 1 && prevId?.isEmpty() == true) { + val serverEntity = entity.serverEntity + if (serverEntity == null) { + i++ + continue + } + val kaiFuTimeEntity = GameEntity().apply { + kaifuTimeHint = serverEntity.getTime() + } + list.add(i + 1, kaiFuTimeEntity) + i++ + } + i++ + } + + val previousData = listLiveData.value?.second ?: arrayListOf() + previousData.addAll(0, list.reversed()) + recordIndex(previousData) + listLiveData.postValue(Triple(action, previousData, list.size)) + initLocationMap(previousData) + + when { +// data.size < 20 -> loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_OVER)) + list.size == 0 -> loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_EMPTY)) + list.size > 0 -> loadStatusLiveData.postValue(Pair(action, LoadStatus.INIT_LOADED)) + } + } + + fun mergerRemainingData(entity: GameEntity, position: Int) { + val serverRemaining = entity.serverRemaining ?: return + val entryMap = entity.getEntryMap() + if (entryMap.isNotEmpty()) { + serverRemaining.forEach { + it.setEntryMap(entryMap) + } + } + val previousData = listLiveData.value?.second ?: return + previousData.addAll(position, serverRemaining) + entity.serverRemaining = null + initLocationMap(previousData) + listLiveData.postValue(Triple(null, previousData, -1)) + } + + private fun initLocationMap(itemList: List) { + locationMap.clear() + + var list: ArrayList? + var gameEntity: GameEntity + var i = 0 + val size: Int = itemList.size + while (i < size) { + gameEntity = itemList[i] + if (gameEntity.getApk().size != 0) { + for ((packageName) in gameEntity.getApk()) { + list = locationMap[packageName] + if (list == null) { + list = java.util.ArrayList() + locationMap[packageName] = list + } + list.add(i) + } + } + i++ + } + } + + private fun recordIndex(list: ArrayList) { + var index = 0 + list.forEach { + if (it.kaifuTimeHint != null) return@forEach + it.sequence = index++ + if (it.serverRemaining != null) { + for (remainingGame in it.serverRemaining!!) { + remainingGame.sequence = index++ + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/servers/GameServersPublishFragment.kt b/app/src/main/java/com/gh/gamecenter/servers/GameServersPublishFragment.kt index 6cd3403598..d69cb80080 100644 --- a/app/src/main/java/com/gh/gamecenter/servers/GameServersPublishFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/servers/GameServersPublishFragment.kt @@ -17,21 +17,19 @@ import com.gh.common.util.dip2px import com.gh.common.util.toColor import com.gh.common.view.DrawableView import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.FragmentGameServersPublishBinding import com.gh.gamecenter.entity.ServersGameCategory import com.gh.gamecenter.eventbus.EBNetworkState import com.gh.gamecenter.retrofit.BiResponse import com.gh.gamecenter.retrofit.RetrofitManager import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers -import kotterknife.bindView import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode class GameServersPublishFragment : LazyFragment() { - private val mServersTime by bindView(R.id.server_time) - private val mGameCategory by bindView(R.id.server_status) - + private var mBinding: FragmentGameServersPublishBinding? = null private lateinit var mContentFragment: GameServersContentFragment private val mCategoryList = ArrayList() @@ -42,28 +40,35 @@ class GameServersPublishFragment : LazyFragment() { private val mType = "开服" override fun getRealLayoutId(): Int { - return R.layout.fragment_game_servers + return R.layout.fragment_game_servers_publish + } + + override fun onRealLayoutInflated(inflatedView: View) { + mBinding = FragmentGameServersPublishBinding.bind(inflatedView) } override fun initRealView() { super.initRealView() - mGameCategory.text = "游戏分类" - mServersTime.text = "开服时间" - mGameCategory.setOnClickListener { - showCategoryPopupWindow(it as CheckedTextView, callback = { tags -> - mTags = tags - mContentFragment.filterData(mDay, mHour, mType, mTags) - }) - } - mServersTime.setOnClickListener { - showServersTimePopupWindow(it as CheckedTextView, callback = { day, hour -> - mDay = day - mHour = hour - mContentFragment.filterData(mDay, mHour, mType, mTags) - }) + mBinding?.run { + serverStatus.text = "游戏分类" + serverTime.text = "开服时间" + serverStatus.setOnClickListener { + showCategoryPopupWindow(it as CheckedTextView, callback = { tags -> + mTags = tags + mContentFragment.filterData(mDay, mHour, mType, mTags) + }) + } + serverTime.setOnClickListener { + showServersTimePopupWindow(it as CheckedTextView, callback = { day, hour -> + mDay = day + mHour = hour + mContentFragment.filterData(mDay, mHour, mType, mTags) + }) + } } + val bundle = arguments bundle?.putString(EntranceUtils.KEY_TYPE, "开服") mContentFragment = childFragmentManager.findFragmentByTag(GameServersContentFragment::class.java.simpleName) as? GameServersContentFragment @@ -124,7 +129,7 @@ class GameServersPublishFragment : LazyFragment() { label.text = name label.background = DrawableView.getOvalSelectorStyle(R.color.background, R.color.text_e6f3ff) label.setTextColor(DrawableView.getSelectorColorStyle(R.color.text_333333, R.color.theme_font)) - label.setSingleLine(true) + label.isSingleLine = true labelsContainer.addView(label) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { label.textAlignment = View.TEXT_ALIGNMENT_CENTER @@ -190,7 +195,7 @@ class GameServersPublishFragment : LazyFragment() { v.isChecked = false if (mTags.isNullOrEmpty()) v.setTextColor(R.color.text_333333.toColor()) } - popupWindow.showAsDropDown(v) + popupWindow.showAsDropDown(mBinding?.divider) } // day, hour @@ -208,7 +213,6 @@ class GameServersPublishFragment : LazyFragment() { LinearLayout.LayoutParams.WRAP_CONTENT ) - val all = layout.findViewById(R.id.all) val today = layout.findViewById(R.id.today) val tomorrow = layout.findViewById(R.id.tomorrow) val after = layout.findViewById(R.id.after) @@ -219,11 +223,7 @@ class GameServersPublishFragment : LazyFragment() { tomorrow.text = "明日开服" after.text = "后续开服" - when (v.text) { - "开服时间" -> all.isChecked = true - "后续开服" -> after.isChecked = true - } - if (v.text.contains("今日")) { + if (v.text == "开服时间" || v.text.contains("今日")) { today.isChecked = true hourScrollView.visibility = View.VISIBLE @@ -232,11 +232,13 @@ class GameServersPublishFragment : LazyFragment() { tomorrow.isChecked = true hourScrollView.visibility = View.VISIBLE } + if (v.text == "后续开服") { + after.isChecked = true + } // add hour content for (i in 0 until 24 + 1) { // position = 0: all - val index = i - 1 val hour = TextView(v.context) hour.textSize = 14F hour.setTextColor(R.color.text_333333.toColor()) @@ -244,20 +246,14 @@ class GameServersPublishFragment : LazyFragment() { hour.setPadding(24F.dip2px(), 0, 0, 0) hourContainer.addView(hour, ViewGroup.LayoutParams.MATCH_PARENT, 43F.dip2px()) - if (index >= 0) { - hour.text = if (index >= 10) "$index:00" else "0$index:00" - } else { - hour.text = if (v.text.contains("今日")) { - "今日全部" - } else { - "明日全部" - } + if (i >= 0) { + hour.text = if (i >= 10) "$i:00" else "0$i:00" } hour.setOnClickListener { if (today.isChecked) { - if (index >= 0) { - callback.invoke("today", index.toString()) + if (i >= 0) { + callback.invoke("today", i.toString()) v.text = (today.text.toString() + " " + hour.text.toString()) } else { callback.invoke("today", null) @@ -265,8 +261,8 @@ class GameServersPublishFragment : LazyFragment() { } MtaHelper.onEvent("开服表", "开服Tab-今日开服", hour.text.toString()) } else { - if (index >= 0) { - callback.invoke("tomorrow", index.toString()) + if (i >= 0) { + callback.invoke("tomorrow", i.toString()) v.text = (tomorrow.text.toString() + " " + hour.text.toString()) } else { callback.invoke("tomorrow", null) @@ -278,7 +274,6 @@ class GameServersPublishFragment : LazyFragment() { } } - all.setTextColor(DrawableView.getSelectorColorStyle(R.color.text_333333, R.color.theme_font)) today.setTextColor(DrawableView.getSelectorColorStyle(R.color.text_333333, R.color.theme_font)) tomorrow.setTextColor(DrawableView.getSelectorColorStyle(R.color.text_333333, R.color.theme_font)) after.setTextColor(DrawableView.getSelectorColorStyle(R.color.text_333333, R.color.theme_font)) @@ -286,12 +281,6 @@ class GameServersPublishFragment : LazyFragment() { layout.setOnClickListener { popupWindow.dismiss() } - all.setOnClickListener { - v.text = "开服时间" - callback.invoke(null, null) - popupWindow.dismiss() - MtaHelper.onEvent("开服表", "开服Tab", "开服时间-全部") - } after.setOnClickListener { v.text = after.text callback.invoke("after", null) @@ -300,26 +289,16 @@ class GameServersPublishFragment : LazyFragment() { } today.setOnClickListener { MtaHelper.onEvent("开服表", "开服Tab", "今日开服") - if (hourContainer.childCount > 0) { - val hour = hourContainer.getChildAt(0) as TextView - hour.text = "今日全部" - } hourScrollView.visibility = View.VISIBLE today.isChecked = true tomorrow.isChecked = !today.isChecked - all.isChecked = !today.isChecked after.isChecked = !today.isChecked } tomorrow.setOnClickListener { MtaHelper.onEvent("开服表", "开服Tab", "明日开服") - if (hourContainer.childCount > 0) { - val hour = hourContainer.getChildAt(0) as TextView - hour.text = "明日全部" - } hourScrollView.visibility = View.VISIBLE tomorrow.isChecked = true today.isChecked = !tomorrow.isChecked - all.isChecked = !tomorrow.isChecked after.isChecked = !tomorrow.isChecked } @@ -330,16 +309,18 @@ class GameServersPublishFragment : LazyFragment() { v.isChecked = false if (mDay.isNullOrEmpty()) v.setTextColor(R.color.text_333333.toColor()) } - popupWindow.showAsDropDown(v) + popupWindow.showAsDropDown(mBinding?.divider) } fun resetFilter() { mDay = null mHour = null mTags = null - mServersTime.text = "开服时间" - mServersTime.setTextColor(R.color.text_333333.toColor()) - mGameCategory.setTextColor(R.color.text_333333.toColor()) + mBinding?.run { + serverTime.text = "开服时间" + serverTime.setTextColor(R.color.text_333333.toColor()) + serverStatus.setTextColor(R.color.text_333333.toColor()) + } mContentFragment.filterData(mDay, mHour, mType, mTags) } diff --git a/app/src/main/java/com/gh/gamecenter/servers/GameServersTestAdapter.kt b/app/src/main/java/com/gh/gamecenter/servers/GameServersTestAdapter.kt index 4c993fe153..b2d57512eb 100644 --- a/app/src/main/java/com/gh/gamecenter/servers/GameServersTestAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/servers/GameServersTestAdapter.kt @@ -98,7 +98,7 @@ class GameServersTestAdapter(context: Context, initViewHolder(gameEntity, holder) } is GameServerTimeViewHolder -> { - holder.container.setPadding(0, 8F.dip2px(), 0, 4F.dip2px()) +// holder.container.setPadding(0, 8F.dip2px(), 0, 4F.dip2px()) holder.header.setImageResource(R.drawable.kaifu_time_icon) holder.time.text = mDataList[position].time } diff --git a/app/src/main/java/com/gh/gamecenter/setting/GameDownloadSettingFragment.kt b/app/src/main/java/com/gh/gamecenter/setting/GameDownloadSettingFragment.kt index 318163fbde..0ed3165238 100644 --- a/app/src/main/java/com/gh/gamecenter/setting/GameDownloadSettingFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/setting/GameDownloadSettingFragment.kt @@ -1,16 +1,19 @@ package com.gh.gamecenter.setting import android.content.Intent +import android.content.SharedPreferences import android.net.Uri +import android.os.Build import android.os.Bundle import android.os.Environment +import android.preference.PreferenceManager import android.text.TextUtils -import android.util.Log import android.view.View +import androidx.core.content.FileProvider import butterknife.OnClick import com.gh.common.util.MtaHelper.onEvent import com.gh.common.util.PackageUtils -import com.gh.common.util.SPUtils +import com.gh.gamecenter.BuildConfig import com.gh.gamecenter.CleanApkActivity import com.gh.gamecenter.R import com.gh.gamecenter.databinding.FragmentGameDownloadSettingBinding @@ -20,6 +23,7 @@ import java.io.File class GameDownloadSettingFragment: NormalFragment() { private var mBinding: FragmentGameDownloadSettingBinding? = null + private var mSP: SharedPreferences? = null override fun getLayoutId() = 0 @@ -27,14 +31,17 @@ class GameDownloadSettingFragment: NormalFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + mSP = PreferenceManager.getDefaultSharedPreferences(requireContext()) initStatus() } private fun initStatus() { mBinding?.run { - autoInstallSwitch.isChecked = SPUtils.getBoolean(AUTO_INSTALL_SP_KEY) - concernGameSwitch.isChecked = SPUtils.getBoolean(CONCERN_GAME_SP_KEY) - trafficSwitch.isChecked = SPUtils.getBoolean(getTrafficDownloadHintKey()) + mSP?.run { + autoInstallSwitch.isChecked = getBoolean(AUTO_INSTALL_SP_KEY, false) + concernGameSwitch.isChecked = getBoolean(CONCERN_GAME_SP_KEY, false) + trafficSwitch.isChecked = getBoolean(getTrafficDownloadHintKey(), false) + } } } @@ -48,19 +55,19 @@ class GameDownloadSettingFragment: NormalFragment() { onEvent("我的光环_设置", "设置功能", "下载完成自动安装游戏") onEvent("我的光环_设置", "自动安装游戏", if (autoInstallSwitch.isChecked) "关闭" else "打开") autoInstallSwitch.isChecked = !autoInstallSwitch.isChecked - SPUtils.setBoolean(AUTO_INSTALL_SP_KEY, autoInstallSwitch.isChecked) + mSP?.edit()?.putBoolean(AUTO_INSTALL_SP_KEY, autoInstallSwitch.isChecked)?.apply() } R.id.concernGameContainer -> { onEvent("我的光环_设置", "设置功能", "安装完成自动关注游戏") onEvent("我的光环_设置", "自动关注游戏", if (concernGameSwitch.isChecked) "关闭" else "打开") concernGameSwitch.isChecked = !concernGameSwitch.isChecked - SPUtils.setBoolean(CONCERN_GAME_SP_KEY, concernGameSwitch.isChecked) + mSP?.edit()?.putBoolean(CONCERN_GAME_SP_KEY, concernGameSwitch.isChecked)?.apply() } R.id.trafficContainer -> { trafficSwitch.isChecked = !trafficSwitch.isChecked - SPUtils.setBoolean(getTrafficDownloadHintKey(), trafficSwitch.isChecked) + mSP?.edit()?.putBoolean(getTrafficDownloadHintKey(), trafficSwitch.isChecked)?.apply() } R.id.downloadPathContainer -> { @@ -87,7 +94,12 @@ class GameDownloadSettingFragment: NormalFragment() { private fun startFilePath(dirPath: String) { val intent = Intent(Intent.ACTION_GET_CONTENT) - intent.setDataAndType(Uri.fromFile(File(dirPath)), "file/*") + val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + FileProvider.getUriForFile(requireContext(), BuildConfig.APPLICATION_ID, File(dirPath)) + } else { + Uri.fromFile(File(dirPath)) + } + intent.setDataAndType(uri, "file/*") intent.addCategory(Intent.CATEGORY_OPENABLE) intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK try { @@ -107,7 +119,7 @@ class GameDownloadSettingFragment: NormalFragment() { @JvmStatic fun getTrafficDownloadHintKey(): String { - return PackageUtils.getVersionName() + "traffic_download_hint" + return PackageUtils.getGhVersionName() + "traffic_download_hint" } } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorGameListAdapter.kt b/app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorGameListAdapter.kt index ce8956577c..b37a10809f 100644 --- a/app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorGameListAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorGameListAdapter.kt @@ -113,7 +113,7 @@ class SimulatorGameListAdapter(context: Context, holder.simulatorBtn.run { if (PackageUtils.isInstalledFromAllPackage(context, simulator.apk?.packageName)) { - val versionFromInstalledApp = PackageUtils.getVersionByPackage(simulator.apk?.packageName) + val versionFromInstalledApp = PackageUtils.getVersionNameByPackageName(simulator.apk?.packageName) val shouldShowUpdate = Version(simulator.apk?.version).isHigherThan(versionFromInstalledApp) text = if (shouldShowUpdate) "更新模拟器" else "卸载模拟器" setTextColor(if (shouldShowUpdate) R.color.theme.toColor() else R.color.text_999999.toColor()) diff --git a/app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorManagementAdapter.kt b/app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorManagementAdapter.kt index c93a53ece6..445a911867 100644 --- a/app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorManagementAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/simulatorgame/SimulatorManagementAdapter.kt @@ -49,7 +49,7 @@ class SimulatorManagementAdapter(context: Context, var shouldShowUpdate = false if (isInstalled) { - val versionFromInstalledApp = PackageUtils.getVersionByPackage(simulator.apk?.packageName) + val versionFromInstalledApp = PackageUtils.getVersionNameByPackageName(simulator.apk?.packageName) shouldShowUpdate = Version(simulator.apk?.version).isHigherThan(versionFromInstalledApp) text = if (shouldShowUpdate) "更新" else "已安装" setTextColor(if (shouldShowUpdate) R.color.theme.toColor() else R.color.text_999999.toColor()) diff --git a/app/src/main/java/com/gh/gamecenter/user/UserRepository.java b/app/src/main/java/com/gh/gamecenter/user/UserRepository.java index ee3edc9947..f993acb2f5 100644 --- a/app/src/main/java/com/gh/gamecenter/user/UserRepository.java +++ b/app/src/main/java/com/gh/gamecenter/user/UserRepository.java @@ -268,7 +268,7 @@ public class UserRepository { if (httpException.code() == 400) { LoginUtils.outputErrorHint(mContext, code); } else if (code == 403092) { - Utils.toast(mContext, "邀请码错误"); + Utils.toast(mContext, "填写邀请码错误"); } else { Utils.toast(mContext, mContext.getString(R.string.login_failure_hint_code, code)); } @@ -458,6 +458,14 @@ public class UserRepository { MessageUnreadRepository.INSTANCE.loadMessageUnreadData(); } + + if (UserManager.getInstance().getLoginTokenEntity() != null) { + if (UserManager.getInstance().getLoginTokenEntity().isFirstLogin()) { + EnergyTaskHelper.postEnergyTask("register"); + } else { + EnergyTaskHelper.postEnergyTask("login"); + } + } } @Override diff --git a/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerViewModel.kt b/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerViewModel.kt index a384d3eadc..1aa1be671a 100644 --- a/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerViewModel.kt @@ -14,6 +14,7 @@ import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.entity.MyVideoEntity import com.gh.gamecenter.entity.User import com.gh.gamecenter.entity.VideoEntity +import com.gh.gamecenter.eventbus.EBUserFollow import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.retrofit.BiResponse import com.gh.gamecenter.retrofit.Response @@ -23,6 +24,7 @@ import com.lightgame.utils.Utils import io.reactivex.Single import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody +import org.greenrobot.eventbus.EventBus import java.lang.ref.WeakReference import java.util.* import kotlin.collections.ArrayList @@ -560,6 +562,7 @@ class VideoDetailContainerViewModel(application: Application) : AndroidViewModel videoEntity.me.isFollower = true followVideoInfo.postValue(videoEntity) Utils.toast(getApplication(), "关注成功") + EventBus.getDefault().post(EBUserFollow(videoEntity.user.id, true)) } }) diff --git a/app/src/main/java/com/gh/gamecenter/video/upload/view/UploadVideoActivity.kt b/app/src/main/java/com/gh/gamecenter/video/upload/view/UploadVideoActivity.kt index 246998ead6..e4533b65ed 100644 --- a/app/src/main/java/com/gh/gamecenter/video/upload/view/UploadVideoActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/video/upload/view/UploadVideoActivity.kt @@ -886,7 +886,7 @@ class UploadVideoActivity : ToolBarActivity() { private fun getConfirmUpdateProtocolKey(): String { - return "ConfirmUpdateProtocolKey" + PackageUtils.getVersionName() + return "ConfirmUpdateProtocolKey" + PackageUtils.getGhVersionName() } companion object { diff --git a/app/src/main/java/com/gh/gamecenter/wxapi/WXEntryActivity.java b/app/src/main/java/com/gh/gamecenter/wxapi/WXEntryActivity.java index cbf327d454..d2bad101ae 100644 --- a/app/src/main/java/com/gh/gamecenter/wxapi/WXEntryActivity.java +++ b/app/src/main/java/com/gh/gamecenter/wxapi/WXEntryActivity.java @@ -11,6 +11,7 @@ import com.gh.common.constant.Config; import com.gh.common.util.EnergyTaskHelper; import com.gh.common.util.LogUtils; import com.gh.common.util.LoginHelper; +import com.gh.common.util.NewLogUtils; import com.gh.common.util.ShareUtils; import com.gh.gamecenter.R; import com.gh.gamecenter.eventbus.EBShare; @@ -77,6 +78,11 @@ public class WXEntryActivity extends Activity implements IWXAPIEventHandler, WeC LogUtils.uploadShareResult(ShareUtils.shareType, ShareUtils.shareEntrance.getName(), "success", ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId); EnergyTaskHelper.postEnergyTaskForShare(ShareUtils.shareEntrance.getName(), ShareUtils.resourceId, ShareUtils.shareEntity.getShareUrl()); + if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.communityArticle || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) { + NewLogUtils.logShareResult(true); + } } else { if (baseResp instanceof SendAuth.Resp) { SendAuth.Resp resp = (SendAuth.Resp) baseResp; @@ -94,6 +100,11 @@ public class WXEntryActivity extends Activity implements IWXAPIEventHandler, WeC resultString = getString(R.string.share_cancel_hint); LogUtils.uploadShareResult(ShareUtils.shareType, ShareUtils.shareEntrance.getName(), "cancel", ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId); + if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.communityArticle || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) { + NewLogUtils.logShareResult(false); + } } else { resultString = "登录已取消"; } @@ -112,6 +123,11 @@ public class WXEntryActivity extends Activity implements IWXAPIEventHandler, WeC resultString = "分享错误"; LogUtils.uploadShareResult(ShareUtils.shareType, ShareUtils.shareEntrance.getName(), "fail", ShareUtils.shareEntity.getShareUrl(), ShareUtils.shareEntity.getShareTitle(), ShareUtils.shareEntity.getSummary(), ShareUtils.resourceId); + if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.askNormal || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.communityArticle || + ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) { + NewLogUtils.logShareResult(false); + } } else { resultString = "登录错误"; } diff --git a/app/src/main/java/com/halo/assistant/HaloApp.java b/app/src/main/java/com/halo/assistant/HaloApp.java index 868b311bcf..51868d88b9 100644 --- a/app/src/main/java/com/halo/assistant/HaloApp.java +++ b/app/src/main/java/com/halo/assistant/HaloApp.java @@ -20,6 +20,7 @@ import com.gh.common.FixedRateJobHelper; import com.gh.common.constant.Config; import com.gh.common.constant.Constants; import com.gh.common.exposure.ExposureManager; +import com.gh.common.filter.RegionSettingHelper; import com.gh.common.loghub.LoghubUtils; import com.gh.common.tracker.Tracker; import com.gh.common.util.DataUtils; @@ -219,6 +220,8 @@ public class HaloApp extends MultiDexApplication { DataUtils.getGid(); FixedRateJobHelper.begin(); + + RegionSettingHelper.getRegionSetting(); PackageRepository.initData(); @@ -360,7 +363,7 @@ public class HaloApp extends MultiDexApplication { * 覆盖安装进入过首页的也当作是同意了 */ public static boolean isUserAcceptPrivacyPolicy(Context context) { - return !PreferenceManager.getDefaultSharedPreferences(context).getBoolean("isNewFirstLaunchV" + PackageUtils.getVersionName(), true) + return !PreferenceManager.getDefaultSharedPreferences(context).getBoolean("isNewFirstLaunchV" + PackageUtils.getGhVersionName(), true) || !SPUtils.getBooleanWithContext(context, Constants.SP_BRAND_NEW_USER, true) || SPUtils.getBooleanWithContext(context, Constants.SP_IS_USER_ACCEPTED_PRIVACY_STATEMENT, false); } diff --git a/app/src/main/java/com/halo/assistant/fragment/AboutFragment.java b/app/src/main/java/com/halo/assistant/fragment/AboutFragment.java index 4935a7b686..1fe55e43dc 100644 --- a/app/src/main/java/com/halo/assistant/fragment/AboutFragment.java +++ b/app/src/main/java/com/halo/assistant/fragment/AboutFragment.java @@ -74,7 +74,7 @@ public class AboutFragment extends NormalFragment { super.onCreate(savedInstanceState); setNavigationTitle(getString(R.string.title_about)); - mVersionName.setText("V" + PackageUtils.getVersionName()); + mVersionName.setText("V" + PackageUtils.getGhVersionName()); long serverTime = PreferenceManager.getDefaultSharedPreferences(requireContext()).getLong("server_time", 1587693163L); String year = TimeUtils.INSTANCE.getFormatTime(serverTime, "yyyy"); diff --git a/app/src/main/java/com/halo/assistant/fragment/SettingsFragment.java b/app/src/main/java/com/halo/assistant/fragment/SettingsFragment.java index 14cef9877c..4dd876d6c7 100644 --- a/app/src/main/java/com/halo/assistant/fragment/SettingsFragment.java +++ b/app/src/main/java/com/halo/assistant/fragment/SettingsFragment.java @@ -151,9 +151,9 @@ public class SettingsFragment extends NormalFragment { } else { // Jenkins 打的包附带个打包时间在版本后面 if (BuildConfig.BUILD_TIME == 0) { - mVersionName.setText(("V" + PackageUtils.getVersionName())); + mVersionName.setText(("V" + PackageUtils.getGhVersionName())); } else { - mVersionName.setText(("V" + PackageUtils.getVersionName()) + " " + BuildConfig.BUILD_TIME); + mVersionName.setText(("V" + PackageUtils.getGhVersionName()) + " " + BuildConfig.BUILD_TIME); } } } diff --git a/app/src/main/java/com/halo/assistant/fragment/SwitchInstallMethodFragment.kt b/app/src/main/java/com/halo/assistant/fragment/SwitchInstallMethodFragment.kt index a48639d98e..7e7b191c7a 100644 --- a/app/src/main/java/com/halo/assistant/fragment/SwitchInstallMethodFragment.kt +++ b/app/src/main/java/com/halo/assistant/fragment/SwitchInstallMethodFragment.kt @@ -1,7 +1,9 @@ package com.halo.assistant.fragment +import android.content.Intent import android.os.Build import android.os.Bundle +import android.provider.Settings import android.view.View import com.gh.common.constant.Constants import com.gh.common.util.SPUtils @@ -37,24 +39,31 @@ class SwitchInstallMethodFragment : NormalFragment() { val manufacturer = Build.MANUFACTURER.toUpperCase(Locale.CHINA) - val defaultHintText: String + var defaultHintText: CharSequence var browserHintText: CharSequence = "1.光环助手下载应用后,通过跳转默认浏览器安装已下载的应用(不会重复消耗流量),即可完成免密码安装\n2.内存较大的游戏在浏览器解压时间较长,需要等待片刻,您也可以通过浏览器的“下载记录”查看解压进度" if (manufacturer == "OPPO" || manufacturer == "VIVO") { - defaultHintText = "直接使用光环助手下载应用,但${manufacturer}手机自身安全性检测,下载后需要进行验证账户密码、指纹等解锁后安装" + val clickText : CharSequence = "前往手机设置-指纹、面部与密码>" + val endText = if (manufacturer == "OPPO") " 设置锁屏密码,再点击[添加指纹]录入指纹,将指纹用于[安装验证];或者点击[添加面部]录入面部,将面部用于[安装验证],即可实现快速安装" else "开启锁屏密码,再点击[添加指纹]录入指纹,将指纹用于[解锁],即可实现快速安装" + defaultHintText = "1.直接使用光环助手下载应用,但${manufacturer}手机自身安全性检测,下载后需要进行验证账户密码、指纹等解锁后安装\n2.您可以 $clickText$endText" + defaultHintText = SpanBuilder(defaultHintText) + .click(defaultHintText.length - clickText.length - endText.length, defaultHintText.length - endText.length, R.color.theme_font, true) { + requireContext().startActivity(Intent(Settings.ACTION_SETTINGS)) + } + .build() val clickableText: CharSequence = "可查看使用教程>" - browserHintText = "$browserHintText\n以上未能解决安装需要密码的,$clickableText" + browserHintText = "$browserHintText\n\n以上未能解决安装需要密码的,$clickableText" browserHintText = SpanBuilder(browserHintText) - .click(browserHintText.length - clickableText.length, browserHintText.length, R.color.theme_font, true) { - val url = if (manufacturer == "OPPO") { - "https://static-web.ghzs.com/ghzs_help/help.html?content=5fa90fe143d91a022e0d33ff" - } else { - "https://static-web.ghzs.com/ghzs_help/help.html?content=5fc05a0033b5f008e04cdc4b" - } - requireContext().startActivity(WebActivity.getIntent(requireContext(), url, "安装问题", false, 1)) + .click(browserHintText.length - clickableText.length, browserHintText.length, R.color.theme_font, true) { + val url = if (manufacturer == "OPPO") { + "https://static-web.ghzs.com/ghzs_help/help.html?content=5fa90fe143d91a022e0d33ff" + } else { + "https://static-web.ghzs.com/ghzs_help/help.html?content=5fc05a0033b5f008e04cdc4b" } - .build() + requireContext().startActivity(WebActivity.getIntent(requireContext(), url, "安装问题", false, 1)) + } + .build() } else { defaultHintText = "直接使用光环助手下载应用,但部分手机可能存在无法安装的问题" } @@ -62,6 +71,7 @@ class SwitchInstallMethodFragment : NormalFragment() { mBinding?.defaultHintTv?.text = defaultHintText mBinding?.browserHintTv?.text = browserHintText mBinding?.browserHintTv?.movementMethod = CustomLinkMovementMethod.getInstance() + mBinding?.defaultHintTv?.movementMethod = CustomLinkMovementMethod.getInstance() } private fun changeSwitch(useBrowserToInstall: Boolean) { diff --git a/app/src/main/java/com/halo/assistant/fragment/WebFragment.java b/app/src/main/java/com/halo/assistant/fragment/WebFragment.java index c719db43be..29cdbedfca 100644 --- a/app/src/main/java/com/halo/assistant/fragment/WebFragment.java +++ b/app/src/main/java/com/halo/assistant/fragment/WebFragment.java @@ -15,6 +15,8 @@ import android.view.View; import android.webkit.JavascriptInterface; import android.webkit.ValueCallback; import android.webkit.WebChromeClient; +import android.webkit.WebResourceError; +import android.webkit.WebResourceRequest; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; @@ -133,6 +135,7 @@ public class WebFragment extends LazyFragment implements IScrollable { private boolean mIsWebPageHandleBackPressed; private boolean mIsOpenNativePage;//网页打开新页面是否重新打开一个原生页面 private boolean mIsHorizontalDispatcherEnabled; + private boolean mIsWebPageSuccessfullyLoaded = true; // 页面是否成功加载 private String mBackConfirmationContent; private String mGameName; private String mIsCloseButton;//h5游戏是否显示关闭按钮 hide(隐藏)、open(开启) @@ -408,6 +411,16 @@ public class WebFragment extends LazyFragment implements IScrollable { } }, 100); } + + if (!"Webpage not available".equals(mWebView.getTitle())) { + mIsWebPageSuccessfullyLoaded = true; + } + } + + @Override + public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { + super.onReceivedError(view, request, error); + mIsWebPageSuccessfullyLoaded = false; } }); @@ -454,7 +467,10 @@ public class WebFragment extends LazyFragment implements IScrollable { public void onReceivedTitle(WebView view, String title) { super.onReceivedTitle(view, title); // title 有可能超出边界 - if (TextUtils.isEmpty(newsId) && TextUtils.isEmpty(mNavigationTitle) && !mIsTools && mAutoCompletionTitle) { + if (TextUtils.isEmpty(newsId) + && (TextUtils.isEmpty(mNavigationTitle) || mNavigationTitle.contains("http")) + && !mIsTools + && mAutoCompletionTitle) { mNavigationTitle = title; setNavigationTitle(mNavigationTitle); } @@ -571,12 +587,12 @@ public class WebFragment extends LazyFragment implements IScrollable { return false; } else if (!TextUtils.isEmpty(mGameName)) { return false; - } else if (mIsWebPageHandleBackPressed) { + } else if (mWebView != null && mIsWebPageHandleBackPressed && mIsWebPageSuccessfullyLoaded) { mWebView.callHandler("onBackPressed", retValue -> { // do nothing }); return true; - } else if (mWebView.canGoBack()) { + } else if (mWebView != null && mWebView.canGoBack()) { mWebView.goBack(); return true; } else if (isDisplayingLogoutPage()) { @@ -612,6 +628,8 @@ public class WebFragment extends LazyFragment implements IScrollable { .equals(Constants.EB_QUIT_LOGIN)) { mWebView.reload(); } + } else { + mJsApi.onLogin(); } } } @@ -632,7 +650,9 @@ public class WebFragment extends LazyFragment implements IScrollable { @Override public void scrollToTop() { - mWebView.scrollTo(0, 0); + if (mWebView != null) { + mWebView.scrollTo(0, 0); + } } /** diff --git a/app/src/main/res/drawable-xxhdpi/bg_badge_btn.webp b/app/src/main/res/drawable-xxhdpi/bg_badge_btn.webp deleted file mode 100644 index 6f90dac570..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/bg_badge_btn.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/bg_badge_light.webp b/app/src/main/res/drawable-xxhdpi/bg_badge_light.webp deleted file mode 100644 index cccfe2d788..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/bg_badge_light.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/bg_commodity_tag.9.png b/app/src/main/res/drawable-xxhdpi/bg_commodity_tag.9.png deleted file mode 100644 index 12dd6bfc0f..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/bg_commodity_tag.9.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/bg_congratulations_words.webp b/app/src/main/res/drawable-xxhdpi/bg_congratulations_words.webp deleted file mode 100644 index eb5247ef06..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/bg_congratulations_words.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/bg_energy_center_day.webp b/app/src/main/res/drawable-xxhdpi/bg_energy_center_day.webp deleted file mode 100644 index d853cea417..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/bg_energy_center_day.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/bg_energy_center_night.webp b/app/src/main/res/drawable-xxhdpi/bg_energy_center_night.webp deleted file mode 100644 index 3d1ed283c5..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/bg_energy_center_night.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/bg_energy_dialog.webp b/app/src/main/res/drawable-xxhdpi/bg_energy_dialog.webp deleted file mode 100644 index a98c71b6c9..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/bg_energy_dialog.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/bg_energy_house.webp b/app/src/main/res/drawable-xxhdpi/bg_energy_house.webp deleted file mode 100644 index aab0b724e1..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/bg_energy_house.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/bg_login.webp b/app/src/main/res/drawable-xxhdpi/bg_login.webp deleted file mode 100644 index bbbfd847eb..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/bg_login.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/bg_personal_info.webp b/app/src/main/res/drawable-xxhdpi/bg_personal_info.webp deleted file mode 100644 index 55df369271..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/bg_personal_info.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/bg_quick_login_dialog.webp b/app/src/main/res/drawable-xxhdpi/bg_quick_login_dialog.webp deleted file mode 100644 index 8a663f076f..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/bg_quick_login_dialog.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/bg_receive_badge.webp b/app/src/main/res/drawable-xxhdpi/bg_receive_badge.webp deleted file mode 100644 index 0f2f0dc00b..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/bg_receive_badge.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/bg_view_badge.webp b/app/src/main/res/drawable-xxhdpi/bg_view_badge.webp deleted file mode 100644 index e845954f4b..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/bg_view_badge.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_choose_activity.webp b/app/src/main/res/drawable-xxhdpi/ic_choose_activity.webp deleted file mode 100644 index 38af24a83d..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_choose_activity.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_energy_arrow_right.png b/app/src/main/res/drawable-xxhdpi/ic_energy_arrow_right.png deleted file mode 100644 index 21ec38ec8d..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_energy_arrow_right.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_energy_center_done.webp b/app/src/main/res/drawable-xxhdpi/ic_energy_center_done.webp deleted file mode 100644 index 7bd2823dc1..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_energy_center_done.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_energy_center_invite.webp b/app/src/main/res/drawable-xxhdpi/ic_energy_center_invite.webp deleted file mode 100644 index 906d17e40d..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_energy_center_invite.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_energy_center_more.webp b/app/src/main/res/drawable-xxhdpi/ic_energy_center_more.webp deleted file mode 100644 index 93b2b9800b..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_energy_center_more.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_energy_center_sign.webp b/app/src/main/res/drawable-xxhdpi/ic_energy_center_sign.webp deleted file mode 100644 index 23b0c7ad87..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_energy_center_sign.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_energy_center_sign_normal.webp b/app/src/main/res/drawable-xxhdpi/ic_energy_center_sign_normal.webp deleted file mode 100644 index 0e77584516..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_energy_center_sign_normal.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_energy_center_signed.webp b/app/src/main/res/drawable-xxhdpi/ic_energy_center_signed.webp deleted file mode 100644 index c1e15c34c8..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_energy_center_signed.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_energy_center_top_energy.webp b/app/src/main/res/drawable-xxhdpi/ic_energy_center_top_energy.webp deleted file mode 100644 index 301c6aa82f..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_energy_center_top_energy.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_exchange_commodity.webp b/app/src/main/res/drawable-xxhdpi/ic_exchange_commodity.webp deleted file mode 100644 index e6c3cc2e76..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_exchange_commodity.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_gamedetail_reserve.webp b/app/src/main/res/drawable-xxhdpi/ic_gamedetail_reserve.webp index 66467b64eb..2ed31eefde 100644 Binary files a/app/src/main/res/drawable-xxhdpi/ic_gamedetail_reserve.webp and b/app/src/main/res/drawable-xxhdpi/ic_gamedetail_reserve.webp differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_gamedetail_reserved.webp b/app/src/main/res/drawable-xxhdpi/ic_gamedetail_reserved.webp index 7057100674..03fe4ab86a 100644 Binary files a/app/src/main/res/drawable-xxhdpi/ic_gamedetail_reserved.webp and b/app/src/main/res/drawable-xxhdpi/ic_gamedetail_reserved.webp differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_login_logo.webp b/app/src/main/res/drawable-xxhdpi/ic_login_logo.webp deleted file mode 100644 index 16c8241b4d..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_login_logo.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_lottery_paradise.webp b/app/src/main/res/drawable-xxhdpi/ic_lottery_paradise.webp deleted file mode 100644 index 312e8ce3da..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_lottery_paradise.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/pic_dialog_shortcut.webp b/app/src/main/res/drawable-xxhdpi/pic_dialog_shortcut.webp deleted file mode 100644 index 7a29a07fb1..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/pic_dialog_shortcut.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/pic_no_data.webp b/app/src/main/res/drawable-xxhdpi/pic_no_data.webp deleted file mode 100644 index 08456bf8ef..0000000000 Binary files a/app/src/main/res/drawable-xxhdpi/pic_no_data.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_bottom_sheet_collapses.webp b/app/src/main/res/drawable-xxxhdpi/bg_bottom_sheet_collapses.webp new file mode 100644 index 0000000000..e1d5e48664 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_bottom_sheet_collapses.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_bottom_sheet_expanded.webp b/app/src/main/res/drawable-xxxhdpi/bg_bottom_sheet_expanded.webp new file mode 100644 index 0000000000..aa5370f8d0 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_bottom_sheet_expanded.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_commodity_cover.webp b/app/src/main/res/drawable-xxxhdpi/bg_commodity_cover.webp new file mode 100644 index 0000000000..9108acd695 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_commodity_cover.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_commodity_item.webp b/app/src/main/res/drawable-xxxhdpi/bg_commodity_item.webp new file mode 100644 index 0000000000..1ce66bb3cd Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_commodity_item.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_commodity_tag.webp b/app/src/main/res/drawable-xxxhdpi/bg_commodity_tag.webp new file mode 100644 index 0000000000..7103d903fa Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_commodity_tag.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_energy_center_day.webp b/app/src/main/res/drawable-xxxhdpi/bg_energy_center_day.webp deleted file mode 100644 index e4de495d62..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/bg_energy_center_day.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_energy_center_night.webp b/app/src/main/res/drawable-xxxhdpi/bg_energy_center_night.webp deleted file mode 100644 index 4c408e3c1a..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/bg_energy_center_night.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_energy_center_top.webp b/app/src/main/res/drawable-xxxhdpi/bg_energy_center_top.webp new file mode 100644 index 0000000000..7bb9f9b46d Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_energy_center_top.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_energy_house.webp b/app/src/main/res/drawable-xxxhdpi/bg_energy_house.webp index 69f6559678..6066354d5f 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/bg_energy_house.webp and b/app/src/main/res/drawable-xxxhdpi/bg_energy_house.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_energy_house_roll_notice.webp b/app/src/main/res/drawable-xxxhdpi/bg_energy_house_roll_notice.webp new file mode 100644 index 0000000000..a3b9f475e1 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_energy_house_roll_notice.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_energy_sign_dialog.webp b/app/src/main/res/drawable-xxxhdpi/bg_energy_sign_dialog.webp new file mode 100644 index 0000000000..b0c53de4af Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_energy_sign_dialog.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_energy_task_btn_finished.webp b/app/src/main/res/drawable-xxxhdpi/bg_energy_task_btn_finished.webp new file mode 100644 index 0000000000..a4af4ebf2d Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_energy_task_btn_finished.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_energy_task_btn_normal.webp b/app/src/main/res/drawable-xxxhdpi/bg_energy_task_btn_normal.webp new file mode 100644 index 0000000000..8a6b062581 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_energy_task_btn_normal.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_energy_value.webp b/app/src/main/res/drawable-xxxhdpi/bg_energy_value.webp new file mode 100644 index 0000000000..f7da39ab22 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_energy_value.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_house_bottom_sheet_collapses.webp b/app/src/main/res/drawable-xxxhdpi/bg_house_bottom_sheet_collapses.webp new file mode 100644 index 0000000000..fbd8898ebc Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_house_bottom_sheet_collapses.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_login.webp b/app/src/main/res/drawable-xxxhdpi/bg_login.webp deleted file mode 100644 index 74a616a357..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/bg_login.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_novice_tasks.webp b/app/src/main/res/drawable-xxxhdpi/bg_novice_tasks.webp new file mode 100644 index 0000000000..5baa09134e Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_novice_tasks.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_task_bottom.webp b/app/src/main/res/drawable-xxxhdpi/bg_task_bottom.webp new file mode 100644 index 0000000000..f510454845 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_task_bottom.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/bg_task_top.webp b/app/src/main/res/drawable-xxxhdpi/bg_task_top.webp new file mode 100644 index 0000000000..8b15d65fa8 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_task_top.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_arrow_blue.png b/app/src/main/res/drawable-xxxhdpi/ic_arrow_blue.png deleted file mode 100644 index b51543329d..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_arrow_blue.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_arrow_blue.webp b/app/src/main/res/drawable-xxxhdpi/ic_arrow_blue.webp new file mode 100644 index 0000000000..8961bbefbc Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_arrow_blue.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_arrow_down_blue.png b/app/src/main/res/drawable-xxxhdpi/ic_arrow_down_blue.png new file mode 100644 index 0000000000..84f088a92e Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_arrow_down_blue.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_arrow_down_grey.webp b/app/src/main/res/drawable-xxxhdpi/ic_arrow_down_grey.webp new file mode 100644 index 0000000000..b723810cd7 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_arrow_down_grey.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_arrow_up_blue.png b/app/src/main/res/drawable-xxxhdpi/ic_arrow_up_blue.png new file mode 100644 index 0000000000..61894f2129 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_arrow_up_blue.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_arrow_up_grey.webp b/app/src/main/res/drawable-xxxhdpi/ic_arrow_up_grey.webp new file mode 100644 index 0000000000..a70a781717 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_arrow_up_grey.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_arrow_up_light_blue.png b/app/src/main/res/drawable-xxxhdpi/ic_arrow_up_light_blue.png new file mode 100644 index 0000000000..38460cf3d9 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_arrow_up_light_blue.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_choose_activity.webp b/app/src/main/res/drawable-xxxhdpi/ic_choose_activity.webp new file mode 100644 index 0000000000..1cf12aa492 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_choose_activity.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_dot_more.png b/app/src/main/res/drawable-xxxhdpi/ic_dot_more.png new file mode 100644 index 0000000000..4b7321fd16 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_dot_more.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_downloading_hint.webp b/app/src/main/res/drawable-xxxhdpi/ic_downloading_hint.webp new file mode 100644 index 0000000000..219a67df1a Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_downloading_hint.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_energy_center_done.webp b/app/src/main/res/drawable-xxxhdpi/ic_energy_center_done.webp deleted file mode 100644 index 91b4014f6d..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_energy_center_done.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_energy_center_invite.webp b/app/src/main/res/drawable-xxxhdpi/ic_energy_center_invite.webp new file mode 100644 index 0000000000..1f17206a34 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_energy_center_invite.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_energy_center_more.png b/app/src/main/res/drawable-xxxhdpi/ic_energy_center_more.png deleted file mode 100755 index 60bf040bbe..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_energy_center_more.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_energy_center_sign.webp b/app/src/main/res/drawable-xxxhdpi/ic_energy_center_sign.webp index 953bfd59df..9b8efee3ed 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_energy_center_sign.webp and b/app/src/main/res/drawable-xxxhdpi/ic_energy_center_sign.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_energy_center_sign_normal.webp b/app/src/main/res/drawable-xxxhdpi/ic_energy_center_sign_normal.webp index 1091899a70..5cc40ee9b8 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_energy_center_sign_normal.webp and b/app/src/main/res/drawable-xxxhdpi/ic_energy_center_sign_normal.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_energy_center_signed.webp b/app/src/main/res/drawable-xxxhdpi/ic_energy_center_signed.webp index b0e7986c7f..6139c2d2d6 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_energy_center_signed.webp and b/app/src/main/res/drawable-xxxhdpi/ic_energy_center_signed.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_energy_center_top_energy.webp b/app/src/main/res/drawable-xxxhdpi/ic_energy_center_top_energy.webp index 5b73fdf836..fe0aab95bc 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_energy_center_top_energy.webp and b/app/src/main/res/drawable-xxxhdpi/ic_energy_center_top_energy.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_energy_tab_indicator.png b/app/src/main/res/drawable-xxxhdpi/ic_energy_tab_indicator.png new file mode 100755 index 0000000000..87d6ec6bc2 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_energy_tab_indicator.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_exchange_commodity.webp b/app/src/main/res/drawable-xxxhdpi/ic_exchange_commodity.webp new file mode 100644 index 0000000000..ee29433c00 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_exchange_commodity.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_gamedetail_switch_install.webp b/app/src/main/res/drawable-xxxhdpi/ic_gamedetail_switch_install.webp new file mode 100644 index 0000000000..5bf37120b3 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_gamedetail_switch_install.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_install_arrow.webp b/app/src/main/res/drawable-xxxhdpi/ic_install_arrow.webp new file mode 100644 index 0000000000..34e1bf6cea Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_install_arrow.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_install_close.webp b/app/src/main/res/drawable-xxxhdpi/ic_install_close.webp new file mode 100644 index 0000000000..d2c117d502 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_install_close.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_install_hint.webp b/app/src/main/res/drawable-xxxhdpi/ic_install_hint.webp new file mode 100644 index 0000000000..a76536b295 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_install_hint.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_install_method_hint.png b/app/src/main/res/drawable-xxxhdpi/ic_install_method_hint.png new file mode 100644 index 0000000000..2f50ce093d Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_install_method_hint.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_install_method_hint.webp b/app/src/main/res/drawable-xxxhdpi/ic_install_method_hint.webp deleted file mode 100644 index 14046b7456..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_install_method_hint.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_libao_code_copy.png b/app/src/main/res/drawable-xxxhdpi/ic_libao_code_copy.png new file mode 100644 index 0000000000..4bf992c669 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_libao_code_copy.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_login_logo.webp b/app/src/main/res/drawable-xxxhdpi/ic_login_logo.webp deleted file mode 100644 index 857b5d3af8..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_login_logo.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_lottery_paradise.webp b/app/src/main/res/drawable-xxxhdpi/ic_lottery_paradise.webp new file mode 100644 index 0000000000..38c924e3c5 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_lottery_paradise.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_pull_down_tip.webp b/app/src/main/res/drawable-xxxhdpi/ic_pull_down_tip.webp new file mode 100644 index 0000000000..2bf4c17fd9 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_pull_down_tip.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_recommend_activity.webp b/app/src/main/res/drawable-xxxhdpi/ic_recommend_activity.webp deleted file mode 100644 index 4dd50dfeee..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_recommend_activity.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_recommend_age12.webp b/app/src/main/res/drawable-xxxhdpi/ic_recommend_age12.webp new file mode 100644 index 0000000000..6b61a7e5c6 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_recommend_age12.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_recommend_age16.webp b/app/src/main/res/drawable-xxxhdpi/ic_recommend_age16.webp new file mode 100644 index 0000000000..bc2b91dd07 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_recommend_age16.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_recommend_age8.webp b/app/src/main/res/drawable-xxxhdpi/ic_recommend_age8.webp new file mode 100644 index 0000000000..4265016b21 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_recommend_age8.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_recommend_discount.webp b/app/src/main/res/drawable-xxxhdpi/ic_recommend_discount.webp deleted file mode 100644 index a115ee3c72..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_recommend_discount.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_recommend_function.webp b/app/src/main/res/drawable-xxxhdpi/ic_recommend_function.webp deleted file mode 100644 index b663dc122f..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_recommend_function.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_recommend_gift.webp b/app/src/main/res/drawable-xxxhdpi/ic_recommend_gift.webp deleted file mode 100644 index 7de7d2cf76..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_recommend_gift.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_recommend_role.webp b/app/src/main/res/drawable-xxxhdpi/ic_recommend_role.webp deleted file mode 100644 index a377af987d..0000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_recommend_role.webp and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/pic_commodity_no_data.webp b/app/src/main/res/drawable-xxxhdpi/pic_commodity_no_data.webp new file mode 100644 index 0000000000..1344da702c Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/pic_commodity_no_data.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/pic_daily_task_title.webp b/app/src/main/res/drawable-xxxhdpi/pic_daily_task_title.webp new file mode 100644 index 0000000000..e603bf17a8 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/pic_daily_task_title.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/pic_earn_energy.webp b/app/src/main/res/drawable-xxxhdpi/pic_earn_energy.webp new file mode 100644 index 0000000000..a3e201dc65 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/pic_earn_energy.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/pic_energy_rule.webp b/app/src/main/res/drawable-xxxhdpi/pic_energy_rule.webp new file mode 100644 index 0000000000..99123d170e Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/pic_energy_rule.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/pic_energy_sign_dialog_top.webp b/app/src/main/res/drawable-xxxhdpi/pic_energy_sign_dialog_top.webp new file mode 100644 index 0000000000..0411424735 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/pic_energy_sign_dialog_top.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/pic_exchange_rule.webp b/app/src/main/res/drawable-xxxhdpi/pic_exchange_rule.webp new file mode 100644 index 0000000000..b39280e5a9 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/pic_exchange_rule.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/pic_fix_task_title.webp b/app/src/main/res/drawable-xxxhdpi/pic_fix_task_title.webp new file mode 100644 index 0000000000..69be1e0cfb Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/pic_fix_task_title.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/pic_novice_task_title.webp b/app/src/main/res/drawable-xxxhdpi/pic_novice_task_title.webp new file mode 100644 index 0000000000..b434c29ede Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/pic_novice_task_title.webp differ diff --git a/app/src/main/res/drawable/bg_browser_install_hint.xml b/app/src/main/res/drawable/bg_browser_install_hint.xml new file mode 100644 index 0000000000..991a3e85f0 --- /dev/null +++ b/app/src/main/res/drawable/bg_browser_install_hint.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_energy_house_roll_notice.xml b/app/src/main/res/drawable/bg_energy_house_roll_notice.xml deleted file mode 100644 index 9f21c282bd..0000000000 --- a/app/src/main/res/drawable/bg_energy_house_roll_notice.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_install_hint.xml b/app/src/main/res/drawable/bg_install_hint.xml new file mode 100644 index 0000000000..6284917b29 --- /dev/null +++ b/app/src/main/res/drawable/bg_install_hint.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button_round_50dcdc.xml b/app/src/main/res/drawable/button_round_00dba4.xml similarity index 79% rename from app/src/main/res/drawable/button_round_50dcdc.xml rename to app/src/main/res/drawable/button_round_00dba4.xml index f7edbb30dc..3667aa72af 100644 --- a/app/src/main/res/drawable/button_round_50dcdc.xml +++ b/app/src/main/res/drawable/button_round_00dba4.xml @@ -4,6 +4,6 @@ - + \ No newline at end of file diff --git a/app/src/main/res/drawable/button_round_806f9cef.xml b/app/src/main/res/drawable/button_round_806f9cef.xml deleted file mode 100644 index 5e0baa7e01..0000000000 --- a/app/src/main/res/drawable/button_round_806f9cef.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/button_round_e6f9fa.xml b/app/src/main/res/drawable/button_round_ebf9fa.xml similarity index 79% rename from app/src/main/res/drawable/button_round_e6f9fa.xml rename to app/src/main/res/drawable/button_round_ebf9fa.xml index 76845b1e20..fc010012c3 100644 --- a/app/src/main/res/drawable/button_round_e6f9fa.xml +++ b/app/src/main/res/drawable/button_round_ebf9fa.xml @@ -4,6 +4,6 @@ - + \ No newline at end of file diff --git a/app/src/main/res/drawable/divider_1dp.xml b/app/src/main/res/drawable/divider_1dp.xml new file mode 100644 index 0000000000..ad8fff68c7 --- /dev/null +++ b/app/src/main/res/drawable/divider_1dp.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/divider_1px.xml b/app/src/main/res/drawable/divider_1px.xml new file mode 100644 index 0000000000..9ab42cb136 --- /dev/null +++ b/app/src/main/res/drawable/divider_1px.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_blue.xml b/app/src/main/res/drawable/gradient_blue.xml new file mode 100644 index 0000000000..8982cff9ed --- /dev/null +++ b/app/src/main/res/drawable/gradient_blue.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_cyan.xml b/app/src/main/res/drawable/gradient_cyan.xml new file mode 100644 index 0000000000..e982451c3a --- /dev/null +++ b/app/src/main/res/drawable/gradient_cyan.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_green.xml b/app/src/main/res/drawable/gradient_green.xml new file mode 100644 index 0000000000..653f7c462e --- /dev/null +++ b/app/src/main/res/drawable/gradient_green.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_light_yellow.xml b/app/src/main/res/drawable/gradient_light_yellow.xml new file mode 100644 index 0000000000..dacfb61642 --- /dev/null +++ b/app/src/main/res/drawable/gradient_light_yellow.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_orange.xml b/app/src/main/res/drawable/gradient_orange.xml new file mode 100644 index 0000000000..cdf94277ee --- /dev/null +++ b/app/src/main/res/drawable/gradient_orange.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_purple_blue.xml b/app/src/main/res/drawable/gradient_purple_blue.xml new file mode 100644 index 0000000000..082fcfcd56 --- /dev/null +++ b/app/src/main/res/drawable/gradient_purple_blue.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_yelow.xml b/app/src/main/res/drawable/gradient_yelow.xml new file mode 100644 index 0000000000..fec83edafc --- /dev/null +++ b/app/src/main/res/drawable/gradient_yelow.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/oval_ebf9fa_bg.xml b/app/src/main/res/drawable/oval_ebf9fa_bg.xml new file mode 100644 index 0000000000..e71c0485b2 --- /dev/null +++ b/app/src/main/res/drawable/oval_ebf9fa_bg.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/commodity_item.xml b/app/src/main/res/layout/commodity_item.xml index 2dbc0472de..48db33802d 100644 --- a/app/src/main/res/layout/commodity_item.xml +++ b/app/src/main/res/layout/commodity_item.xml @@ -19,25 +19,30 @@ android:layout_marginLeft="4dp" android:layout_marginRight="4dp" android:layout_centerHorizontal="true" - android:background="@drawable/background_shape_white_radius_8"> + android:background="@drawable/bg_commodity_item"> - + app:layout_constraintTop_toTopOf="parent"> + + + + tools:text="答题先锋答题先锋答题先锋答题先锋答题先锋答题先锋" /> - + android:background="#E9F3FF"> - + - + - + - + - + - - + + + \ No newline at end of file diff --git a/app/src/main/res/layout/detail_download_item.xml b/app/src/main/res/layout/detail_download_item.xml index 7e3da5b63e..a143a5f716 100644 --- a/app/src/main/res/layout/detail_download_item.xml +++ b/app/src/main/res/layout/detail_download_item.xml @@ -24,14 +24,14 @@ android:id="@+id/browser_install_hint_container" android:layout_width="match_parent" android:layout_height="40dp" - android:background="@color/bg_FFF6E6" + android:background="@drawable/bg_browser_install_hint" android:visibility="gone" tools:visibility="visible"> @@ -44,6 +44,8 @@ android:layout_marginLeft="8dp" android:layout_toRightOf="@id/browser_install_hint_iv" android:textColor="@color/text_F9A755" + android:textSize="12sp" + app:lineHeight="12dp" tools:text="VIVO手机如何解决安装需要密码" /> + + + + + + + + + + + + + + - + android:paddingTop="10dp" + android:paddingEnd="20dp" + android:paddingBottom="10dp"> - + + + + + + + + - + android:layout_marginStart="24dp" + android:layout_marginLeft="24dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/iv_switch" + app:layout_constraintTop_toTopOf="parent" /> + diff --git a/app/src/main/res/layout/dialog_apply_moderator.xml b/app/src/main/res/layout/dialog_apply_moderator.xml index 7c3ff8b2e8..9cd630d545 100644 --- a/app/src/main/res/layout/dialog_apply_moderator.xml +++ b/app/src/main/res/layout/dialog_apply_moderator.xml @@ -22,6 +22,7 @@ android:id="@+id/titleTv" android:layout_width="match_parent" android:layout_height="wrap_content" + android:includeFontPadding="false" android:text="提交申请成功" android:textAlignment="center" android:textColor="@color/text_333333" @@ -31,58 +32,31 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - - - - - - - + app:layout_constraintTop_toBottomOf="@+id/titleTv" + app:lineHeight="22dp" + tools:text="版主考核群:\n感谢你对论坛建设的支持\n请加入版主考核群并联系群主进行版主资格考核" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_game_detail_more.xml b/app/src/main/res/layout/dialog_game_detail_more.xml index 7ec5123f2e..2041687489 100644 --- a/app/src/main/res/layout/dialog_game_detail_more.xml +++ b/app/src/main/res/layout/dialog_game_detail_more.xml @@ -143,36 +143,43 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/share_container" /> - - + - + - - + + + + + + app:layout_constraintTop_toBottomOf="@+id/action_scrollview" /> \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_report_reason.xml b/app/src/main/res/layout/dialog_report_reason.xml index 5bade728cb..0ea4587fb8 100644 --- a/app/src/main/res/layout/dialog_report_reason.xml +++ b/app/src/main/res/layout/dialog_report_reason.xml @@ -5,7 +5,7 @@ @@ -24,12 +24,18 @@ - + + @@ -9,6 +11,41 @@ android:layout_height="match_parent" android:background="@color/white" /> + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_commodity_list.xml b/app/src/main/res/layout/fragment_commodity_list.xml index 8dcb7c7e85..7728db8e52 100644 --- a/app/src/main/res/layout/fragment_commodity_list.xml +++ b/app/src/main/res/layout/fragment_commodity_list.xml @@ -21,7 +21,7 @@ android:id="@+id/header" android:layout_width="match_parent" android:layout_height="48dp" - android:background="@color/white"> + android:background="@color/transparent"> + android:layout_width="156dp" + android:layout_height="120dp" + android:src="@drawable/pic_commodity_no_data" /> + android:text="暂时没有商品哦~" + android:textColor="#A4EBEB" + android:textSize="14sp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_energy_center.xml b/app/src/main/res/layout/fragment_energy_center.xml index d21d260deb..bd28bc16db 100644 --- a/app/src/main/res/layout/fragment_energy_center.xml +++ b/app/src/main/res/layout/fragment_energy_center.xml @@ -3,19 +3,140 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/cl" + android:background="@color/white" android:layout_width="match_parent" android:layout_height="match_parent"> + android:layout_height="match_parent" + android:background="@color/white"> + android:layout_height="400dp" + android:scaleType="fitXY" + android:src="@drawable/bg_energy_center_top" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + android:layout_width="73dp" + android:layout_height="22dp" + android:layout_marginTop="13dp" + android:layout_marginLeft="47dp" + android:clipChildren="false" + android:gravity="center_vertical"> + android:textSize="14sp" + android:text="0"/> - - + + + + android:src="@drawable/pic_energy_rule" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_energy_house.xml b/app/src/main/res/layout/fragment_energy_house.xml index e763261203..65c0104cfe 100644 --- a/app/src/main/res/layout/fragment_energy_house.xml +++ b/app/src/main/res/layout/fragment_energy_house.xml @@ -1,261 +1,228 @@ - - + android:layout_height="wrap_content"> - + - + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintLeft_toLeftOf="parent" /> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + android:background="#FF4DCCD3" /> + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_height="44dp" + android:paddingBottom="8dp"> + + + + + + android:background="#CCFCFF" /> - - + + + + + + + android:layout_height="wrap_content"> - + - + - \ No newline at end of file + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_game.xml b/app/src/main/res/layout/fragment_game.xml index 31794cd782..09ba71fd53 100644 --- a/app/src/main/res/layout/fragment_game.xml +++ b/app/src/main/res/layout/fragment_game.xml @@ -30,8 +30,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" - android:clipToPadding="false" - android:paddingTop="@dimen/home_recyclerview_padding_top" /> + android:clipToPadding="false" /> diff --git a/app/src/main/res/layout/fragment_game_servers_publish.xml b/app/src/main/res/layout/fragment_game_servers_publish.xml new file mode 100644 index 0000000000..bddfe8dc64 --- /dev/null +++ b/app/src/main/res/layout/fragment_game_servers_publish.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_game_updatable.xml b/app/src/main/res/layout/fragment_game_updatable.xml new file mode 100644 index 0000000000..378a1981e2 --- /dev/null +++ b/app/src/main/res/layout/fragment_game_updatable.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 35306aeac2..7e12debc5b 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -57,15 +57,15 @@ app:layout_constraintTop_toTopOf="parent"> + app:layout_constraintTop_toTopOf="parent" + app:placeholderImage="@drawable/bg_home_user_info" + app:placeholderImageScaleType="fitXY" /> + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + tools:layout_height="96dp" + tools:layout_width="96dp" /> + tools:visibility="visible" /> + app:layout_constraintTop_toTopOf="@+id/user_icon" + tools:text="我的名字很长的哟" /> + android:paddingLeft="4dp" + android:paddingRight="4dp" + android:visibility="gone" + tools:visibility="visible"> + android:paddingLeft="4dp" + android:visibility="gone" + tools:visibility="visible"> + android:layout_marginRight="2dp" + android:layout_toRightOf="@+id/badge_icon" + android:gravity="center_vertical" + android:orientation="horizontal"> + android:src="@drawable/ic_my_badge" + android:visibility="gone" + tools:visibility="visible" /> + android:visibility="gone" + tools:text="3" + tools:visibility="visible" /> + android:src="@drawable/ic_badge_tv" + android:visibility="gone" + tools:visibility="visible" /> + android:visibility="gone" + tools:visibility="visible" /> - + android:src="@drawable/ic_regulation_tag" + tools:visibility="visible"> + app:layout_constraintTop_toBottomOf="@+id/regulation_and_badge_container" + tools:visibility="visible"> + app:placeholderImage="@drawable/ic_auth" + app:roundAsCircle="true" /> @@ -301,33 +301,33 @@ android:id="@+id/user_introduce" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="16dp" android:layout_marginLeft="16dp" + android:layout_marginTop="16dp" android:layout_marginRight="16dp" + android:ellipsize="end" android:includeFontPadding="false" android:lineSpacingExtra="5dp" android:maxLines="2" - android:ellipsize="end" + android:text='@{TextUtils.isEmpty(entity.introduce)?"这是一个很神秘的崽~":entity.introduce}' android:textColor="@color/white" android:textSize="12sp" - android:text='@{TextUtils.isEmpty(entity.introduce)?"这是一个很神秘的崽~":entity.introduce}' - tools:text="这是我的个性签名呀欢迎大家来撩,特别长的签名,很长很长,这是我的个性签名呀欢迎大家来撩,特别长的签名,很长很长,这是我的个性签名呀欢迎大家来撩,特别长的签名,很长很长这是我的个性签名呀欢迎大家来撩,特别长的签名,很长很长这是我的个性签名呀欢迎大家来撩,特别长的签名,很长很长这是我的个性签名呀欢迎大家来撩,特别长的签名,很长很长" app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintTop_toBottomOf="@+id/auth_container" /> + app:layout_constraintTop_toBottomOf="@+id/auth_container" + tools:text="这是我的个性签名呀欢迎大家来撩,特别长的签名,很长很长,这是我的个性签名呀欢迎大家来撩,特别长的签名,很长很长,这是我的个性签名呀欢迎大家来撩,特别长的签名,很长很长这是我的个性签名呀欢迎大家来撩,特别长的签名,很长很长这是我的个性签名呀欢迎大家来撩,特别长的签名,很长很长这是我的个性签名呀欢迎大家来撩,特别长的签名,很长很长" /> + tools:visibility="visible"> + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + android:orientation="horizontal" + app:layout_constraintLeft_toRightOf="@+id/recent_visit_tv" + app:layout_constraintTop_toTopOf="parent"> + imageUrl="@{entity.lastVisitor.icon}" + visibleGone="@{!TextUtils.isEmpty(entity.lastVisitor.icon)}" + android:layout_width="12dp" + android:layout_height="12dp" /> @@ -376,47 +376,49 @@ android:id="@+id/today_visit_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:includeFontPadding="false" android:layout_marginTop="5dp" + android:includeFontPadding="false" + android:text="@string/today_visit" android:textColor="@color/white" android:textSize="10sp" - android:text="@string/today_visit" - app:layout_constraintTop_toBottomOf="@+id/recent_visit_tv" - app:layout_constraintLeft_toLeftOf="parent" /> + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintTop_toBottomOf="@+id/recent_visit_tv" /> + app:layout_constraintRight_toRightOf="@+id/recentVisitRightContainer" + app:layout_constraintTop_toBottomOf="@+id/recentVisitRightContainer" /> + android:orientation="horizontal" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintTop_toBottomOf="@+id/user_introduce"> + android:orientation="horizontal" + android:paddingLeft="16dp" + android:paddingTop="20dp" + android:paddingRight="12dp" + android:paddingBottom="20dp"> + android:orientation="horizontal" + android:paddingLeft="12dp" + android:paddingTop="20dp" + android:paddingRight="12dp" + android:paddingBottom="20dp"> + android:orientation="horizontal" + android:paddingLeft="12dp" + android:paddingTop="20dp" + android:paddingRight="24dp" + android:paddingBottom="20dp"> + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="@+id/user_icon" + tools:visibility="visible"> + android:textSize="14sp" /> + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="@+id/user_icon" /> + tools:visibility="visible"> + app:layout_constraintRight_toRightOf="@+id/user_change_bg_btn" + app:layout_constraintTop_toBottomOf="@+id/user_change_bg_btn"> + android:textSize="12sp" /> + app:layout_constraintRight_toRightOf="parent" /> + app:navigationIcon="@null"> @@ -670,37 +678,37 @@ android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginTop="3dp" + android:text="@{entity.name}" android:textColor="@color/white" android:textSize="14sp" - android:text="@{entity.name}" tools:text="姓名" /> + android:src="@drawable/ic_share" + android:visibility="gone" /> + android:src="@drawable/ic_user_home_more" + android:visibility="gone" /> diff --git a/app/src/main/res/layout/fragment_kaifu_content.xml b/app/src/main/res/layout/fragment_kaifu_content.xml index 3c0a7a661a..0cb189475b 100644 --- a/app/src/main/res/layout/fragment_kaifu_content.xml +++ b/app/src/main/res/layout/fragment_kaifu_content.xml @@ -1,12 +1,34 @@ + android:layout_height="match_parent" + android:overScrollMode="never" /> + + + + - - - - - - - - - - - - - - - + android:layout_height="wrap_content" /> + android:background="@color/white" + android:fitsSystemWindows="false"> + @@ -53,11 +54,11 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" app:avatar_width="64dp" - app:badge_width="23dp" /> + app:badge_width="18dp" + app:border_width="4dp" /> + app:layout_constraintTop_toTopOf="@+id/personal_user_icon_container" + tools:visibility="gone" /> + tools:text="姓名" + tools:visibility="visible" /> + android:paddingLeft="4dp" + android:visibility="gone" + tools:visibility="visible"> + android:layout_marginRight="2dp" + android:layout_toRightOf="@+id/personal_badge_icon" + android:gravity="center_vertical" + android:orientation="horizontal"> + android:src="@drawable/ic_my_badge" + android:visibility="gone" + tools:visibility="visible" /> + android:visibility="gone" + tools:text="3" + tools:visibility="visible" /> + android:src="@drawable/ic_badge_tv" + android:visibility="gone" + tools:visibility="visible" /> + android:visibility="gone" + tools:visibility="visible" /> @@ -179,10 +181,10 @@ android:id="@+id/personal_home" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingTop="15dp" android:paddingLeft="15dp" - android:paddingBottom="15dp" + android:paddingTop="15dp" android:paddingRight="6dp" + android:paddingBottom="15dp" android:text="个人主页" android:textColor="@color/white" android:textSize="12sp" @@ -200,15 +202,15 @@ app:layout_constraintTop_toTopOf="@+id/personal_user_icon_container" /> + app:layout_constraintTop_toTopOf="@+id/personal_home" /> @@ -216,14 +218,14 @@ android:id="@+id/personal_energy_container" android:layout_width="match_parent" android:layout_height="92dp" - android:layout_marginTop="156dp" android:layout_marginLeft="16dp" + android:layout_marginTop="156dp" android:layout_marginRight="16dp" - android:orientation="horizontal" android:gravity="center" + android:orientation="horizontal" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintLeft_toRightOf="parent" - app:layout_constraintBottom_toBottomOf="parent"> + app:layout_constraintLeft_toRightOf="parent"> + android:textSize="11sp" /> + android:paddingTop="16dp" + android:visibility="gone"> + android:textSize="11sp" /> @@ -300,9 +302,9 @@ android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" - android:paddingTop="16dp" android:gravity="center_horizontal" - android:orientation="vertical"> + android:orientation="vertical" + android:paddingTop="16dp"> + android:textSize="11sp" /> + android:orientation="vertical" + android:paddingTop="16dp"> + android:textSize="11sp" /> + android:orientation="vertical" + android:paddingTop="16dp"> + android:textSize="11sp" /> @@ -456,7 +458,7 @@ android:textColor="@android:color/white" android:textSize="8sp" android:textStyle="bold" - tools:text="12"/> + tools:text="12" /> diff --git a/app/src/main/res/layout/fragment_new_personal_stub.xml b/app/src/main/res/layout/fragment_new_personal_stub.xml index 391830aec6..085c41a222 100644 --- a/app/src/main/res/layout/fragment_new_personal_stub.xml +++ b/app/src/main/res/layout/fragment_new_personal_stub.xml @@ -1,11 +1,18 @@ - + - + + + + - + android:layout_height="match_parent"> + + + + diff --git a/app/src/main/res/layout/fragment_personal.xml b/app/src/main/res/layout/fragment_personal.xml index 19640c9540..9c286e02e5 100644 --- a/app/src/main/res/layout/fragment_personal.xml +++ b/app/src/main/res/layout/fragment_personal.xml @@ -3,15 +3,15 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/list_refresh" - android:fitsSystemWindows="false" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:fitsSystemWindows="false"> + android:background="@drawable/shadow_personal_bg" + android:visibility="gone" /> + app:badge_width="18dp" + app:border_width="4dp" /> + app:layout_constraintTop_toTopOf="@+id/personal_user_icon_container" + tools:visibility="gone" /> + tools:text="姓名" + tools:visibility="visible" /> + android:paddingLeft="4dp" + android:visibility="gone" + tools:visibility="visible"> + android:layout_marginRight="2dp" + android:layout_toRightOf="@+id/personal_badge_icon" + android:gravity="center_vertical" + android:orientation="horizontal"> + android:src="@drawable/ic_my_badge" + android:visibility="gone" + tools:visibility="visible" /> + android:visibility="gone" + tools:text="3" + tools:visibility="visible" /> + android:src="@drawable/ic_badge_tv" + android:visibility="gone" + tools:visibility="visible" /> + android:visibility="gone" + tools:visibility="visible" /> @@ -199,10 +200,10 @@ android:id="@+id/personal_home" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingTop="15dp" android:paddingLeft="15dp" - android:paddingBottom="15dp" + android:paddingTop="15dp" android:paddingRight="6dp" + android:paddingBottom="15dp" android:text="个人主页" android:textColor="@color/white" android:textSize="12sp" @@ -221,15 +222,15 @@ + app:layout_constraintTop_toTopOf="@+id/personal_home" /> @@ -333,7 +334,7 @@ android:textColor="@android:color/white" android:textSize="8sp" android:textStyle="bold" - tools:text="12"/> + tools:text="12" /> diff --git a/app/src/main/res/layout/fragment_personal_stub.xml b/app/src/main/res/layout/fragment_personal_stub.xml index 0be2c48211..07fe4e8511 100644 --- a/app/src/main/res/layout/fragment_personal_stub.xml +++ b/app/src/main/res/layout/fragment_personal_stub.xml @@ -1,11 +1,18 @@ - + - + + + + - + android:layout_height="match_parent"> + + + + diff --git a/app/src/main/res/layout/fragment_search_default.xml b/app/src/main/res/layout/fragment_search_default.xml index 3e240eda72..1f73e69e92 100644 --- a/app/src/main/res/layout/fragment_search_default.xml +++ b/app/src/main/res/layout/fragment_search_default.xml @@ -119,7 +119,8 @@ android:textSize="14sp" android:textStyle="bold" app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintTop_toBottomOf="@id/hot_tag_flex_container" /> + app:layout_constraintTop_toBottomOf="@id/hot_tag_flex_container" + app:lazyPaddingTop="@{!isExistHistory && !isExistHotTag ? 16 : 32}" /> - - @@ -172,7 +168,7 @@ android:ellipsize="end" android:includeFontPadding="false" android:singleLine="true" - android:text="@{(game.apk.size > 0 && !hideSize && (TextUtils.isEmpty(briefStyle)||briefStyle.contains(`size`)||briefStyle.contains(`recommend`))) ? game.getApk().get(0).getSize() + ` ` + game.brief : game.brief }" + android:text="@{game.decoratedDes}" android:textColor="@color/text_999999" android:textSize="10sp" tools:text="巫妖王再怒霜之哀殤又飢渴" /> @@ -233,11 +229,10 @@ android:paddingEnd="8dp" android:visibility="gone"> - diff --git a/app/src/main/res/layout/gamedetail_body.xml b/app/src/main/res/layout/gamedetail_body.xml index 721eec8c77..a3cd992b4f 100644 --- a/app/src/main/res/layout/gamedetail_body.xml +++ b/app/src/main/res/layout/gamedetail_body.xml @@ -37,7 +37,7 @@ - + android:layout_marginRight="12dp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + android:layout_height="68dp" + android:layout_marginLeft="8dp" + android:orientation="vertical" + android:gravity="center_vertical" + app:layout_constraintEnd_toStartOf="@+id/rating_score_container" + app:layout_constraintStart_toEndOf="@+id/gameIconContainer" + app:layout_constraintTop_toTopOf="@+id/gameIconContainer"> + tools:text="地海争霸2" /> + + - + + + + app:layout_constraintRight_toLeftOf="@+id/followTv" + tools:text="龙之谷龙之谷龙之谷龙之谷龙之谷龙之谷龙之谷龙之谷龙之谷龙之谷龙之谷龙之谷龙之谷" /> + tools:text="答题先锋"/> + app:layout_constraintTop_toTopOf="parent" /> @@ -174,6 +175,7 @@ android:id="@+id/originalTv" android:layout_width="28dp" android:layout_height="16dp" + android:layout_marginLeft="20dp" android:layout_marginTop="12dp" android:background="@drawable/bg_border_original" android:gravity="center" @@ -182,7 +184,6 @@ android:textColor="@color/theme_font" android:textSize="10sp" android:visibility="gone" - android:layout_marginLeft="20dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/desTv" /> @@ -191,14 +192,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" /> - - diff --git a/app/src/main/res/layout/item_game_libao.xml b/app/src/main/res/layout/item_game_libao.xml index 9413918633..238973f5a2 100644 --- a/app/src/main/res/layout/item_game_libao.xml +++ b/app/src/main/res/layout/item_game_libao.xml @@ -75,6 +75,17 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + android:paddingLeft="16dp" + android:paddingRight="16dp"> diff --git a/app/src/main/res/layout/item_report_reason.xml b/app/src/main/res/layout/item_report_reason.xml new file mode 100644 index 0000000000..5999270b93 --- /dev/null +++ b/app/src/main/res/layout/item_report_reason.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_updatable_game.xml b/app/src/main/res/layout/item_updatable_game.xml new file mode 100644 index 0000000000..ea7a8c2434 --- /dev/null +++ b/app/src/main/res/layout/item_updatable_game.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_updatable_game_header.xml b/app/src/main/res/layout/item_updatable_game_header.xml new file mode 100644 index 0000000000..3252d3edb0 --- /dev/null +++ b/app/src/main/res/layout/item_updatable_game_header.xml @@ -0,0 +1,36 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_updatable_other_game_hint.xml b/app/src/main/res/layout/item_updatable_other_game_hint.xml new file mode 100644 index 0000000000..0cea46207b --- /dev/null +++ b/app/src/main/res/layout/item_updatable_other_game_hint.xml @@ -0,0 +1,35 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_video_desc_top.xml b/app/src/main/res/layout/item_video_desc_top.xml index 447ecb87aa..a840a950de 100644 --- a/app/src/main/res/layout/item_video_desc_top.xml +++ b/app/src/main/res/layout/item_video_desc_top.xml @@ -48,6 +48,20 @@ app:layout_constraintTop_toTopOf="@+id/userAvatar" tools:text="多勒密法索拉斯多" /> + + + android:background="@color/white" + android:orientation="vertical"> - - - + android:layout_height="8dp" /> + + + + + + + + - \ No newline at end of file diff --git a/app/src/main/res/layout/layout_filter_category.xml b/app/src/main/res/layout/layout_filter_category.xml index 39114e595e..95530ac5e5 100644 --- a/app/src/main/res/layout/layout_filter_category.xml +++ b/app/src/main/res/layout/layout_filter_category.xml @@ -10,7 +10,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" - android:background="@color/white"> + android:background="#F5FEFF"> + + + @@ -51,6 +54,7 @@ android:id="@+id/userNameTv" android:layout_width="match_parent" android:layout_height="wrap_content" + android:includeFontPadding="false" android:text="@{entity.name}" android:textColor="@color/text_333333" android:textSize="14sp" @@ -61,6 +65,8 @@ android:id="@+id/labelTv" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:includeFontPadding="false" android:text="@{entity.nameLabel}" android:textColor="@color/theme_font" android:textSize="12sp" diff --git a/app/src/main/res/layout/novice_task_item.xml b/app/src/main/res/layout/novice_task_item.xml index a1ba1b8fc9..902958a144 100644 --- a/app/src/main/res/layout/novice_task_item.xml +++ b/app/src/main/res/layout/novice_task_item.xml @@ -9,18 +9,16 @@ + android:orientation="vertical"> - - + app:layout_constraintTop_toBottomOf="@+id/taskName" /> \ No newline at end of file diff --git a/app/src/main/res/layout/novice_tasks_item.xml b/app/src/main/res/layout/novice_tasks_item.xml index 3b92c2b200..d329a2d096 100644 --- a/app/src/main/res/layout/novice_tasks_item.xml +++ b/app/src/main/res/layout/novice_tasks_item.xml @@ -1,9 +1,27 @@ - + android:layout_height="175dp" + android:layout_marginTop="16dp"> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/popup_server_time.xml b/app/src/main/res/layout/popup_server_time.xml index 93afd76b14..6efdc7f451 100644 --- a/app/src/main/res/layout/popup_server_time.xml +++ b/app/src/main/res/layout/popup_server_time.xml @@ -23,15 +23,6 @@ app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent"> - - + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/tab_item_download_number.xml b/app/src/main/res/layout/tab_item_download_number.xml index 957959048e..0001d83a83 100644 --- a/app/src/main/res/layout/tab_item_download_number.xml +++ b/app/src/main/res/layout/tab_item_download_number.xml @@ -8,7 +8,7 @@ android:id="@+id/tab_title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" + android:layout_marginStart="8dp" android:text="@string/download_game" android:textColor="@color/text_tabbar_style" android:textSize="14sp" /> @@ -17,7 +17,7 @@ android:id="@+id/tab_download_number" android:layout_width="6dp" android:layout_height="6dp" - android:layout_marginLeft="2dp" + android:layout_marginStart="2dp" android:layout_marginBottom="3dp" android:background="@drawable/oval_hint_red_bg" android:gravity="center" diff --git a/app/src/main/res/layout/task_bottom_item.xml b/app/src/main/res/layout/task_bottom_item.xml new file mode 100644 index 0000000000..aa9beac9b4 --- /dev/null +++ b/app/src/main/res/layout/task_bottom_item.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/task_title_item.xml b/app/src/main/res/layout/task_title_item.xml index d9658bd13a..f4418f6168 100644 --- a/app/src/main/res/layout/task_title_item.xml +++ b/app/src/main/res/layout/task_title_item.xml @@ -1,18 +1,23 @@ - + android:layout_height="wrap_content" + android:layout_marginTop="20dp" + android:layout_marginLeft="16dp" + android:layout_marginRight="16dp"> - - + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/user_history_item.xml b/app/src/main/res/layout/user_history_item.xml index 1581d13717..79d8e2cdb2 100644 --- a/app/src/main/res/layout/user_history_item.xml +++ b/app/src/main/res/layout/user_history_item.xml @@ -41,16 +41,6 @@ app:layout_constraintTop_toTopOf="parent" tools:visibility="visible" /> - - + tools:text="答题先锋答题先锋答题先锋答题先锋答题先锋答题先锋"/> - - + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index bd5f95e43a..cf04965bba 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -4,10 +4,37 @@ #2496FF + + #FFA142 + + #FF4147 + + #06CEA8 + #1383EB #991383EB + + #333333 + #666666 + #999999 + #CCCCCC + + + #F5F5F5 + + #EEEEEE + + #1A000000 + + #66000000 + @color/white @@ -16,8 +43,6 @@ @color/text_9a9a9a #B3B3B3 - - #f5f5f5 @color/bg_ededed @@ -149,7 +174,6 @@ #EBFDFF #7CE7F8 #E6F8FA - #E6F9FA #91F0FD #F6FBFF #50DCDC @@ -159,6 +183,8 @@ #74FFFF #60D5FF #EDF5FC + #F2F7FC + #EBFAF7 #b2b2b2 #9a9a9a #3a3a3a @@ -241,6 +267,7 @@ #140B6D #16161A #28282E + #8798A8 #3796FF #213964 #06CEA8 @@ -267,6 +294,9 @@ #DAF7F1 #FFE5E6 #17C2A1 + #0089D1 + #00DBA4 + #07B896 #99666666 #6621282E diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index d503f4740c..7e7f0c1ad2 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,5 +1,24 @@ + + 20sp + 18sp + 16sp + 14sp + 13sp + 12sp + 11sp + 10sp + 0dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bad7f7b25f..5b58cc8556 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -99,6 +99,7 @@ 免流量传送 游戏下载 游戏更新 + 已安装 已连接 无需操作,请让对方继续发送即可 完成 @@ -376,6 +377,8 @@ 试玩 展开 > 解压中 + 下载后前往浏览器解压安装 + 浏览器解压安装 已淘号:%1$s]]> 已领取:%1$s]]> @@ -807,7 +810,7 @@ 立即更换手机号 好友邀请码 输入好友邀请码 - 温馨提示:\n当你填写邀请码成功后,你和邀请人都能获取光能,被\n邀请人必须是新用户,否则无法成功邀请 + 温馨提示:\n当你填写邀请码成功后,你和邀请人都能获取光能,必\n须是新用户才能填写邀请码获取光能哦! 举报原因 头像、昵称、背景图、签名含有违规信息 diff --git a/build.gradle b/build.gradle index 52b5c126cc..dcde164fa0 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ apply from: 'dependencies.gradle' buildscript { - ext.kotlin_version = '1.3.72' + ext.kotlin_version = '1.4.20' repositories { google() diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index f96cf65788..aaa1d7b0e7 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -1,6 +1,6 @@ buildscript { ext { - kotlinVersion = "1.3.72" + kotlinVersion = "1.4.20" } repositories { google() @@ -20,7 +20,7 @@ dependencies { implementation "com.android.tools.build:gradle:4.1.0" implementation "commons-io:commons-io:2.4" implementation "org.javassist:javassist:3.25.0-GA" - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion" } repositories { google() diff --git a/dependencies.gradle b/dependencies.gradle index 3c5425669d..467566f2d0 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,8 +7,8 @@ ext { targetSdkVersion = 26 // application info (每个大版本之间的 versionCode 增加 20) - versionCode = 370 - versionName = "5.1.0" + versionCode = 390 + versionName = "5.2.0" applicationId = "com.gh.gamecenter" // AndroidX @@ -110,6 +110,7 @@ ext { nanohttpd = "2.3.1" aliyunLog = "2.5.14" easyFloat = "1.3.4" + shapeOfView = "1.4.7" sentry = "3.2.0" } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 90d3ef7aee..def161b6e3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -49,7 +49,7 @@ QUICK_LOGIN_APPID=300012035775 QUICK_LOGIN_APPKEY=002BAABA2C078342DA33BEAB0A4C6A25 # hosts -DEV_API_HOST=https\://dev-and-api.ghzs.com/v5d0d0/ +DEV_API_HOST=https\://dev-and-api.ghzs.com/v5d2d0/ API_HOST=https\://and-api.ghzs.com/v5d0d0/ SENSITIVE_API_HOST=https\://and-api.ghzs.com/v5d0d0/ diff --git a/scripts/build_with_chucker_open.sh b/scripts/build_with_chucker_open.sh index 93d8cc8d62..627a86469f 100755 --- a/scripts/build_with_chucker_open.sh +++ b/scripts/build_with_chucker_open.sh @@ -9,8 +9,8 @@ build_time_without_divider=$(TZ=Asia/Shanghai date +'%Y%m%d%H%M')L git checkout app/build.gradle git checkout gradle.properties -sed -i '/debugImplementation "com.github.nichbar.chucker:library:$chucker"/c\ implementation "com.github.nichbar.chucker:library:$chucker"' app/build.gradle -sed -i '/releaseImplementation "com.github.nichbar.chucker:library-no-op:$chucker"/c\' app/build.gradle +sed -i '/debugImplementation "com.github.nichbar.chucker:library:${chucker}"/c\ implementation "com.github.nichbar.chucker:library:${chucker}"' app/build.gradle +sed -i '/releaseImplementation "com.github.nichbar.chucker:library-no-op:${chucker}"/c\' app/build.gradle ./gradlew --stop ./gradlew clean