Compare commits
41 Commits
feat/GHZSC
...
pack/updat
| Author | SHA1 | Date | |
|---|---|---|---|
| 681e2cd4ee | |||
| 883dad8f06 | |||
| 0d650d2d00 | |||
| 8f8ac99dae | |||
| 0be7db94ad | |||
| ae80359b48 | |||
| 81281855a1 | |||
| a5174c6931 | |||
| a3cc74afb3 | |||
| 84e78de6fc | |||
| 9bf4c73250 | |||
| 57a222b87a | |||
| 3e125b90a2 | |||
| 1809265d4f | |||
| 3b3774596d | |||
| bded49c366 | |||
| 841711b5f1 | |||
| 7a080115a7 | |||
| 337c4724a7 | |||
| 2119691bf6 | |||
| caf50055c9 | |||
| 3ee3c2453f | |||
| 5e431e8a61 | |||
| ff72c7cac8 | |||
| 047325e9bc | |||
| afbb758740 | |||
| 5de629cfdd | |||
| f026623600 | |||
| 2f5ee0eb91 | |||
| e7651e8092 | |||
| 82d51d6375 | |||
| 6080edfd8a | |||
| d9713571c9 | |||
| b466525e8b | |||
| 2a25675dce | |||
| 5486ad8818 | |||
| 5552fcf7bc | |||
| 782a0af13c | |||
| c6c2d9cd12 | |||
| f929a08e46 | |||
| e48f96d7d7 |
@ -72,7 +72,7 @@ android_build:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-6136
|
||||
- pack/update_sentry_plugin_cache
|
||||
|
||||
# 代码检查
|
||||
sonarqube_analysis:
|
||||
@ -104,7 +104,6 @@ sonarqube_analysis:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-6136
|
||||
|
||||
## 发送简易检测结果报告
|
||||
send_sonar_report:
|
||||
@ -123,7 +122,6 @@ send_sonar_report:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-6136
|
||||
|
||||
oss-upload&send-email:
|
||||
tags:
|
||||
@ -160,4 +158,4 @@ oss-upload&send-email:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-6136
|
||||
- pack/update_sentry_plugin_cache
|
||||
|
||||
@ -101,6 +101,8 @@ android {
|
||||
buildConfigField "String", "NEW_API_HOST", "\"${NEW_API_HOST}\""
|
||||
buildConfigField "String", "LOG_HUB_PROJECT", "\"${LOG_HUB_PROJECT}\""
|
||||
buildConfigField "String", "VAPI_HOST", "\"${VAPI_HOST}\""
|
||||
buildConfigField "String", "WGAME_CPM_BUSIAPPID", "\"${WGAME_CPM_BUSIAPPID}\""
|
||||
buildConfigField "String", "WGAME_CPM_API_HOST", "\"${WGAME_CPM_API_HOST}\""
|
||||
buildConfigField "String", "WECHAT_APPID", "\"${WECHAT_APPID}\""
|
||||
buildConfigField "String", "WECHAT_SECRET", "\"${WECHAT_SECRET}\""
|
||||
buildConfigField "String", "TENCENT_APPID", "\"${TENCENT_APPID}\""
|
||||
|
||||
@ -815,14 +815,6 @@
|
||||
<!-- android:taskAffinity="${applicationId}"-->
|
||||
<!-- android:exported="true" />-->
|
||||
|
||||
<activity
|
||||
android:name=".forum.home.recommend.PublishImageArticleActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.home.recommend.ImageArticleDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}"
|
||||
|
||||
@ -588,7 +588,7 @@ document.addEventListener("selectionchange", function(e) {
|
||||
});
|
||||
|
||||
document.addEventListener("selectionchange", function(e) {
|
||||
RE.enabledEditingItems(e)
|
||||
setTimeout(() => RE.enabledEditingItems(e), 10)
|
||||
});
|
||||
|
||||
RE.recursion = function(dom) {
|
||||
|
||||
@ -374,7 +374,7 @@ object DefaultUrlHandler {
|
||||
val iconSubscript = uri.getQueryParameter("game_icon_subscript") ?: ""
|
||||
val gameEntity =
|
||||
if (forumType == BbsType.OFFICIAL_BBS.value && gameId.isNotEmpty() && gameName.isNotEmpty() && icon.isNotEmpty()) {
|
||||
GameEntity(id = gameId, mName = gameName, mIcon = icon, mIconSubscript = iconSubscript)
|
||||
GameEntity(_id = gameId, mName = gameName, mIcon = icon, mIconSubscript = iconSubscript)
|
||||
} else null
|
||||
val activityLabelEntity = if (activityId.isNotEmpty() && activityName.isNotEmpty()) {
|
||||
ActivityLabelEntity(
|
||||
|
||||
@ -63,6 +63,9 @@ public class Config {
|
||||
public static final String NEW_API_HOST = EnvHelper.getNewHost();
|
||||
public static final String VAPI_HOST = EnvHelper.getVHost();
|
||||
|
||||
public static final String WGAME_CPM_BUSIAPPID = BuildConfig.WGAME_CPM_BUSIAPPID;
|
||||
public static final String WGAME_CPM_API_HOST = EnvHelper.getWGameCPMHost();
|
||||
|
||||
// Third-Party confs
|
||||
public static final String WECHAT_APPID = BuildConfig.WECHAT_APPID;
|
||||
public static final String WECHAT_SECRET = BuildConfig.WECHAT_SECRET;
|
||||
|
||||
@ -6,6 +6,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.LayoutManager
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import io.reactivex.functions.Consumer
|
||||
|
||||
@ -16,8 +17,9 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
|
||||
|
||||
val throttleBus: ExposureThrottleBus by lazy {
|
||||
ExposureThrottleBus(
|
||||
Consumer { commitExposure(it) },
|
||||
Consumer(Throwable::printStackTrace)
|
||||
{ commitExposure(it) },
|
||||
Consumer(Throwable::printStackTrace),
|
||||
{ commitWXCPMExposure(it) }
|
||||
)
|
||||
}
|
||||
var layoutManager: LayoutManager? = null
|
||||
@ -93,4 +95,32 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
|
||||
ExposureManager.log(eventList)
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信小游戏CPM曝光事件接口上报,由于普通曝光事件的上报通道存在节流特性,不符合CPM接口对于数据上报的实时性和准确性的要求,所以使用额外的通道进行上报
|
||||
*/
|
||||
private fun commitWXCPMExposure(visibleState: ExposureThrottleBus.VisibleState) {
|
||||
|
||||
val eventList = arrayListOf<ExposureEvent>()
|
||||
|
||||
for (pos in visibleState.firstVisiblePosition..visibleState.lastVisiblePosition) {
|
||||
try {
|
||||
exposable.getEventByPosition(pos)?.let {
|
||||
if (it.payload.miniGameType == Constants.WECHAT_MINI_GAME_CPM) {
|
||||
eventList.add(it)
|
||||
}
|
||||
}
|
||||
exposable.getEventListByPosition(pos)?.let { list ->
|
||||
list.forEach {
|
||||
if (it.payload.miniGameType == Constants.WECHAT_MINI_GAME_CPM) {
|
||||
eventList.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ignore: Exception) {
|
||||
// Just ignore the error.
|
||||
}
|
||||
}
|
||||
ExposureManager.logCPM(eventList)
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,12 +1,13 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.common.loghub.LoghubUtils
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.loghub.TLogHubHelper
|
||||
import com.gh.gamecenter.common.utils.FixedSizeLinkedHashSet
|
||||
import com.gh.gamecenter.common.utils.toJson
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.feature.minigame.wechat.WGameSubjectCPMListReportHelper
|
||||
import com.lightgame.utils.Utils
|
||||
import com.volcengine.model.tls.LogItem
|
||||
|
||||
@ -33,6 +34,9 @@ object ExposureManager {
|
||||
*/
|
||||
fun log(event: ExposureEvent) {
|
||||
AppExecutor.logExecutor.execute {
|
||||
if (event.payload.miniGameType == Constants.WECHAT_MINI_GAME_CPM) {
|
||||
WGameSubjectCPMListReportHelper.reportExposure(event)
|
||||
}
|
||||
if (!exposureCache.contains(event.id)) {
|
||||
exposureSet.add(event)
|
||||
exposureCache.add(event.id)
|
||||
@ -59,6 +63,17 @@ object ExposureManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a wechat mini game cpm collection of exposure event.
|
||||
*/
|
||||
fun logCPM(eventList: List<ExposureEvent>) {
|
||||
AppExecutor.logExecutor.execute {
|
||||
if (eventList.isNotEmpty()) {
|
||||
WGameSubjectCPMListReportHelper.reportExposure(eventList.toSet())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param forcedUpload Ignore all restrictions.
|
||||
*/
|
||||
@ -79,12 +94,7 @@ object ExposureManager {
|
||||
|
||||
private fun uploadExposures(eventSet: HashSet<ExposureEvent>, forced: Boolean) {
|
||||
eventSet.forEach {
|
||||
val jsonExposure = it.jsonExposure
|
||||
if (jsonExposure == null) {
|
||||
TLogHubHelper.sendLog(buildLog(it), LOG_STORE)
|
||||
} else {
|
||||
LoghubUtils.log(jsonExposure, it.logStore, true)
|
||||
}
|
||||
TLogHubHelper.sendLog(buildLog(it), LOG_STORE)
|
||||
// LoghubHelper.uploadLog(buildLog(it), LOG_STORE, forced)
|
||||
// it.recycle()
|
||||
}
|
||||
|
||||
@ -3,16 +3,20 @@ package com.gh.common.exposure
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.functions.Consumer
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import io.reactivex.subjects.BehaviorSubject
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ExposureThrottleBus(var onSuccess: Consumer<VisibleState>, var onError: Consumer<Throwable>) {
|
||||
class ExposureThrottleBus(
|
||||
var onSuccess: Consumer<VisibleState>,
|
||||
var onError: Consumer<Throwable>,
|
||||
onPreSuccess: Consumer<VisibleState>
|
||||
) {
|
||||
|
||||
companion object {
|
||||
private const val THRESHOLD_TIME = 300L
|
||||
}
|
||||
|
||||
private val mPublishSubject: PublishSubject<VisibleState> = PublishSubject.create()
|
||||
private val mPublishSubject: BehaviorSubject<VisibleState> = BehaviorSubject.create()
|
||||
private val mCompositeDisposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
init {
|
||||
@ -24,6 +28,7 @@ class ExposureThrottleBus(var onSuccess: Consumer<VisibleState>, var onError: Co
|
||||
*/
|
||||
val disposable = mPublishSubject
|
||||
.distinctUntilChanged()
|
||||
.doOnNext(onPreSuccess)
|
||||
.throttleWithTimeout(THRESHOLD_TIME, TimeUnit.MILLISECONDS)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(onSuccess, onError)
|
||||
|
||||
@ -33,5 +33,9 @@ class BuildConfigImpl : IBuildConfigProvider {
|
||||
|
||||
override fun getVDevApiHost(): String = BuildConfig.DEV_VAPI_HOST
|
||||
|
||||
override fun getWGameCPMApiHost(): String = BuildConfig.WGAME_CPM_API_HOST
|
||||
|
||||
override fun getWGameCPMBusiAppId(): String = BuildConfig.WGAME_CPM_BUSIAPPID
|
||||
|
||||
override fun getLogProducerProject(): String = BuildConfig.LOG_HUB_PROJECT
|
||||
}
|
||||
@ -62,7 +62,13 @@ class DirectProviderImpl : IDirectProvider {
|
||||
DirectUtils.directToCommunityArticle(context, articleId, communityId, entrance, path, sourceEntrance)
|
||||
}
|
||||
|
||||
override fun directToVideoDetail(context: Context, videoId: String, entrance: String?, path: String?, sourceEntrance: String) {
|
||||
override fun directToVideoDetail(
|
||||
context: Context,
|
||||
videoId: String,
|
||||
entrance: String?,
|
||||
path: String?,
|
||||
sourceEntrance: String
|
||||
) {
|
||||
DirectUtils.directToVideoDetail(context, videoId, entrance, path, sourceEntrance)
|
||||
}
|
||||
|
||||
@ -78,8 +84,13 @@ class DirectProviderImpl : IDirectProvider {
|
||||
DirectUtils.directToQQGameById(activity, qqAppId)
|
||||
}
|
||||
|
||||
override fun directToWechatGameById(activity: Activity, qqAppId: String) {
|
||||
DirectUtils.directToWechatGameById(activity, qqAppId)
|
||||
override fun directToWechatGameById(
|
||||
activity: Activity,
|
||||
wechatAppId: String,
|
||||
wechatAppPath: String,
|
||||
wechatAppExtData: String
|
||||
) {
|
||||
DirectUtils.directToWechatGameById(activity, wechatAppId, wechatAppPath, wechatAppExtData)
|
||||
}
|
||||
|
||||
override fun directToExternalBrowser(context: Context, url: String) {
|
||||
|
||||
@ -77,19 +77,6 @@ class NewCommentDetailProviderImpl : INewCommentDetailProvider {
|
||||
)
|
||||
}
|
||||
|
||||
override fun getImageArticleCommentIntent(
|
||||
context: Context,
|
||||
commentId: String,
|
||||
imageArticleId: String,
|
||||
topCommentId: String,
|
||||
entrance: String,
|
||||
path: String
|
||||
):Intent {
|
||||
return NewCommentDetailActivity.getImageArticleCommentIntent(
|
||||
context, commentId, imageArticleId, topCommentId, entrance, path
|
||||
)
|
||||
}
|
||||
|
||||
override fun init(context: Context?) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@ -14,7 +14,6 @@ import com.gh.gamecenter.adapter.ReportReasonAdapter
|
||||
import com.gh.gamecenter.common.constant.CommonConsts
|
||||
import com.gh.gamecenter.common.json.json
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.toObject
|
||||
import com.gh.gamecenter.common.utils.toRequestBody
|
||||
@ -25,17 +24,15 @@ import com.gh.gamecenter.databinding.DialogReportReasonBinding
|
||||
import com.gh.gamecenter.feature.entity.SettingsEntity
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONObject
|
||||
import retrofit2.HttpException
|
||||
|
||||
object BbsReportHelper {
|
||||
|
||||
fun showReportDialog(report: CommunityReporter) {
|
||||
fun showReportDialog(contentId: String) {
|
||||
val sp = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance())
|
||||
val suggestion: SettingsEntity.Suggestion? =
|
||||
sp.getString(CommonConsts.SUGGESTION_HINT_TYPE, null)?.toObject()
|
||||
@ -55,7 +52,7 @@ object BbsReportHelper {
|
||||
binding.normalReasonContainer.visibility = View.GONE
|
||||
binding.otherReasonContainer.visibility = View.VISIBLE
|
||||
} else {
|
||||
report.postReport(json {
|
||||
postReport(contentId, json {
|
||||
"reason" to reason
|
||||
})
|
||||
dialog.cancel()
|
||||
@ -85,7 +82,7 @@ object BbsReportHelper {
|
||||
) {
|
||||
ToastUtils.showToast("请填写举报原因")
|
||||
} else {
|
||||
report.postReport(json {
|
||||
postReport(contentId, json {
|
||||
"reason" to "其它"
|
||||
"description" to binding.otherReasonEt.text.toString()
|
||||
})
|
||||
@ -108,45 +105,28 @@ object BbsReportHelper {
|
||||
}
|
||||
}
|
||||
|
||||
interface CommunityReporter {
|
||||
@SuppressLint("CheckResult")
|
||||
private fun postReport(contentId: String, reportContent: JSONObject) {
|
||||
RetrofitManager.getInstance()
|
||||
.api
|
||||
.postBbsReport(contentId, reportContent.toRequestBody())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
ToastUtils.toast("举报成功")
|
||||
}
|
||||
|
||||
fun createReportSingle(content: JSONObject): Single<ResponseBody>
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun postReport(content: JSONObject) {
|
||||
createReportSingle(content)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
super.onFailure(exception)
|
||||
if (exception is HttpException) {
|
||||
ErrorHelper.handleError(
|
||||
HaloApp.getInstance().application,
|
||||
exception.response().errorBody()?.string()
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class PostsReporter(private val contentId: String) : CommunityReporter {
|
||||
|
||||
override fun createReportSingle(content: JSONObject): Single<ResponseBody> =
|
||||
RetrofitManager.getInstance()
|
||||
.api
|
||||
.postBbsReport(contentId, content.toRequestBody())
|
||||
}
|
||||
|
||||
class ImageArticleReporter(private val contentId: String) : CommunityReporter {
|
||||
|
||||
override fun createReportSingle(content: JSONObject): Single<ResponseBody> =
|
||||
RetrofitManager.getInstance().api
|
||||
.postImageArticleReport(contentId, content.toRequestBody())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@ -119,23 +119,6 @@ object CommentHelper {
|
||||
)
|
||||
}
|
||||
|
||||
fun showImageArticleCommentOptions(
|
||||
view: View,
|
||||
commentEntity: CommentEntity,
|
||||
imageArticleId: String,
|
||||
isShowTop: Boolean = false,
|
||||
listener: OnCommentOptionClickListener?
|
||||
) {
|
||||
showCommentOptions(
|
||||
view,
|
||||
commentEntity,
|
||||
imageArticleId = imageArticleId,
|
||||
showConversation = false,
|
||||
isShowTopOrAccept = isShowTop,
|
||||
listener = listener
|
||||
)
|
||||
}
|
||||
|
||||
private fun showCommentOptions(
|
||||
view: View,
|
||||
commentEntity: CommentEntity,
|
||||
@ -146,7 +129,6 @@ object CommentHelper {
|
||||
questionId: String? = null,
|
||||
videoId: String? = null,
|
||||
gameCollectionId: String? = null,
|
||||
imageArticleId: String? = null,
|
||||
isShowTopOrAccept: Boolean = false,
|
||||
ignoreModerator: Boolean = false,
|
||||
isVideoAuthor: Boolean = false,
|
||||
@ -155,7 +137,8 @@ object CommentHelper {
|
||||
val context = view.context
|
||||
val dialogOptions = ArrayList<String>()
|
||||
val isContentAuthor = commentEntity.me?.isContentAuthor == true
|
||||
if (isShowTopOrAccept && (articleId != null || questionId != null || videoId != null || imageArticleId != null) && isContentAuthor) {
|
||||
|
||||
if (isShowTopOrAccept && (articleId != null || questionId != null || videoId != null) && isContentAuthor) {
|
||||
dialogOptions.add(if (commentEntity.isTop) "取消置顶" else "置顶")
|
||||
}
|
||||
if (isShowTopOrAccept && questionId != null && isContentAuthor) {
|
||||
@ -246,7 +229,6 @@ object CommentHelper {
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
|
||||
articleId != null -> {
|
||||
PostCommentUtils.reportCommunityArticleComment(
|
||||
commentEntity.id,
|
||||
@ -254,7 +236,6 @@ object CommentHelper {
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
|
||||
questionId != null -> {
|
||||
PostCommentUtils.reportQuestionComment(
|
||||
questionId,
|
||||
@ -263,7 +244,6 @@ object CommentHelper {
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
|
||||
gameCollectionId != null -> {
|
||||
PostCommentUtils.reportGameCollectionComment(
|
||||
gameCollectionId,
|
||||
@ -272,15 +252,6 @@ object CommentHelper {
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
|
||||
imageArticleId != null -> {
|
||||
PostCommentUtils.reportImageArticleComment(
|
||||
commentEntity.id,
|
||||
reportType,
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
PostCommentUtils.reportVideoComment(
|
||||
videoId,
|
||||
@ -316,17 +287,6 @@ object CommentHelper {
|
||||
null
|
||||
)
|
||||
)
|
||||
} else if (imageArticleId != null) {
|
||||
context.startActivity(
|
||||
CommentDetailActivity
|
||||
.getImageArticleCommentIntent(
|
||||
context,
|
||||
imageArticleId,
|
||||
commentEntity.id,
|
||||
communityId,
|
||||
null
|
||||
)
|
||||
)
|
||||
} else {
|
||||
context.startActivity(
|
||||
CommentDetailActivity
|
||||
|
||||
@ -305,7 +305,6 @@ public class CommentUtils {
|
||||
String articleCommunityId,
|
||||
String videoId,
|
||||
String questionId,
|
||||
String imageArticleId,
|
||||
final CommentEntity commentEntity,
|
||||
final TextView commentLikeCountTv,
|
||||
final ImageView commentLikeIv,
|
||||
@ -329,7 +328,7 @@ public class CommentUtils {
|
||||
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
|
||||
commentLikeCountTv.setVisibility(View.VISIBLE);
|
||||
|
||||
PostCommentUtils.likeComment(answerId, articleId, videoId, questionId, imageArticleId, commentEntity.getId(),
|
||||
PostCommentUtils.likeComment(answerId, articleId, videoId, questionId, commentEntity.getId(),
|
||||
new PostCommentUtils.PostCommentListener() {
|
||||
@Override
|
||||
public void postSuccess(JSONObject response) {
|
||||
@ -375,7 +374,6 @@ public class CommentUtils {
|
||||
String articleId,
|
||||
String articleCommunityId,
|
||||
String videoId,
|
||||
String imageArticleId,
|
||||
final CommentEntity commentEntity,
|
||||
final TextView commentLikeCountTv,
|
||||
final ImageView commentLikeIv,
|
||||
@ -384,7 +382,7 @@ public class CommentUtils {
|
||||
String entrance = "视频流-评论-点赞";
|
||||
CheckLoginUtils.checkLogin(context, entrance, () -> {
|
||||
|
||||
PostCommentUtils.likeComment(answerId, articleId, videoId, "", imageArticleId, commentEntity.getId(),
|
||||
PostCommentUtils.likeComment(answerId, articleId, videoId, "", commentEntity.getId(),
|
||||
new PostCommentUtils.PostCommentListener() {
|
||||
@Override
|
||||
public void postSuccess(JSONObject response) {
|
||||
|
||||
@ -485,11 +485,13 @@ object DirectUtils {
|
||||
ColumnCollectionDetailFragment.TYPE_QQ_MINI_GAME_COLUMN -> directToQGameHome(context)
|
||||
|
||||
// QQ游戏专题详情页
|
||||
ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN, ViewPagerFragmentHelper.TYPE_WECHAT_GAME_COLUMN -> {
|
||||
val subjectType = if (linkEntity.type == ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN) {
|
||||
SubjectData.SubjectType.QQ_GAME
|
||||
} else {
|
||||
SubjectData.SubjectType.WECHAT_GAME
|
||||
ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN,
|
||||
ViewPagerFragmentHelper.TYPE_WECHAT_GAME_COLUMN,
|
||||
ViewPagerFragmentHelper.TYPE_WECHAT_GAME_CPM_COLUMN -> {
|
||||
val subjectType = when (linkEntity.type) {
|
||||
ViewPagerFragmentHelper.TYPE_QQ_MINI_GAME_COLUMN -> SubjectData.SubjectType.QQ_GAME
|
||||
ViewPagerFragmentHelper.TYPE_WECHAT_GAME_CPM_COLUMN -> SubjectData.SubjectType.WECHAT_GAME_CPM
|
||||
else -> SubjectData.SubjectType.WECHAT_GAME
|
||||
}
|
||||
directToSubject(
|
||||
context = context,
|
||||
@ -568,16 +570,6 @@ object DirectUtils {
|
||||
}
|
||||
}
|
||||
|
||||
"image_article" -> {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(KEY_IMAGE_ARTICLE_ID, linkEntity.link)
|
||||
.appendQueryParameter(KEY_SOURCE_ENTRANCE, sourceEntrance)
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
}
|
||||
|
||||
|
||||
"" -> {
|
||||
// do nothing
|
||||
}
|
||||
@ -2019,6 +2011,8 @@ object DirectUtils {
|
||||
fun directToWechatGameById(
|
||||
activity: Activity,
|
||||
wechatAppId: String,
|
||||
wechatAppPath: String = "",
|
||||
wechatAppExtData: String = ""
|
||||
) {
|
||||
|
||||
val wxApiProxy = WXAPIFactory.createWXAPI(
|
||||
@ -2033,8 +2027,9 @@ object DirectUtils {
|
||||
wxApiProxy.sendReq(
|
||||
WXLaunchMiniProgram.Req().apply {
|
||||
userName = wechatAppId
|
||||
path = Constants.WECHAT_MINI_GAME_PCS
|
||||
miniprogramType = WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE;
|
||||
path = wechatAppPath.ifEmpty { Constants.WECHAT_MINI_GAME_PCS }
|
||||
extData = wechatAppExtData
|
||||
miniprogramType = WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@ -880,7 +880,7 @@ object DownloadItemUtils {
|
||||
}
|
||||
if (gameEntity.isMiniGame()) {
|
||||
downloadBtn.setOnClickListener {
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity)
|
||||
clickCallback?.onCallback()
|
||||
allStateClickCallback?.onCallback()
|
||||
}
|
||||
|
||||
@ -494,7 +494,7 @@ object DownloadObserver {
|
||||
java.lang.Boolean.parseBoolean(downloadEntity.getMetaExtra(Constants.IS_PLATFORM_RECOMMEND))
|
||||
val exposureEvent = ExposureUtils.logADownloadCompleteExposureEvent(
|
||||
GameEntity(
|
||||
id = downloadEntity.gameId,
|
||||
_id = downloadEntity.gameId,
|
||||
mName = downloadEntity.name.removeSuffix(Constants.GAME_NAME_DECORATOR),
|
||||
gameVersion = downloadEntity.versionName ?: "",
|
||||
isPlatformRecommend = isPlatformRecommend,
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
package com.gh.common.util;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
@ -19,10 +16,8 @@ import org.greenrobot.eventbus.EventBus;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* 下载完成跳安装,
|
||||
*/
|
||||
@ -49,15 +44,15 @@ public class InstallUtils {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (msg.what == INSTALL_WHAT && packageManager != null) {
|
||||
List<String> packageNameList = PackageHelper.INSTANCE.getInstalledPackageNameList(context, 0);
|
||||
ArrayList<String> list = new ArrayList<>(packageNameList);
|
||||
if (installMap != null && installMap.size() != 0) {
|
||||
ArrayList<String> keys = new ArrayList<>();
|
||||
for (String packageName : installMap.keySet()) {
|
||||
if (TextUtils.isEmpty(packageName)) continue;
|
||||
|
||||
long time = installMap.get(packageName);
|
||||
if (System.currentTimeMillis() - time >= MAX_TIME) {
|
||||
keys.add(packageName);
|
||||
} else if (list.contains(packageName)) {
|
||||
} else if (PackageUtils.isInstalled(context, packageName)) {
|
||||
keys.add(packageName);
|
||||
|
||||
DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntityByPackageName(packageName);
|
||||
@ -80,7 +75,7 @@ public class InstallUtils {
|
||||
long time = uninstallMap.get(packageName);
|
||||
if (System.currentTimeMillis() - time >= MAX_TIME) {
|
||||
keys.add(packageName);
|
||||
} else if (!list.contains(packageName)) {
|
||||
} else if (!PackageUtils.isInstalled(context, packageName)) {
|
||||
keys.add(packageName);
|
||||
EventBus.getDefault().post(new EBPackage("卸载", packageName, "", false));
|
||||
}
|
||||
@ -105,6 +100,8 @@ public class InstallUtils {
|
||||
}
|
||||
|
||||
public void addInstall(String packageName) {
|
||||
if (TextUtils.isEmpty(packageName)) return;
|
||||
|
||||
if (installMap == null) {
|
||||
installMap = Collections.synchronizedMap(new HashMap<String, Long>());
|
||||
}
|
||||
|
||||
@ -33,8 +33,6 @@ object NewFlatLogUtils {
|
||||
private const val EVENT_INSTALLED_LAUNCH_DIALOG_SHOW = "halo_fun_installed_launch_dialog_show"
|
||||
private const val EVENT_INSTALLED_LAUNCH_DIALOG_CLICK = "halo_fun_installed_launch_dialog_click"
|
||||
|
||||
private const val LOG_STORE_BBS_COMMUNITY = "bbs_community"
|
||||
|
||||
private fun log(jsonObject: JSONObject, logStore: String = "event", uploadImmediately: Boolean = false) {
|
||||
Utils.log("NewFlatLogUtils", jsonObject.toString(4))
|
||||
LoghubUtils.log(jsonObject, logStore, uploadImmediately, true)
|
||||
@ -98,12 +96,7 @@ object NewFlatLogUtils {
|
||||
|
||||
// 畅玩助手更新弹窗展示事件
|
||||
@JvmStatic
|
||||
fun logHaloFunUpdateDialogShow(
|
||||
gameId: String,
|
||||
gameName: String,
|
||||
gameArchitecture: String,
|
||||
targetVaVersion: String
|
||||
) {
|
||||
fun logHaloFunUpdateDialogShow(gameId: String, gameName: String, gameArchitecture: String, targetVaVersion: String) {
|
||||
val json = json {
|
||||
KEY_EVENT to "halo_fun_update_dialog_show"
|
||||
"game_id" to gameId
|
||||
@ -153,12 +146,7 @@ object NewFlatLogUtils {
|
||||
|
||||
// 畅玩助手更新弹窗点击事件
|
||||
@JvmStatic
|
||||
fun logHaloFunUpdateDialogClick(
|
||||
dialogType: String,
|
||||
buttonType: String,
|
||||
architecture: String,
|
||||
targetVaVersion: String
|
||||
) {
|
||||
fun logHaloFunUpdateDialogClick(dialogType: String, buttonType: String, architecture: String, targetVaVersion: String) {
|
||||
val json = json {
|
||||
KEY_EVENT to "halo_fun_update_dialog_click"
|
||||
"dialog_type" to dialogType
|
||||
@ -752,7 +740,7 @@ object NewFlatLogUtils {
|
||||
"search_key" to searchKey
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
log(json)
|
||||
}
|
||||
|
||||
//社区搜索结果浏览
|
||||
@ -764,7 +752,7 @@ object NewFlatLogUtils {
|
||||
"search_key" to searchKey
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
log(json)
|
||||
}
|
||||
|
||||
//社区搜索tab结果切换事件
|
||||
@ -776,7 +764,7 @@ object NewFlatLogUtils {
|
||||
"tab_type" to tab
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
log(json)
|
||||
}
|
||||
|
||||
//点击论坛-搜索页返回按钮
|
||||
@ -788,7 +776,7 @@ object NewFlatLogUtils {
|
||||
"bbs_id" to bbsId
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
log(json)
|
||||
}
|
||||
|
||||
//论坛搜索结果浏览
|
||||
@ -801,7 +789,7 @@ object NewFlatLogUtils {
|
||||
"bbs_id" to bbsId
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
log(json)
|
||||
}
|
||||
|
||||
//新版我的光环触发登录
|
||||
@ -881,7 +869,7 @@ object NewFlatLogUtils {
|
||||
"bbs_id" to bbsId
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
log(json)
|
||||
}
|
||||
|
||||
//个人主页-内容
|
||||
@ -894,7 +882,7 @@ object NewFlatLogUtils {
|
||||
"tab_name" to tabName
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
log(json)
|
||||
}
|
||||
|
||||
//游戏详情页-视频合集内容
|
||||
@ -906,7 +894,7 @@ object NewFlatLogUtils {
|
||||
"ref_user_id" to refUserId
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
log(json)
|
||||
}
|
||||
|
||||
//进入游戏详情
|
||||
|
||||
@ -31,10 +31,9 @@ object NewLogUtils {
|
||||
private const val KEY_CONTENT_TYPE = "content_type"
|
||||
private const val KEY_CONTENT_ID = "content_id"
|
||||
private const val KEY_USER_ID = "ref_user_id"
|
||||
private const val KEY_BUTTON = "button"
|
||||
|
||||
private const val LOG_STORE_EVENT = "event"
|
||||
const val LOG_STORE_BBS = "bbs_community"
|
||||
private const val LOG_STORE_BBS = "bbs_community"
|
||||
|
||||
private fun log(jsonObject: JSONObject, logStore: String, uploadImmediately: Boolean = false) {
|
||||
Utils.log("NewLogUtils", jsonObject.toString(4))
|
||||
@ -2105,13 +2104,7 @@ object NewLogUtils {
|
||||
|
||||
//点击底部导航栏
|
||||
@JvmStatic
|
||||
fun logBottomNavigationClick(
|
||||
navigationName: String,
|
||||
linkType: String,
|
||||
linkText: String,
|
||||
linkId: String = "",
|
||||
sequence: Int
|
||||
) {
|
||||
fun logBottomNavigationClick(navigationName: String, linkType: String, linkText: String, linkId: String = "", sequence: Int) {
|
||||
val json = json {
|
||||
KEY_EVENT to "bottom_navigation_click"
|
||||
"navigation_name" to navigationName
|
||||
@ -2645,183 +2638,4 @@ object NewLogUtils {
|
||||
}
|
||||
log(json, LOG_STORE_EVENT)
|
||||
}
|
||||
|
||||
/**
|
||||
* 社区推荐信息流曝光埋点
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getCommunityExposureJsonObject(
|
||||
contentId: String,
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
sequence: Int,
|
||||
location: String
|
||||
): JSONObject {
|
||||
return json {
|
||||
KEY_EVENT to "community_exposure"
|
||||
KEY_CONTENT_ID to contentId
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
"sequence" to sequence
|
||||
KEY_LOCATION to location
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:180
|
||||
* 事件ID:view_note_detail
|
||||
* 事件名称:进入图文帖详情页
|
||||
* 触发时机:点击图文帖类型的内容时触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logViewNoteDetail(
|
||||
contentId: String,
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
userId: String
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "view_note_detail"
|
||||
KEY_CONTENT_ID to contentId
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
KEY_USER_ID to userId
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:181
|
||||
* 事件ID:click_note_detail_more
|
||||
* 事件名称:点击更多按钮
|
||||
* 触发时机:点击时触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logClickNoteDetailMore() {
|
||||
val json = json {
|
||||
KEY_EVENT to "click_note_detail_more"
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:182
|
||||
* 事件ID:click_note_detail_profile_photo
|
||||
* 事件名称:点击头像
|
||||
* 触发时机:点击时触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logClickNoteDetailProfilePhoto(
|
||||
contentId: String,
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
userId: String
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "click_note_detail_profile_photo"
|
||||
KEY_CONTENT_ID to contentId
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
KEY_USER_ID to userId
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:183
|
||||
* 事件ID:click_note_detail_nickname
|
||||
* 事件名称:点击昵称
|
||||
* 触发时机:点击时触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logClickNoteDetailNickname(
|
||||
contentId: String,
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
userId: String
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "click_note_detail_nickname"
|
||||
KEY_CONTENT_ID to contentId
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
KEY_USER_ID to userId
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:184
|
||||
* 事件ID:click_note_detail_follow
|
||||
* 事件名称:点击关注按钮
|
||||
* 触发时机:点击时触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logClickNoteDetailFollow(
|
||||
contentId: String,
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
userId: String,
|
||||
follow: Boolean
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "click_note_detail_follow"
|
||||
KEY_CONTENT_ID to contentId
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
KEY_USER_ID to userId
|
||||
KEY_BUTTON to if(follow) "关注" else "取消关注"
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:185
|
||||
* 事件ID:jump_note_detail
|
||||
* 事件名称:跳出帖子详情页
|
||||
* 触发时机:跳出当前页后触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logJumpNoteDetail(
|
||||
contentId: String,
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
stayTime: Long
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "jump_note_detail"
|
||||
KEY_CONTENT_ID to contentId
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
"stay_time" to stayTime
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:186
|
||||
* 事件ID:click_note_detail_forum
|
||||
* 事件名称:点击论坛
|
||||
* 触发时机:点击时触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logClickNoteDetailForum(
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "click_note_detail_forum"
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
}
|
||||
@ -814,7 +814,7 @@ object PackageHelper {
|
||||
uploadUIDGapLog = false
|
||||
|
||||
val uidGap = (android.os.Process.LAST_APPLICATION_UID - lastValidUid) / 100 * 100
|
||||
SentryHelper.onEvent("UID_GAP", "gap", uidGap.toString())
|
||||
// SentryHelper.onEvent("UID_GAP", "gap", uidGap.toString())
|
||||
}
|
||||
|
||||
return packageList
|
||||
|
||||
@ -225,17 +225,6 @@ public class PackageUtils {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
if (e instanceof AndroidException) {
|
||||
// 有些设备会出现 DeadSystemException
|
||||
SentryHelper.INSTANCE.onEvent(
|
||||
"GET_META_DATA_ERROR",
|
||||
"packageName",
|
||||
packageName,
|
||||
"exception_digest",
|
||||
e.getLocalizedMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -497,7 +486,6 @@ public class PackageUtils {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
SentryHelper.INSTANCE.onEvent("GET_PACKAGE_INFO_ERROR", "path", path);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -640,17 +628,6 @@ public class PackageUtils {
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionName;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
if (e instanceof AndroidException) {
|
||||
// 有些设备会出现 DeadSystemException
|
||||
SentryHelper.INSTANCE.onEvent(
|
||||
"GET_VERSION_NAME_ERROR",
|
||||
"packageName",
|
||||
packageName,
|
||||
"exception_digest",
|
||||
e.getLocalizedMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -664,16 +641,6 @@ public class PackageUtils {
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT).versionCode;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (e instanceof AndroidException) {
|
||||
// 有些设备会出现 DeadSystemException
|
||||
SentryHelper.INSTANCE.onEvent(
|
||||
"GET_VERSION_CODE_ERROR",
|
||||
"packageName",
|
||||
packageName,
|
||||
"exception_digest",
|
||||
e.getLocalizedMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -688,16 +655,6 @@ public class PackageUtils {
|
||||
return packageManager.getApplicationIcon(packageName);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (e instanceof AndroidException) {
|
||||
// 有些设备会出现 DeadSystemException
|
||||
SentryHelper.INSTANCE.onEvent(
|
||||
"GET_ICON_ERROR",
|
||||
"packageName",
|
||||
packageName,
|
||||
"exception_digest",
|
||||
e.getLocalizedMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -731,17 +688,6 @@ public class PackageUtils {
|
||||
return jsonObject;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (e instanceof AndroidException) {
|
||||
// 有些设备会出现 DeadSystemException
|
||||
SentryHelper.INSTANCE.onEvent(
|
||||
"GET_APP_BASIC_INFO_BY_PACKAGE_NAME",
|
||||
"packageName",
|
||||
packageName,
|
||||
"exception_digest",
|
||||
e.getLocalizedMessage()
|
||||
);
|
||||
}
|
||||
|
||||
return jsonObject;
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +77,6 @@ public class PostCommentUtils {
|
||||
String articleId,
|
||||
String videoId,
|
||||
String questionId,
|
||||
final String imageArticleId,
|
||||
final String commentId,
|
||||
final PostCommentListener listener) {
|
||||
|
||||
@ -89,8 +88,6 @@ public class PostCommentUtils {
|
||||
observable = RetrofitManager.getInstance().getApi().postVoteCommunityArticleComment(commentId);
|
||||
} else if (!TextUtils.isEmpty(questionId)) {
|
||||
observable = RetrofitManager.getInstance().getApi().postVoteQuestionComment(questionId, commentId);
|
||||
} else if (!TextUtils.isEmpty(imageArticleId)) {
|
||||
observable = RetrofitManager.getInstance().getApi().postVoteToImageArticle(commentId);
|
||||
} else {
|
||||
observable = RetrofitManager.getInstance().getApi().postVoteToVideo(videoId, commentId);
|
||||
}
|
||||
@ -119,7 +116,6 @@ public class PostCommentUtils {
|
||||
String articleCommunityId,
|
||||
String videoId,
|
||||
String questionId,
|
||||
String imageArticleId,
|
||||
final String commentId,
|
||||
final PostCommentListener listener) {
|
||||
Observable<ResponseBody> observable;
|
||||
@ -128,8 +124,6 @@ public class PostCommentUtils {
|
||||
observable = RetrofitManager.getInstance().getApi().postUnVoteQuestionComment(questionId, commentId);
|
||||
} else if (!TextUtils.isEmpty(articleId)) {
|
||||
observable = RetrofitManager.getInstance().getApi().postUnVoteArticleComment(commentId);
|
||||
} else if (!TextUtils.isEmpty(imageArticleId)) {
|
||||
observable = RetrofitManager.getInstance().getApi().postUnVoteImageArticle(commentId);
|
||||
} else {
|
||||
observable = RetrofitManager.getInstance().getApi().postUnVoteVideoComment(videoId, commentId);
|
||||
}
|
||||
@ -306,25 +300,6 @@ public class PostCommentUtils {
|
||||
});
|
||||
}
|
||||
|
||||
public static void reportImageArticleComment(String commentId, String reportData, PostCommentListener listener) {
|
||||
RequestBody body = RequestBody.create(MediaType.parse("application/json"), reportData);
|
||||
RetrofitManager.getInstance().getApi()
|
||||
.reportImageArticleComment(commentId, body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Response<ResponseBody>() {
|
||||
@Override
|
||||
public void onResponse(ResponseBody response) {
|
||||
listener.postSuccess(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(HttpException e) {
|
||||
listener.postFailed(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface PostCommentListener {
|
||||
void postSuccess(JSONObject response);
|
||||
|
||||
|
||||
@ -27,7 +27,9 @@ import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
@ -176,7 +178,7 @@ object UsageStatsHelper {
|
||||
return
|
||||
}
|
||||
|
||||
val body = RequestBody.create(MediaType.parse("application/json"), postBody.toString())
|
||||
val body = postBody.toString().toRequestBody("application/json".toMediaTypeOrNull())
|
||||
mApi.postUsageStatus(body, UserManager.getInstance().userId)
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
|
||||
@ -65,6 +65,7 @@ object ViewPagerFragmentHelper {
|
||||
const val TYPE_COLUMN = "column" // 游戏专题详情页
|
||||
const val TYPE_QQ_MINI_GAME_COLUMN = "qq_mini_game_column_detail" // QQ小游戏专题详情页
|
||||
const val TYPE_WECHAT_GAME_COLUMN = "wechat_game_column_detail" // 微信小游戏专题详情页
|
||||
const val TYPE_WECHAT_GAME_CPM_COLUMN = "wechat_game_cpm_column_detail" // 微信小游戏CPM专题详情页
|
||||
const val TYPE_COLUMN_COLLECTION = "column_collection" // 专题合集详情页
|
||||
const val TYPE_SERVER = "server" // 开服表
|
||||
const val TYPE_COLUMN_TEST = "column_test_v2" // 新游开测
|
||||
@ -163,10 +164,11 @@ object ViewPagerFragmentHelper {
|
||||
className = GameCollectionSquareFragment::class.java.name
|
||||
}
|
||||
// 游戏专题详情页/QQ游戏专题详情页
|
||||
TYPE_COLUMN, TYPE_QQ_MINI_GAME_COLUMN, TYPE_WECHAT_GAME_COLUMN -> {
|
||||
TYPE_COLUMN, TYPE_QQ_MINI_GAME_COLUMN, TYPE_WECHAT_GAME_COLUMN, TYPE_WECHAT_GAME_CPM_COLUMN -> {
|
||||
val subjectType = when(entity.type) {
|
||||
TYPE_QQ_MINI_GAME_COLUMN -> SubjectData.SubjectType.QQ_GAME
|
||||
TYPE_WECHAT_GAME_COLUMN -> SubjectData.SubjectType.WECHAT_GAME
|
||||
TYPE_WECHAT_GAME_CPM_COLUMN -> SubjectData.SubjectType.WECHAT_GAME_CPM
|
||||
else -> SubjectData.SubjectType.NORMAL
|
||||
}
|
||||
className = SubjectFragment::class.java.name
|
||||
|
||||
@ -14,7 +14,6 @@ import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.TopCutProcess
|
||||
import com.gh.gamecenter.databinding.ItemCommunityImageBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
import com.gh.gamecenter.feature.entity.ImageInfo
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
@ -312,7 +311,7 @@ class ImageContainerView : LinearLayout {
|
||||
|| images.isNullOrEmpty())
|
||||
return ImageContainerData(
|
||||
status = status,
|
||||
isPostCard = type == COMMUNITY_ARTICLE || type == ImageArticleEntity.IMAGE_ARTICLE_TYPE,
|
||||
isPostCard = type == COMMUNITY_ARTICLE,
|
||||
images = imageInfoList,
|
||||
video = video,
|
||||
show
|
||||
|
||||
@ -1,277 +0,0 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
|
||||
class RedBookBannerIndicatorView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0,
|
||||
) : View(context, attrs, defStyleAttr) {
|
||||
|
||||
private var defaultColor = com.gh.gamecenter.common.R.color.text_instance.toColor(context)
|
||||
private var selectedColor = com.gh.gamecenter.common.R.color.primary_theme.toColor(context)
|
||||
private var largeRadius = 2F.dip2px().toFloat()
|
||||
private var smallRadius = 1.2F.dip2px().toFloat()
|
||||
private var distanceBetweenCenters = 8F.dip2px().toFloat()
|
||||
private var maxShowDotCount = 5
|
||||
|
||||
private var lastPosition = 0
|
||||
private var currentPosition = 0
|
||||
private var firstShowPosition = 0
|
||||
private var lastShowPosition = 0
|
||||
|
||||
private var animationProgress = 0F
|
||||
|
||||
private var animationState: AnimationState = AnimationState.No
|
||||
|
||||
private var valueAnimator: ValueAnimator? = null
|
||||
|
||||
private val paint by lazy {
|
||||
Paint().apply {
|
||||
style = Paint.Style.FILL
|
||||
isAntiAlias = true
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
initAttrs(context, attrs)
|
||||
}
|
||||
|
||||
private fun initAttrs(context: Context, attrs: AttributeSet?) {
|
||||
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RedBookBannerIndicatorView)
|
||||
defaultColor = typedArray.getColor(R.styleable.RedBookBannerIndicatorView_default_color, defaultColor)
|
||||
selectedColor = typedArray.getColor(R.styleable.RedBookBannerIndicatorView_selected_color, selectedColor)
|
||||
largeRadius = typedArray.getDimension(R.styleable.RedBookBannerIndicatorView_large_radius, largeRadius)
|
||||
smallRadius = typedArray.getDimension(R.styleable.RedBookBannerIndicatorView_small_radius, smallRadius)
|
||||
distanceBetweenCenters = typedArray.getDimension(
|
||||
R.styleable.RedBookBannerIndicatorView_distance_between_centers,
|
||||
distanceBetweenCenters
|
||||
)
|
||||
maxShowDotCount =
|
||||
typedArray.getInt(R.styleable.RedBookBannerIndicatorView_max_show_dot_count, maxShowDotCount)
|
||||
typedArray.recycle()
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val width = if (lastPosition >= maxShowDotCount) {
|
||||
(maxShowDotCount - 1) * distanceBetweenCenters + 2 * largeRadius
|
||||
} else {
|
||||
lastShowPosition * distanceBetweenCenters + 2 * largeRadius
|
||||
}
|
||||
val height = largeRadius * 2
|
||||
setMeasuredDimension(width.toInt(), height.toInt())
|
||||
}
|
||||
|
||||
fun show(total: Int) {
|
||||
valueAnimator?.cancel()
|
||||
lastPosition = total - 1
|
||||
lastShowPosition = if (total > maxShowDotCount) {
|
||||
maxShowDotCount - 1
|
||||
} else {
|
||||
lastPosition
|
||||
}
|
||||
requestLayout()
|
||||
}
|
||||
|
||||
/**
|
||||
* 请注意,selectPosition只能一步一步跳
|
||||
* 比如:当currentPosition ==0 时,selectPosition为2,仍然只会往前跳一步,最终 currentPosition == 1
|
||||
*/
|
||||
fun selectPosition(position: Int) {
|
||||
if (currentPosition == position || position < 0 || position > lastPosition) {
|
||||
return
|
||||
}
|
||||
valueAnimator?.cancel()
|
||||
if (position > currentPosition) {
|
||||
currentPosition++
|
||||
} else if (position < currentPosition) {
|
||||
currentPosition--
|
||||
}
|
||||
|
||||
when (currentPosition) {
|
||||
0 -> {
|
||||
firstShowPosition = 0
|
||||
lastShowPosition = maxShowDotCount - 1
|
||||
if (lastShowPosition > lastPosition) {
|
||||
lastShowPosition = lastPosition
|
||||
}
|
||||
}
|
||||
|
||||
lastPosition -> {
|
||||
lastShowPosition = lastPosition
|
||||
firstShowPosition = lastPosition - maxShowDotCount + 1
|
||||
if (firstShowPosition < 0) {
|
||||
firstShowPosition = (0)
|
||||
}
|
||||
}
|
||||
|
||||
firstShowPosition -> {
|
||||
animationState = AnimationState.RightReady
|
||||
}
|
||||
|
||||
lastShowPosition -> {
|
||||
animationState = AnimationState.LeftReady
|
||||
}
|
||||
|
||||
}
|
||||
invalidate()
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
// 保存 Canvas 的当前状态
|
||||
canvas.save();
|
||||
|
||||
// 限制绘制区域为 View 的边界
|
||||
canvas.clipRect(0, 0, getWidth(), getHeight());
|
||||
if (lastShowPosition > firstShowPosition) {
|
||||
val first = if (firstShowPosition > 0) {
|
||||
firstShowPosition - 1
|
||||
} else {
|
||||
firstShowPosition
|
||||
}
|
||||
val last = if (lastShowPosition < lastPosition) {
|
||||
lastShowPosition + 1
|
||||
} else {
|
||||
lastPosition
|
||||
}
|
||||
|
||||
for (position in first..last) {
|
||||
var radius = when (position) {
|
||||
firstShowPosition -> if (firstShowPosition == 0) {
|
||||
largeRadius
|
||||
} else {
|
||||
smallRadius
|
||||
}
|
||||
|
||||
lastShowPosition -> if (lastShowPosition == lastPosition) {
|
||||
largeRadius
|
||||
} else {
|
||||
smallRadius
|
||||
}
|
||||
|
||||
else -> largeRadius
|
||||
}
|
||||
|
||||
val offset = if (animationState == AnimationState.LeftPlaying) {
|
||||
-animationProgress * distanceBetweenCenters
|
||||
} else {
|
||||
animationProgress * distanceBetweenCenters
|
||||
}
|
||||
val centerX = ((position - firstShowPosition) * distanceBetweenCenters + largeRadius) + offset
|
||||
paint.color = if (position == currentPosition) {
|
||||
selectedColor
|
||||
} else {
|
||||
defaultColor
|
||||
}
|
||||
|
||||
radius = getScaleRadius(position, radius)
|
||||
canvas.drawCircle(centerX, largeRadius, radius, paint)
|
||||
}
|
||||
|
||||
if (animationState == AnimationState.LeftReady || animationState == AnimationState.RightReady) {
|
||||
startAnimation()
|
||||
}
|
||||
}
|
||||
// 恢复 Canvas 到之前的状态
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
private fun getScaleRadius(position: Int, radius: Float): Float {
|
||||
var newRadius = radius
|
||||
if (animationState == AnimationState.LeftPlaying) {
|
||||
// 第二个可见的小圆点
|
||||
if (position - 1 == firstShowPosition) {
|
||||
newRadius = largeRadius - (largeRadius - smallRadius) * animationProgress
|
||||
}
|
||||
// 最后一个可见的小圆点
|
||||
if (position == lastShowPosition) {
|
||||
newRadius = smallRadius + (largeRadius - smallRadius) * animationProgress
|
||||
}
|
||||
// 最后一个不可见的小圆点
|
||||
if (position == lastShowPosition + 1) {
|
||||
newRadius = smallRadius
|
||||
}
|
||||
|
||||
}
|
||||
if (animationState == AnimationState.RightPlaying) {
|
||||
if (position == firstShowPosition - 1) {
|
||||
newRadius = smallRadius
|
||||
}
|
||||
if (position == firstShowPosition) {
|
||||
newRadius = smallRadius + (largeRadius - smallRadius) * animationProgress
|
||||
}
|
||||
if (position + 1 == lastShowPosition) {
|
||||
newRadius = largeRadius - (largeRadius - smallRadius) * animationProgress
|
||||
}
|
||||
}
|
||||
return newRadius
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行向左的平移动画
|
||||
*/
|
||||
private fun startAnimation() {
|
||||
animationState = if (animationState == AnimationState.LeftReady) {
|
||||
AnimationState.LeftPlaying
|
||||
} else {
|
||||
AnimationState.RightPlaying
|
||||
}
|
||||
fun resetShowPosition() {
|
||||
if (animationState == AnimationState.LeftPlaying) {
|
||||
firstShowPosition++
|
||||
lastShowPosition++
|
||||
} else {
|
||||
firstShowPosition--
|
||||
lastShowPosition--
|
||||
}
|
||||
animationState = AnimationState.No
|
||||
animationProgress = 0F
|
||||
invalidate()
|
||||
}
|
||||
valueAnimator = ValueAnimator.ofFloat(0F, 1F).apply {
|
||||
setDuration(ANIMATION_DURATION)
|
||||
addUpdateListener {
|
||||
val progress = it.animatedValue as Float
|
||||
animationProgress = progress
|
||||
invalidate()
|
||||
}
|
||||
addListener(object : Animator.AnimatorListener {
|
||||
override fun onAnimationStart(animation: Animator) = Unit
|
||||
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
resetShowPosition()
|
||||
}
|
||||
|
||||
override fun onAnimationCancel(animation: Animator) {
|
||||
resetShowPosition()
|
||||
}
|
||||
|
||||
override fun onAnimationRepeat(animation: Animator) = Unit
|
||||
|
||||
})
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ANIMATION_DURATION = 300L
|
||||
}
|
||||
|
||||
sealed class AnimationState {
|
||||
object No : AnimationState()
|
||||
object LeftReady : AnimationState()
|
||||
object RightReady : AnimationState()
|
||||
object LeftPlaying : AnimationState()
|
||||
object RightPlaying : AnimationState()
|
||||
}
|
||||
}
|
||||
@ -1,107 +0,0 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.OnClickListener
|
||||
import android.widget.LinearLayout
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.doOnAnimationEnd
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.toResString
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.databinding.LayoutVoteBinding
|
||||
import com.gh.gamecenter.entity.VoteEntity
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleUseCase.Companion.notifyVoteChanged
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
|
||||
class VoteStateView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private var binding: LayoutVoteBinding = LayoutVoteBinding.inflate(LayoutInflater.from(context), this, true)
|
||||
|
||||
private var status = IMAGE_ARTICLE_PENDING
|
||||
|
||||
private var isAnimatorPlaying = false
|
||||
|
||||
private var outClickListener: OnClickListener? = null
|
||||
|
||||
private val inClickListener = OnClickListener {
|
||||
if (isAnimatorPlaying) {
|
||||
return@OnClickListener
|
||||
}
|
||||
when (status) {
|
||||
IMAGE_ARTICLE_PENDING -> {
|
||||
ToastUtils.showToast(R.string.content_pending_status.toResString())
|
||||
}
|
||||
|
||||
IMAGE_ARTICLE_FAIL -> {
|
||||
ToastUtils.showToast(R.string.fail_status.toResString())
|
||||
}
|
||||
|
||||
IMAGE_ARTICLE_PASS -> {
|
||||
outClickListener?.onClick(it)
|
||||
if (!binding.ivVote.isChecked) {
|
||||
playVoteAnimation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun setVote(isVote: Boolean, count: Int, status: String) {
|
||||
this.status = status
|
||||
binding.ivVote.isChecked = isVote
|
||||
binding.tvVoteCount.text = getVoteCountText(count, context)
|
||||
val textColorResId = if (isVote) {
|
||||
com.gh.gamecenter.common.R.color.text_theme
|
||||
} else {
|
||||
com.gh.gamecenter.common.R.color.text_secondary
|
||||
}
|
||||
binding.tvVoteCount.setTextColor(textColorResId.toColor(context))
|
||||
}
|
||||
|
||||
override fun setOnClickListener(l: OnClickListener?) {
|
||||
outClickListener = l
|
||||
super.setOnClickListener(inClickListener)
|
||||
}
|
||||
|
||||
private fun getVoteCountText(count: Int, context: Context) =
|
||||
when {
|
||||
count <= 0 -> R.string.like.toResString()
|
||||
count in 1 until VOTE_TEN_THOUSAND -> "$count"
|
||||
else -> context.getString(R.string.ten_thousand, "$count")
|
||||
}
|
||||
|
||||
private fun playVoteAnimation() {
|
||||
with(binding) {
|
||||
isAnimatorPlaying = true
|
||||
tvVoteCount.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
ivVote.isChecked = true
|
||||
ivVote.visibility = View.INVISIBLE
|
||||
voteAnimation.visibility = View.VISIBLE
|
||||
voteAnimation.setAnimation("lottie/community_vote.json")
|
||||
voteAnimation.playAnimation()
|
||||
voteAnimation.doOnAnimationEnd {
|
||||
voteAnimation.visibility = View.GONE
|
||||
ivVote.visibility = View.VISIBLE
|
||||
isAnimatorPlaying = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val VOTE_TEN_THOUSAND = 10000
|
||||
|
||||
private const val IMAGE_ARTICLE_PENDING = "pending"
|
||||
private const val IMAGE_ARTICLE_FAIL = "fail"
|
||||
private const val IMAGE_ARTICLE_PASS = "pass"
|
||||
}
|
||||
}
|
||||
@ -34,7 +34,9 @@ import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
@ -216,7 +218,7 @@ object PackageObserver {
|
||||
try {
|
||||
jsonObject.put("game_id", gameId)
|
||||
jsonObject.put("package", packageName)
|
||||
val rBody = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
|
||||
val rBody = jsonObject.toString().toRequestBody("application/json".toMediaTypeOrNull())
|
||||
RetrofitManager.getInstance().api
|
||||
.postPlayedGame(UserManager.getInstance().userId, rBody)
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
@ -94,8 +94,8 @@ object ExoCacheManager {
|
||||
response =
|
||||
OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build()
|
||||
.newCall(request).execute()
|
||||
if (response!!.isSuccessful && response.body() != null) {
|
||||
val length = response.body()!!.contentLength()
|
||||
if (response!!.isSuccessful && response.body != null) {
|
||||
val length = response.body!!.contentLength()
|
||||
contentLength = if (length == 0L) -1L else length
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
@ -27,12 +27,24 @@ object SimpleDownloadManager {
|
||||
val downloadStatus = mDownloadQueue.getStatus(config.uniqueId)
|
||||
|
||||
if (downloadStatus != DownloadStatus.PAUSED) {
|
||||
ExecutorProvider.getInstance().backgroundExecutor.execute {
|
||||
DownloadMessageHandler.insertDownloadToDatabase(getDownloadEntity(config))
|
||||
mDownloadQueue.submitNewTask(config)
|
||||
}
|
||||
createNewTaskAndDownload(config)
|
||||
} else {
|
||||
resume(config.uniqueId)
|
||||
try {
|
||||
resume(config.uniqueId)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
createNewTaskAndDownload(config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新任务并下载
|
||||
*/
|
||||
private fun createNewTaskAndDownload(config: DownloadConfig) {
|
||||
ExecutorProvider.getInstance().backgroundExecutor.execute {
|
||||
mDownloadQueue.cancel(config.uniqueId)
|
||||
DownloadMessageHandler.insertDownloadToDatabase(getDownloadEntity(config))
|
||||
mDownloadQueue.submitNewTask(config)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -76,19 +76,6 @@ public class CommentDetailActivity extends ToolBarActivity {
|
||||
return getTargetIntent(context, CommentDetailActivity.class, NewCommentConversationFragment.class, args);
|
||||
}
|
||||
|
||||
public static Intent getImageArticleCommentIntent(Context context,
|
||||
String articleId,
|
||||
String articleCommentId,
|
||||
String communityId,
|
||||
LinkEntity linkEntity) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(CommentActivity.IMAGE_ARTICLE_ID, articleId);
|
||||
args.putString(EntranceConsts.KEY_COMMENTID, articleCommentId);
|
||||
args.putString(CommentActivity.COMMUNITY_ID, communityId);
|
||||
args.putParcelable(EntranceConsts.KEY_LINK, linkEntity);
|
||||
return getTargetIntent(context, CommentDetailActivity.class, NewCommentConversationFragment.class, args);
|
||||
}
|
||||
|
||||
public static Intent getVideoCommentIntent(Context context,
|
||||
String commentId,
|
||||
String videoId,
|
||||
|
||||
@ -408,7 +408,7 @@ public class SkipActivity extends BaseActivity {
|
||||
try {
|
||||
JSONObject extJsonObject = new JSONObject(extJson);
|
||||
String qqGameId = extJsonObject.optString("aid");
|
||||
MiniGameItemHelper.INSTANCE.launchMiniGame(qqGameId, Constants.QQ_MINI_GAME);
|
||||
MiniGameItemHelper.INSTANCE.launchMiniGame(qqGameId, Constants.QQ_MINI_GAME, "", "");
|
||||
} catch (JSONException ignored) {
|
||||
}
|
||||
break;
|
||||
|
||||
@ -27,7 +27,7 @@ open class BaseCloudArchiveViewModel(application: Application, private val mConf
|
||||
)
|
||||
.enqueue(object : Callback {
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
mArchiveConfigStr = response.body()?.string() ?: ""
|
||||
mArchiveConfigStr = response.body?.string() ?: ""
|
||||
callback?.invoke(mArchiveConfigStr)
|
||||
}
|
||||
|
||||
|
||||
@ -93,7 +93,7 @@ class AdGameBannerAdapter(
|
||||
it.name ?: ""
|
||||
)
|
||||
if (it.isMiniGame()) {
|
||||
MiniGameItemHelper.launchMiniGame(it.miniGameAppId, it.miniGameType)
|
||||
MiniGameItemHelper.launchMiniGame(it)
|
||||
} else {
|
||||
GameDetailActivity.startGameDetailActivity(
|
||||
mContext,
|
||||
|
||||
@ -43,7 +43,6 @@ data class FollowDynamicEntity(
|
||||
const val FOLLOW_UPDATE_TYPE_LIBAO_EXCHANGE = "libao_exchange"
|
||||
const val FOLLOW_UPDATE_TYPE_ARTICLE = "article"
|
||||
const val FOLLOW_UPDATE_TYPE_USER_POST = "user_post"
|
||||
const val FOLLOW_UPDATE_TYPE_IMAGE_ARTICLE = "image_article"
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
|
||||
@ -1,230 +0,0 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.feature.entity.*
|
||||
import com.gh.gamecenter.feature.entity.TimeEntity
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class ImageArticleEntity(
|
||||
@SerializedName("_id")
|
||||
private var _id: String? = null,
|
||||
@SerializedName("title")
|
||||
private var _title: String? = null,
|
||||
@SerializedName("content")
|
||||
private val _content: String? = null,
|
||||
@SerializedName("community_id")
|
||||
private var _communityId: String? = null,
|
||||
@SerializedName("community_type")
|
||||
private val _communityType: String? = null,
|
||||
@SerializedName("sections")
|
||||
private val _sections: List<SectionEntity>? = null,
|
||||
@SerializedName("images")
|
||||
private var _images: List<String>? = null,
|
||||
@SerializedName("images_info")
|
||||
private val _imagesInfos: List<ImageInfo>? = null,
|
||||
@SerializedName("community")
|
||||
val community: Community? = null,
|
||||
@SerializedName("user")
|
||||
private val _user: UserEntity? = null,
|
||||
@SerializedName("time")
|
||||
private val _time: TimeEntity? = null,
|
||||
@SerializedName("status")
|
||||
private val _status: String? = null,
|
||||
@SerializedName("source")
|
||||
private val _source: SourceEntity? = null,
|
||||
@SerializedName("count")
|
||||
private val _count: Count? = null,
|
||||
@SerializedName("me")
|
||||
private val _me: MeEntity? = null,
|
||||
@SerializedName("_seq")
|
||||
private val _shortId: String? = null,
|
||||
@SerializedName("choiceness_status")
|
||||
private var _choicenessStatus: String? = null,// 精选状态 apply(申请), pass already(已精选) cancel not_yet(未精选)
|
||||
@SerializedName("recommend_id")
|
||||
private val _recommendId: String? = null,
|
||||
/**
|
||||
* 临时变量,区分是编辑发布还是编辑草稿
|
||||
*/
|
||||
var isDraft: Boolean = false
|
||||
) : Parcelable {
|
||||
|
||||
val id: String
|
||||
get() = _id ?: ""
|
||||
|
||||
val title: String
|
||||
get() = _title ?: ""
|
||||
|
||||
val content: String
|
||||
get() = _content ?: ""
|
||||
|
||||
val communityId: String
|
||||
get() = _communityId ?: ""
|
||||
|
||||
val communityType: String
|
||||
get() = _communityType ?: ""
|
||||
|
||||
val sections: List<SectionEntity>
|
||||
get() = _sections ?: emptyList()
|
||||
|
||||
val images: List<String>
|
||||
get() = _images ?: emptyList()
|
||||
|
||||
val imagesInfos: List<ImageInfo>
|
||||
get() = _imagesInfos ?: emptyList()
|
||||
|
||||
val user: UserEntity
|
||||
get() = _user ?: UserEntity()
|
||||
|
||||
val time: TimeEntity
|
||||
get() = _time ?: TimeEntity()
|
||||
|
||||
val status: String
|
||||
get() = _status ?: "pending"
|
||||
|
||||
val source: SourceEntity
|
||||
get() = _source ?: SourceEntity()
|
||||
|
||||
val count: Count
|
||||
get() = _count ?: Count()
|
||||
|
||||
val me: MeEntity
|
||||
get() = _me ?: MeEntity()
|
||||
|
||||
val shortId: String
|
||||
get() = _shortId ?: ""
|
||||
|
||||
var choicenessStatus: String
|
||||
get() = _choicenessStatus ?: ""
|
||||
set(value) {
|
||||
_choicenessStatus = value
|
||||
}
|
||||
|
||||
val recommendId: String
|
||||
get() = _recommendId ?: ""
|
||||
|
||||
fun getSimplifyChoicenessStatus(): String {
|
||||
return when (choicenessStatus) {
|
||||
"already" -> "pass"
|
||||
"not_yet" -> "cancel"
|
||||
else -> choicenessStatus ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val IMAGE_ARTICLE_TYPE = "image_article"
|
||||
|
||||
fun getImageRadio(imageInfo: ImageInfo?, minRadio: Float, maxRadio: Float): Float {
|
||||
return if (imageInfo != null && imageInfo.width > 0 && imageInfo.height > 0) {
|
||||
val imageRadio = imageInfo.height.toFloat() / imageInfo.width
|
||||
when {
|
||||
imageRadio < minRadio -> {
|
||||
minRadio
|
||||
}
|
||||
|
||||
imageRadio in 0.5..1.33 -> {
|
||||
imageRadio
|
||||
}
|
||||
|
||||
else -> {
|
||||
maxRadio
|
||||
}
|
||||
}
|
||||
} else {
|
||||
minRadio
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
data class Community(
|
||||
@SerializedName("_id")
|
||||
private val _id: String? = null,
|
||||
@SerializedName("name")
|
||||
private val _name: String? = null,
|
||||
@SerializedName("icon")
|
||||
private val _icon: String? = null,
|
||||
@SerializedName("hot")
|
||||
private val _hot: Int? = null,
|
||||
@SerializedName("game")
|
||||
val game: GameEntity? = null,
|
||||
@SerializedName("type")
|
||||
private val _type: String? = null,
|
||||
@SerializedName("me")
|
||||
private val _me: MeEntity?
|
||||
) : Parcelable {
|
||||
|
||||
val id: String
|
||||
get() = _id ?: ""
|
||||
|
||||
val name: String
|
||||
get() = _name ?: ""
|
||||
|
||||
val icon: String
|
||||
get() = _icon ?: ""
|
||||
|
||||
val hot: Int
|
||||
get() = _hot ?: 0
|
||||
|
||||
val type: String
|
||||
get() = _type ?: "game_bbs"
|
||||
|
||||
val typeChinese: String
|
||||
get() = when (type) {
|
||||
"game_bbs" -> "游戏论坛"
|
||||
"official_bbs" -> "综合论坛"
|
||||
else -> ""
|
||||
}
|
||||
|
||||
var isFollowed: Boolean
|
||||
get() = _me?.isFollower ?: false
|
||||
set(value) {
|
||||
_me?.isFollower = value
|
||||
}
|
||||
|
||||
fun toCommunityEntity() = CommunityEntity(
|
||||
id = id,
|
||||
name = name,
|
||||
icon = icon,
|
||||
type = type,
|
||||
)
|
||||
}
|
||||
|
||||
fun toPersonHistoryEntity() = PersonalHistoryEntity().also {
|
||||
it.id = id
|
||||
it.title = title
|
||||
it.brief = content
|
||||
it.community = community?.toCommunityEntity() ?: CommunityEntity()
|
||||
it.sections = sections
|
||||
it.images = images
|
||||
it.imagesInfo = imagesInfos
|
||||
it.count = count
|
||||
it.user = user
|
||||
it.time = time.update
|
||||
it.status = status
|
||||
it.me = me
|
||||
}
|
||||
|
||||
fun toAnswerEntity() = AnswerEntity().also {
|
||||
it.id = id
|
||||
it.title = title
|
||||
it.brief = content
|
||||
it.content = content
|
||||
it.community = community?.toCommunityEntity() ?: CommunityEntity()
|
||||
it.sections = sections
|
||||
it.images = images
|
||||
it.imagesInfo = imagesInfos
|
||||
it.count = count
|
||||
it.user = user
|
||||
it.time = time.update
|
||||
it.status = status
|
||||
it.me = me
|
||||
it.type = IMAGE_ARTICLE_TYPE
|
||||
}
|
||||
|
||||
}
|
||||
@ -36,13 +36,12 @@ data class PersonalHistoryEntity(
|
||||
var length: Long = 0,
|
||||
@SerializedName("count")
|
||||
private var _count: Count = Count(),
|
||||
var time: Long = 0,
|
||||
val time: Long = 0,
|
||||
@SerializedName("title")
|
||||
|
||||
private var _title: String = "",
|
||||
var description: String = "",
|
||||
@SerializedName("community")
|
||||
private var _community: CommunityEntity? = null,
|
||||
private var _community: CommunityEntity = CommunityEntity(),
|
||||
var videos: List<CommunityVideoEntity> = ArrayList(),
|
||||
@SerializedName("user")
|
||||
private var _user: UserEntity? = null,
|
||||
@ -64,17 +63,8 @@ data class PersonalHistoryEntity(
|
||||
@SerializedName("sections")
|
||||
@Ignore
|
||||
private var _sections: List<SectionEntity> = ArrayList(),
|
||||
|
||||
// 图文新增字段
|
||||
@SerializedName("content")
|
||||
private val _content: String? = null,
|
||||
@SerializedName("source")
|
||||
private val _source: SourceEntity? = null,
|
||||
) : Parcelable, CommunityItemData {
|
||||
|
||||
val content: String
|
||||
get() = _content ?: ""
|
||||
|
||||
override var id: String
|
||||
get() = _id
|
||||
set(value) {
|
||||
@ -114,7 +104,7 @@ data class PersonalHistoryEntity(
|
||||
}
|
||||
|
||||
override var community: CommunityEntity
|
||||
get() = _community ?: CommunityEntity()
|
||||
get() = _community
|
||||
set(value) {
|
||||
_community = value
|
||||
}
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class PublishImageTextRequest(
|
||||
val title: String,
|
||||
val content: String,
|
||||
@SerializedName("community_type")
|
||||
val communityType: String,
|
||||
@SerializedName("community_id")
|
||||
val communityId: String,
|
||||
@SerializedName("section_id")
|
||||
val sectionId: List<String>,
|
||||
var images: List<String> = listOf(),
|
||||
@SerializedName("draft_id")
|
||||
val draftId: String = ""
|
||||
)
|
||||
@ -9,14 +9,16 @@ import kotlinx.parcelize.Parcelize
|
||||
@Parcelize
|
||||
data class SearchSubjectEntity(
|
||||
val name: String = "",
|
||||
val games: List<GameEntity> = listOf(),
|
||||
var games: List<GameEntity> = listOf(),
|
||||
val location: Int = 0,
|
||||
@SerializedName("column_id")
|
||||
val columnId: String = "",
|
||||
val adId: String = "", // 广告ID(本地字段),不为空时为广告专题
|
||||
val codeId: String = "", // 广告CODE_ID(本地字段),不为空时为广告专题
|
||||
@SerializedName("ad_icon_active")
|
||||
val adIconActive: Boolean = false
|
||||
val adIconActive: Boolean = false,
|
||||
// 本地字段,标记是否为微信小游戏CPM专题
|
||||
var isWGameSubjectCPM: Boolean = false
|
||||
) : Parcelable {
|
||||
fun getFilterGame() = RegionSettingHelper.filterGame(games)
|
||||
}
|
||||
@ -63,6 +63,11 @@ class SubjectData(
|
||||
/**
|
||||
* 微信小游戏专题
|
||||
*/
|
||||
WECHAT_GAME
|
||||
WECHAT_GAME,
|
||||
|
||||
/**
|
||||
* 微信小游戏CPM专题
|
||||
*/
|
||||
WECHAT_GAME_CPM,
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,6 +104,8 @@ data class SubjectEntity(
|
||||
@SerializedName("is_wechat_column")
|
||||
var isWechatColumn: Boolean = false,
|
||||
|
||||
var isWechatColumnCPM: Boolean = false,
|
||||
|
||||
var explain: String = "", // 游戏单合集说明
|
||||
|
||||
@SerializedName("show_star")
|
||||
@ -130,6 +132,7 @@ data class SubjectEntity(
|
||||
|
||||
val subjectType: SubjectData.SubjectType get() = when {
|
||||
isQQColumn -> SubjectData.SubjectType.QQ_GAME
|
||||
isWechatColumnCPM -> SubjectData.SubjectType.WECHAT_GAME_CPM
|
||||
isWechatColumn -> SubjectData.SubjectType.WECHAT_GAME
|
||||
else -> SubjectData.SubjectType.NORMAL
|
||||
}
|
||||
|
||||
@ -2,15 +2,8 @@ package com.gh.gamecenter.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class VoteEntity(
|
||||
@SerializedName("vote")
|
||||
private val _vote: Int? = null,
|
||||
class VoteEntity(
|
||||
var vote: Int? = 0,
|
||||
@SerializedName("is_guide_follow")
|
||||
private var _isGuideFollow: Boolean? = null
|
||||
) {
|
||||
val vote: Int
|
||||
get() = _vote ?: 0
|
||||
|
||||
val isGuideFollow: Boolean
|
||||
get() = _isGuideFollow ?: false
|
||||
}
|
||||
var isGuideFollow: Boolean = false
|
||||
)
|
||||
@ -1,16 +0,0 @@
|
||||
package com.gh.gamecenter.eventbus
|
||||
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
|
||||
sealed class EBImageArticleChanged {
|
||||
|
||||
data class VoteChanged(val id: String, val isVoted: Boolean, val count: Int) : EBImageArticleChanged()
|
||||
|
||||
data class CommentChanged(val id: String, val count: Int) : EBImageArticleChanged()
|
||||
|
||||
data class DataChanged(val data: ImageArticleEntity) : EBImageArticleChanged()
|
||||
|
||||
data class DataDeleted(val imageArticleId: String) : EBImageArticleChanged()
|
||||
|
||||
data class DataCreated(val imageArticle: ImageArticleEntity, val draftId: String = "") : EBImageArticleChanged()
|
||||
}
|
||||
@ -1,13 +1,11 @@
|
||||
package com.gh.gamecenter.forum.detail
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
import com.gh.gamecenter.common.constant.ItemViewType
|
||||
import com.gh.gamecenter.common.syncpage.ISyncAdapterHandler
|
||||
@ -16,8 +14,6 @@ import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.viewholder.FooterViewHolder
|
||||
import com.gh.gamecenter.common.baselist.ListAdapter
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
@ -25,7 +21,6 @@ import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.toDrawable
|
||||
import com.gh.gamecenter.databinding.ItemForumArticleHeadBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.forum.home.ForumArticleAskItemViewHolder
|
||||
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
|
||||
import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
@ -52,7 +47,7 @@ class ForumArticleAskListAdapter(
|
||||
}
|
||||
|
||||
override fun areItemsTheSame(oldItem: AnswerEntity?, newItem: AnswerEntity?): Boolean {
|
||||
return oldItem?.id == newItem?.id && oldItem?.type == newItem?.type
|
||||
return oldItem?.id == newItem?.id
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
@ -60,17 +55,9 @@ class ForumArticleAskListAdapter(
|
||||
ItemViewType.ITEM_HEADER -> {
|
||||
ForumArticleHeadViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
ItemViewType.ITEM_FOOTER -> {
|
||||
FooterViewHolder(
|
||||
mLayoutInflater.inflate(
|
||||
com.gh.gamecenter.common.R.layout.refresh_footerview,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
FooterViewHolder(mLayoutInflater.inflate(com.gh.gamecenter.common.R.layout.refresh_footerview, parent, false))
|
||||
}
|
||||
|
||||
else -> {
|
||||
ForumArticleAskItemViewHolder(
|
||||
CommunityAnswerItemBinding.bind(
|
||||
@ -108,8 +95,7 @@ class ForumArticleAskListAdapter(
|
||||
questions.answerCount = answer.count.answer
|
||||
answer.questions = questions
|
||||
}
|
||||
if (path == "精华" && answer.type != "answer" && answer.type != "video") answer.type =
|
||||
"community_article"
|
||||
if (path == "精华" && answer.type != "answer" && answer.type != "video") answer.type = "community_article"
|
||||
if (path == "问答") answer.type = "question"
|
||||
if (path == "视频") answer.type = "video"
|
||||
|
||||
@ -162,7 +148,6 @@ class ForumArticleAskListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"video" -> {
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
"click_forum_detail_content",
|
||||
@ -179,16 +164,8 @@ class ForumArticleAskListAdapter(
|
||||
holder.getKey(entrance),
|
||||
"${answer.title}(${answer.id})"
|
||||
)
|
||||
mContext.startActivity(
|
||||
ForumVideoDetailActivity.getIntent(
|
||||
mContext,
|
||||
answer.id,
|
||||
bbsId,
|
||||
"论坛详情-信息流"
|
||||
)
|
||||
)
|
||||
mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, answer.id, bbsId, "论坛详情-信息流"))
|
||||
}
|
||||
|
||||
"question" -> {
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
"click_forum_detail_content",
|
||||
@ -211,7 +188,6 @@ class ForumArticleAskListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"answer" -> {
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
"click_forum_detail_content",
|
||||
@ -239,63 +215,29 @@ class ForumArticleAskListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
"click_forum_detail_content",
|
||||
userId,
|
||||
contentId,
|
||||
"图文",
|
||||
sequence,
|
||||
bbsId,
|
||||
bbsType,
|
||||
tabInfo
|
||||
)
|
||||
val uri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, answer.id)
|
||||
.appendQueryParameter(EntranceConsts.KEY_SOURCE_ENTRANCE, "论坛详情-信息流")
|
||||
.build()
|
||||
ARouter.getInstance().build(uri).navigation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ItemViewType.ITEM_FOOTER -> {
|
||||
val footerViewHolder = holder as FooterViewHolder
|
||||
footerViewHolder.initItemPadding()
|
||||
footerViewHolder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver)
|
||||
footerViewHolder.hint.textSize = 12f
|
||||
footerViewHolder.hint.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
mContext,
|
||||
com.gh.gamecenter.common.R.color.aaaaaa
|
||||
)
|
||||
)
|
||||
footerViewHolder.hint.setTextColor(ContextCompat.getColor(mContext, com.gh.gamecenter.common.R.color.aaaaaa))
|
||||
}
|
||||
|
||||
ItemViewType.ITEM_HEADER -> {
|
||||
if (holder is ForumArticleHeadViewHolder) {
|
||||
val articleListHead = if (path == "全部") {
|
||||
viewModel.selectedSection.name
|
||||
} else path
|
||||
holder.binding.root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(mContext))
|
||||
holder.binding.articleListHeadTv.setTextColor(
|
||||
com.gh.gamecenter.common.R.color.text_primary.toColor(
|
||||
mContext
|
||||
)
|
||||
)
|
||||
holder.binding.articleListHeadTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
|
||||
holder.binding.articleListHeadTv.text = "${articleListHead}列表"
|
||||
|
||||
if (path != "精华") {
|
||||
holder.binding.orderSfv.run {
|
||||
visibility = View.VISIBLE
|
||||
setContainerBackground(
|
||||
com.gh.gamecenter.common.R.drawable.button_round_f5f5f5.toDrawable(
|
||||
mContext
|
||||
)
|
||||
)
|
||||
setContainerBackground(com.gh.gamecenter.common.R.drawable.button_round_f5f5f5.toDrawable(mContext))
|
||||
setIndicatorBackground(R.drawable.bg_game_collection_sfv_indicator.toDrawable(mContext))
|
||||
setTextColor(
|
||||
com.gh.gamecenter.common.R.color.text_secondary.toColor(mContext),
|
||||
|
||||
@ -10,7 +10,6 @@ import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.baselist.LazyListFragment
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.utils.safelyGetInRelease
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.tryCatchInRelease
|
||||
@ -19,13 +18,10 @@ import com.gh.gamecenter.core.iinterface.IScrollable
|
||||
import com.gh.gamecenter.core.utils.MD5Utils
|
||||
import com.gh.gamecenter.databinding.FragmentForumArticleAskListBinding
|
||||
import com.gh.gamecenter.entity.ForumDetailEntity
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.eventbus.EBDeleteDetail
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.eventbus.EBUserFollow
|
||||
import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
import com.gh.gamecenter.forum.home.ForumScrollCalculatorHelper
|
||||
import com.gh.gamecenter.personalhome.home.UserHistoryAdapter.Companion.USER_HISTORY_PAYLOADS_VOTE_CHANGED
|
||||
import com.gh.gamecenter.video.detail.CustomManager
|
||||
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
@ -136,72 +132,6 @@ class ForumArticleAskListFragment : LazyListFragment<AnswerEntity, ForumArticleA
|
||||
mScrollCalculatorHelper?.currentPlayer?.release()
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
when {
|
||||
changed is EBImageArticleChanged.VoteChanged -> {
|
||||
updateImageArticleItem(changed.id, true) {
|
||||
val newCount = it.count
|
||||
newCount.vote = changed.count
|
||||
it.count = newCount
|
||||
it.me.isCommunityArticleVote = changed.isVoted
|
||||
}
|
||||
}
|
||||
|
||||
changed is EBImageArticleChanged.CommentChanged -> {
|
||||
updateImageArticleItem(changed.id, true) {
|
||||
val newCount = it.count
|
||||
newCount.comment = changed.count
|
||||
it.count = newCount
|
||||
}
|
||||
}
|
||||
|
||||
changed is EBImageArticleChanged.DataDeleted -> {
|
||||
mViewModel?.deleteImageArticle(changed.imageArticleId)
|
||||
}
|
||||
|
||||
changed is EBImageArticleChanged.DataChanged -> {
|
||||
val imageArticle = changed.data
|
||||
updateImageArticleItem(changed.data.id, false) {
|
||||
it.title = imageArticle.title
|
||||
it.brief = imageArticle.content
|
||||
it.images = imageArticle.images
|
||||
it.imagesInfo = imageArticle.imagesInfos
|
||||
it.community = imageArticle.community?.toCommunityEntity() ?: CommunityEntity()
|
||||
it.sections = imageArticle.sections
|
||||
it.count = imageArticle.count
|
||||
it.user = imageArticle.user
|
||||
it.time = imageArticle.time.update
|
||||
it.status = imageArticle.status
|
||||
}
|
||||
}
|
||||
|
||||
changed is EBImageArticleChanged.DataCreated -> {
|
||||
mViewModel?.addNewestImageArticle(changed.imageArticle.toAnswerEntity())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateImageArticleItem(
|
||||
id: String,
|
||||
hasPayload: Boolean,
|
||||
block: (AnswerEntity) -> Unit
|
||||
) {
|
||||
val dataList = mAdapter?.entityList ?: return
|
||||
val position =
|
||||
dataList.indexOfFirst { it.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE && it.id == id }
|
||||
if (position != -1) {
|
||||
val item = dataList[position]
|
||||
block(item)
|
||||
if (hasPayload) {
|
||||
mAdapter?.notifyItemChanged(position, USER_HISTORY_PAYLOADS_VOTE_CHANGED)
|
||||
} else {
|
||||
mAdapter?.notifyItemChanged(position)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLoadRefresh() {
|
||||
super.onLoadRefresh()
|
||||
if (::mBinding.isInitialized) {
|
||||
|
||||
@ -4,13 +4,11 @@ import android.app.Application
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.gh.gamecenter.common.baselist.ListViewModel
|
||||
import com.gh.gamecenter.common.baselist.LoadType
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.core.utils.PageSwitchDataHelper
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.core.utils.UrlFilterUtils
|
||||
import com.gh.gamecenter.entity.ForumDetailEntity
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.ForumVideoEntity
|
||||
import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
@ -60,11 +58,9 @@ class ForumArticleAskListViewModel(application: Application, val bbsId: String =
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
"精华" -> {
|
||||
RetrofitManager.getInstance().api.getEssenceForumList(bbsId, page)
|
||||
}
|
||||
|
||||
"问答" -> {
|
||||
RetrofitManager.getInstance().api.getAskForumList(
|
||||
bbsId,
|
||||
@ -72,7 +68,6 @@ class ForumArticleAskListViewModel(application: Application, val bbsId: String =
|
||||
page
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
RetrofitManager.getInstance().api.getVideoForumList(
|
||||
bbsId,
|
||||
@ -99,28 +94,6 @@ class ForumArticleAskListViewModel(application: Application, val bbsId: String =
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteImageArticle(imageArticleId: String) {
|
||||
val oldData = mResultLiveData.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val hasRemoved =
|
||||
newData.removeAll { it.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE && it.id == imageArticleId }
|
||||
if (hasRemoved) {
|
||||
mResultLiveData.value = newData
|
||||
}
|
||||
}
|
||||
|
||||
fun addNewestImageArticle(item: AnswerEntity) {
|
||||
val oldData = mResultLiveData.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
if (newData.isEmpty()) {
|
||||
load(LoadType.REFRESH)
|
||||
} else {
|
||||
newData.add(1, item)
|
||||
mResultLiveData.value = newData
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Factory(private val bbsId: String, val path: String) : ViewModelProvider.NewInstanceFactory() {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return ForumArticleAskListViewModel(HaloApp.getInstance().application, bbsId, path) as T
|
||||
|
||||
@ -8,7 +8,6 @@ import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
@ -29,7 +28,6 @@ import androidx.core.os.bundleOf
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
@ -37,7 +35,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
|
||||
import androidx.viewpager.widget.PagerAdapter
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.ethanhua.skeleton.Skeleton
|
||||
import com.ethanhua.skeleton.ViewSkeletonScreen
|
||||
import com.facebook.drawee.drawable.ScalingUtils
|
||||
@ -59,7 +56,6 @@ import com.gh.gamecenter.common.base.fragment.BaseLazyTabFragment
|
||||
import com.gh.gamecenter.common.callback.BiCallback
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.databinding.ItemIconTabBinding
|
||||
import com.gh.gamecenter.common.databinding.PopupAllTabsBinding
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
@ -83,7 +79,6 @@ import com.gh.gamecenter.feature.entity.ForumVideoEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.UserEntity
|
||||
import com.gh.gamecenter.forum.home.CommunityHomeFragment
|
||||
import com.gh.gamecenter.forum.home.recommend.PublishImageArticleActivity
|
||||
import com.gh.gamecenter.forum.moderator.ApplyModeratorActivity
|
||||
import com.gh.gamecenter.forum.moderator.ModeratorListActivity
|
||||
import com.gh.gamecenter.forum.search.ForumOrUserSearchActivity
|
||||
@ -270,14 +265,12 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
|
||||
|
||||
if (!mIsFromTabWrapper) {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(mBinding.forumAppbar) { _, insets ->
|
||||
(mBinding.toolbar.layoutParams as MarginLayoutParams).topMargin =
|
||||
insets.getInsets(WindowInsetsCompat.Type.systemBars()).top
|
||||
(mBinding.toolbar.layoutParams as MarginLayoutParams).topMargin = insets.getInsets(WindowInsetsCompat.Type.systemBars()).top
|
||||
WindowInsetsCompat.CONSUMED
|
||||
}
|
||||
}
|
||||
if (mIsFromMainWrapper) {
|
||||
(mBinding.toolbar.layoutParams as MarginLayoutParams).topMargin =
|
||||
DisplayUtils.getStatusBarHeight(requireContext().resources)
|
||||
(mBinding.toolbar.layoutParams as MarginLayoutParams).topMargin = DisplayUtils.getStatusBarHeight(requireContext().resources)
|
||||
}
|
||||
mBinding.toolbar.setNavigationOnClickListener {
|
||||
NewLogUtils.logForumDetailEnterOrClick("click_forum_detail_return", mBbsId, mBbsType)
|
||||
@ -311,12 +304,7 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
|
||||
}
|
||||
|
||||
if (absVerticalOffset == total) {
|
||||
mBinding.toolbar.setTitleTextColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
com.gh.gamecenter.common.R.color.black
|
||||
)
|
||||
)
|
||||
mBinding.toolbar.setTitleTextColor(ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.black))
|
||||
}
|
||||
})
|
||||
mViewPager.doOnPageSelected {
|
||||
@ -642,10 +630,7 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
|
||||
params.topMargin = DisplayUtils.dip2px(-8f)
|
||||
mBinding.tabContainer.layoutParams = params
|
||||
mBinding.tabContainer.background =
|
||||
ContextCompat.getDrawable(
|
||||
requireContext(),
|
||||
com.gh.gamecenter.common.R.drawable.background_shape_white_radius_5_top_only
|
||||
)
|
||||
ContextCompat.getDrawable(requireContext(), com.gh.gamecenter.common.R.drawable.background_shape_white_radius_5_top_only)
|
||||
}
|
||||
|
||||
if (background.isEmpty()) {
|
||||
@ -896,7 +881,7 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
|
||||
forumName = mForumDetail?.name ?: "",
|
||||
bbsType = mForumDetail?.typeChinese ?: "",
|
||||
buttonName = mBinding.followTv.text.toString(),
|
||||
gameForumType = mForumDetail?.game?.categoryChinese ?: ""
|
||||
gameForumType = mForumDetail?.game?.categoryChinese?:""
|
||||
)
|
||||
ifLogin(mEntrance) {
|
||||
val forumEntity = ForumEntity(
|
||||
@ -1035,31 +1020,14 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
|
||||
val headView = SimpleDraweeView(requireContext())
|
||||
val roundingParams = RoundingParams().apply {
|
||||
roundAsCircle = true
|
||||
setBorder(
|
||||
ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.white),
|
||||
1F.dip2px().toFloat()
|
||||
)
|
||||
setBorder(ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.white), 1F.dip2px().toFloat())
|
||||
}
|
||||
headView.hierarchy = GenericDraweeHierarchyBuilder(resources)
|
||||
.setFadeDuration(500)
|
||||
.setRoundingParams(roundingParams)
|
||||
.setPressedStateOverlay(
|
||||
ColorDrawable(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
com.gh.gamecenter.common.R.color.pressed_bg
|
||||
)
|
||||
)
|
||||
)
|
||||
.setPressedStateOverlay(ColorDrawable(ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.pressed_bg)))
|
||||
.setPlaceholderImage(com.gh.gamecenter.common.R.drawable.occupy2, ScalingUtils.ScaleType.CENTER)
|
||||
.setBackground(
|
||||
ColorDrawable(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
com.gh.gamecenter.common.R.color.placeholder_bg
|
||||
)
|
||||
)
|
||||
)
|
||||
.setBackground(ColorDrawable(ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.placeholder_bg)))
|
||||
.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP)
|
||||
.build()
|
||||
headView.layoutParams = params
|
||||
@ -1121,35 +1089,6 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
|
||||
}
|
||||
}
|
||||
|
||||
contentView.findViewById<View>(R.id.community_edit_recommend_container).setOnClickListener {
|
||||
val icon = if ("official_bbs" == mForumDetail?.type) {
|
||||
mForumDetail?.icon ?: ""
|
||||
} else {
|
||||
mForumDetail?.game?.getIcon()
|
||||
}
|
||||
context?.ifLogin("论坛详情-发布-图文动态", action = {
|
||||
val uri = Uri.Builder()
|
||||
.path(RouteConsts.activity.publishImageArticleActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_ENTRANCE, "论坛详情页")
|
||||
.build()
|
||||
ARouter.getInstance()
|
||||
.build(uri)
|
||||
.withParcelable(
|
||||
EntranceConsts.KEY_COMMUNITY_DATA,
|
||||
CommunityEntity(
|
||||
mBbsId,
|
||||
name = mForumDetail?.name ?: "",
|
||||
iconSubscript = mForumDetail?.game?.iconSubscript,
|
||||
icon = icon,
|
||||
type = mForumDetail?.type ?: "",
|
||||
game = mForumDetail?.game?.toCommunityGameEntity()
|
||||
)
|
||||
)
|
||||
.navigation()
|
||||
dialog.dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
contentView.findViewById<View>(R.id.community_edit_article_container).setOnClickListener {
|
||||
context?.ifLogin("论坛详情-发布-发帖子", action = {
|
||||
checkStoragePermissionBeforeAction {
|
||||
@ -1275,12 +1214,10 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
|
||||
private fun toggleHighlightedView(targetView: View, highlightIt: Boolean) {
|
||||
val sectionTv = targetView.findViewById<TextView>(R.id.titleTv)
|
||||
if (highlightIt) {
|
||||
targetView.background =
|
||||
com.gh.gamecenter.common.R.drawable.button_round_theme_alpha_10.toDrawable(requireContext())
|
||||
targetView.background = com.gh.gamecenter.common.R.drawable.button_round_theme_alpha_10.toDrawable(requireContext())
|
||||
sectionTv?.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
|
||||
} else {
|
||||
targetView.background =
|
||||
com.gh.gamecenter.feature.R.drawable.button_round_gray_light.toDrawable(requireContext())
|
||||
targetView.background = com.gh.gamecenter.feature.R.drawable.button_round_gray_light.toDrawable(requireContext())
|
||||
sectionTv?.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,13 +17,11 @@ import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.airbnb.lottie.LottieProperty
|
||||
import com.airbnb.lottie.SimpleColorFilter
|
||||
import com.airbnb.lottie.model.KeyPath
|
||||
import com.airbnb.lottie.value.LottieValueCallback
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.common.browse.BrowseTimer
|
||||
import com.gh.common.iinterface.ISuperiorChain
|
||||
import com.gh.common.prioritychain.CommunityHomeGuideHandler
|
||||
@ -38,7 +36,6 @@ import com.gh.gamecenter.common.base.fragment.LazyFragment
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts.IS_DETAIL_PAGE
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.retrofit.ApiResponse
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.view.AvatarBorderView
|
||||
@ -55,8 +52,6 @@ import com.gh.gamecenter.feature.entity.ArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.ForumVideoEntity
|
||||
import com.gh.gamecenter.forum.home.follow.FollowHomeFilterPopWindow
|
||||
import com.gh.gamecenter.forum.home.follow.fragment.FollowHomeFragment
|
||||
import com.gh.gamecenter.forum.home.recommend.PublishImageArticleActivity
|
||||
import com.gh.gamecenter.forum.home.recommend.fragment.ImageArticleHomeFragment
|
||||
import com.gh.gamecenter.forum.search.ForumOrUserSearchActivity
|
||||
import com.gh.gamecenter.login.entity.UserInfoEntity
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
@ -73,7 +68,6 @@ import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
|
||||
import com.halo.assistant.HaloApp
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import splitties.resources.int
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@ -133,7 +127,6 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
override fun getRealLayoutId(): Int {
|
||||
return R.layout.fragment_community_home
|
||||
}
|
||||
@ -142,6 +135,7 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
mBinding = FragmentCommunityHomeBinding.bind(inflatedView)
|
||||
}
|
||||
|
||||
|
||||
override fun onFragmentFirstVisible() {
|
||||
ArticleDetailWebCacheManager.init(requireContext().applicationContext)
|
||||
|
||||
@ -168,8 +162,7 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
|
||||
private fun addHomeVideoGuideHandler() {
|
||||
val decorView = activity?.window?.decorView as? FrameLayout
|
||||
val communityHomeGuideHandler =
|
||||
CommunityHomeGuideHandler(21, requireContext(), decorView, mBinding?.videoLottie)
|
||||
val communityHomeGuideHandler = CommunityHomeGuideHandler(21, requireContext(), decorView, mBinding?.videoLottie)
|
||||
mPriorityChain.addHandler(communityHomeGuideHandler)
|
||||
}
|
||||
|
||||
@ -313,14 +306,14 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
?: FollowHomeFragment()
|
||||
mFragmentList.add(followFragment)
|
||||
|
||||
val recommendFragment = childFragmentManager.findFragmentByTag("$tag$TAB_RECOMMEND_INDEX")
|
||||
?: ImageArticleHomeFragment.newInstance().with(
|
||||
val forumArticleListFragment = childFragmentManager.findFragmentByTag("$tag$TAB_RECOMMEND_INDEX")
|
||||
?: ForumArticleListFragment().with(
|
||||
bundleOf(
|
||||
EntranceConsts.KEY_ENTRANCE to "社区",
|
||||
EntranceConsts.KEY_PATH to "推荐"
|
||||
)
|
||||
)
|
||||
mFragmentList.add(recommendFragment)
|
||||
mFragmentList.add(forumArticleListFragment)
|
||||
|
||||
val forumFragment = childFragmentManager.findFragmentByTag("${tag}$TAB_FORUM_INDEX")
|
||||
?: ForumFragment().with(bundleOf(EntranceConsts.KEY_ENTRANCE to "社区"))
|
||||
@ -341,18 +334,9 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
doOnScroll(
|
||||
onPageSelected = { position ->
|
||||
communityEditBtn.goneIf(position != TAB_RECOMMEND_INDEX && position != TAB_FOLLOW_INDEX)
|
||||
if (position == TAB_RECOMMEND_INDEX) {
|
||||
communityEditBtn.setImageResource(R.drawable.ic_community_float_publish)
|
||||
} else {
|
||||
communityEditBtn.setImageResource(R.drawable.ic_community_float_create)
|
||||
}
|
||||
when (position) {
|
||||
TAB_FOLLOW_INDEX -> {
|
||||
root.setBackgroundColor(
|
||||
com.gh.gamecenter.common.R.color.ui_background.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_background.toColor(requireContext()))
|
||||
topBg.translationY = 0F
|
||||
changeNavigationBg()
|
||||
NewLogUtils.logCommunityHomeEvent("click_for_you_tab")
|
||||
@ -360,11 +344,7 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
|
||||
TAB_RECOMMEND_INDEX -> {
|
||||
root.setBackgroundColor(
|
||||
com.gh.gamecenter.common.R.color.ui_background.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_background.toColor(requireContext()))
|
||||
topBg.translationY = 0F
|
||||
changeNavigationBg()
|
||||
NewLogUtils.logCommunityHomeEvent("click_for_you_tab")
|
||||
@ -372,11 +352,7 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
|
||||
TAB_FORUM_INDEX -> {
|
||||
root.setBackgroundColor(
|
||||
com.gh.gamecenter.common.R.color.ui_surface.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
|
||||
(mFragmentList[2] as ForumFragment).translationY.run {
|
||||
topBg.translationY = -this.toFloat()
|
||||
changeNavigationBg(this)
|
||||
@ -386,11 +362,7 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
|
||||
TAB_ACTIVITY_INDEX -> {
|
||||
root.setBackgroundColor(
|
||||
com.gh.gamecenter.common.R.color.ui_background.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_background.toColor(requireContext()))
|
||||
(mFragmentList[3] as ForumActivityFragment).translationY.run {
|
||||
topBg.translationY = -this.toFloat()
|
||||
changeNavigationBg(this)
|
||||
@ -615,20 +587,6 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
UserRepository.getInstance().loginUserInfo.removeObserver(observer)
|
||||
}
|
||||
|
||||
contentView.findViewById<View>(R.id.community_edit_recommend_container).setOnClickListener {
|
||||
context?.ifLogin("论坛首页-发布-图文动态", action = {
|
||||
showRegulationTestDialogIfNeeded {
|
||||
NewLogUtils.logArticleEditEnter("推荐信息流", "", "")
|
||||
// ARouter不支持 Fragment.startActivityForResult的形式启动页面,这里无奈只能使用原生方法
|
||||
// ARouter.getInstance().build(RouteConsts.activity.publishImageArticleActivity)
|
||||
// .navigation(this, IMAGE_ARTICLE_REQUEST_CODE)
|
||||
val intent = PublishImageArticleActivity.getIntent(requireContext(), "社区推荐Tab")
|
||||
startActivityForResult(intent, IMAGE_ARTICLE_REQUEST_CODE)
|
||||
}
|
||||
dialog.dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
contentView.findViewById<View>(R.id.community_edit_article_container).setOnClickListener {
|
||||
context?.ifLogin("论坛首页-发布-发帖子", action = {
|
||||
showRegulationTestDialogIfNeeded {
|
||||
@ -679,7 +637,6 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun resetFollowTab() {
|
||||
mBinding?.tabLayout?.run {
|
||||
if (selectedTabPosition == TAB_FOLLOW_INDEX) {
|
||||
@ -696,11 +653,6 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
IMAGE_ARTICLE_REQUEST_CODE -> {
|
||||
// 发布图文成功,切换到推荐tab
|
||||
mBinding?.viewPager?.setCurrentItem(TAB_RECOMMEND_INDEX, false)
|
||||
}
|
||||
|
||||
ARTICLE_REQUEST_CODE -> {
|
||||
val articleId = data?.getStringExtra("article_id") ?: return
|
||||
// val communityId = data?.getStringExtra("community_id") ?: return
|
||||
@ -723,13 +675,13 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
|
||||
private fun insertDataToRecommendTab(entity: ArticleEntity) {
|
||||
// 废弃 后续会逐渐将 activityForResult迁移到 launcher
|
||||
(mFragmentList[TAB_RECOMMEND_INDEX] as? ForumArticleListFragment)?.insertDataToFirstIndex(entity)
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
mBinding?.viewPager?.run {
|
||||
if (currentItem == 1) {
|
||||
return (mFragmentList[1] as ImageArticleHomeFragment).onBackPressed()
|
||||
return (mFragmentList[1] as ForumArticleListFragment).onBackPressed()
|
||||
}
|
||||
}
|
||||
return super.onBackPressed()
|
||||
@ -838,11 +790,7 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
}
|
||||
tvTitle.setTextColor(
|
||||
ColorStateList.valueOf(
|
||||
com.gh.gamecenter.common.R.color.text_primary.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -851,9 +799,7 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
mBinding?.run {
|
||||
root.setBackgroundColor(
|
||||
if (viewPager.currentItem == TAB_FORUM_INDEX) com.gh.gamecenter.common.R.color.ui_surface.toColor(
|
||||
requireContext()
|
||||
) else com.gh.gamecenter.common.R.color.ui_background.toColor(
|
||||
if (viewPager.currentItem == TAB_FORUM_INDEX) com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()) else com.gh.gamecenter.common.R.color.ui_background.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
@ -874,12 +820,10 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
searchIconIv.setImageResource(R.drawable.ic_column_search)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
searchIconIv.imageTintList =
|
||||
ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
searchIconIv.imageTintList = ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
}
|
||||
|
||||
val csl =
|
||||
AppCompatResources.getColorStateList(requireContext(), com.gh.gamecenter.common.R.color.text_primary)
|
||||
val csl = AppCompatResources.getColorStateList(requireContext(), com.gh.gamecenter.common.R.color.text_primary)
|
||||
val filter = SimpleColorFilter(csl.defaultColor)
|
||||
val keyPath = KeyPath("**")
|
||||
val callback = LottieValueCallback<ColorFilter>(filter)
|
||||
@ -912,7 +856,6 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
const val ARTICLE_REQUEST_CODE = 200
|
||||
const val QUESTION_REQUEST_CODE = 201
|
||||
const val VIDEO_REQUEST_CODE = 202
|
||||
const val IMAGE_ARTICLE_REQUEST_CODE = 203
|
||||
const val LAST_SELECTED_POSITION = "last_selected_position"
|
||||
const val EB_SHOW_QUESTION_BUTTON = "EB_SHOW_QUESTION_BUTTON"
|
||||
const val EB_HIDE_QUESTION_BUTTON = "EB_HIDE_QUESTION_BUTTON"
|
||||
|
||||
@ -8,7 +8,6 @@ import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.ArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.ForumVideoEntity
|
||||
import com.gh.gamecenter.feature.entity.TimeEntity
|
||||
|
||||
@ -4,10 +4,8 @@ package com.gh.gamecenter.forum.home
|
||||
import android.app.Activity
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.net.Uri
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.view.View
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.DialogUtils
|
||||
@ -19,8 +17,6 @@ import com.gh.gamecenter.ImageViewerActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
import com.gh.gamecenter.common.callback.ConfirmListener
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.entity.AdditionalParamsEntity
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
@ -28,7 +24,6 @@ import com.gh.gamecenter.core.utils.MtaHelper
|
||||
import com.gh.gamecenter.core.utils.SpanBuilder
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.ForumVideoEntity
|
||||
import com.gh.gamecenter.eventbus.EBUserFollow
|
||||
import com.gh.gamecenter.forum.detail.ForumDetailActivity
|
||||
@ -111,14 +106,9 @@ class ForumArticleAskItemViewHolder(
|
||||
else -> R.drawable.icon_forum_fail
|
||||
}
|
||||
)
|
||||
val titleText = if (entity.type.contains("video")) entity.title else entity.questions.title
|
||||
title.goneIf(entity.type == "answer" || titleText.isNullOrEmpty()) {
|
||||
title.text = titleText
|
||||
}
|
||||
val contentText = if (entity.type.contains("video")) entity.des else entity.brief
|
||||
content.goneIf(contentText.isEmpty()) {
|
||||
content.text = contentText
|
||||
}
|
||||
title.goneIf(entity.type == "answer")
|
||||
title.text = if (entity.type.contains("video")) entity.title else entity.questions.title
|
||||
content.text = if (entity.type.contains("video")) entity.des else entity.brief
|
||||
popularAnswerContainer.background = GradientDrawable().apply {
|
||||
setColor(Color.parseColor("#F5F6F7"))
|
||||
cornerRadius = 4F.dip2px().toFloat()
|
||||
@ -148,8 +138,11 @@ class ForumArticleAskItemViewHolder(
|
||||
binding.title.text = SpanBuilder(title).image(0, 1, this).build()
|
||||
}
|
||||
} else {
|
||||
binding.content.visibility = View.VISIBLE
|
||||
if (entity.type == "video") {
|
||||
binding.content.goneIf(entity.des.isEmpty())
|
||||
} else {
|
||||
binding.content.visibility = View.VISIBLE
|
||||
}
|
||||
//若文章内有图片和视频,标题后增加‘有视频’标签 issues-1052
|
||||
if (entity.getPassVideos().isNotEmpty()) {
|
||||
@ -209,7 +202,6 @@ class ForumArticleAskItemViewHolder(
|
||||
"community_article" -> "帖子"
|
||||
"video" -> "视频帖"
|
||||
"question" -> "提问帖"
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> "图文"
|
||||
else -> "提问帖评论"
|
||||
}
|
||||
val userId = user.id ?: ""
|
||||
@ -388,7 +380,6 @@ class ForumArticleAskItemViewHolder(
|
||||
voteCountContainer.visibility = View.GONE
|
||||
}
|
||||
|
||||
forumNameContainer?.visibleIf(entity.community.id.isNotBlank())
|
||||
if (entity.community.type == "official_bbs") {
|
||||
forumIcon?.displayGameIcon(entity.community.icon, null)
|
||||
} else {
|
||||
@ -458,17 +449,15 @@ class ForumArticleAskItemViewHolder(
|
||||
"community_article" -> "帖子"
|
||||
"video" -> "视频帖"
|
||||
"question" -> "提问帖"
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> "图文"
|
||||
else -> "提问帖评论"
|
||||
}
|
||||
val sequence = position + 1
|
||||
val bbsId = entity.community.id
|
||||
val bbsType = entity.community.typeChinese
|
||||
val bbsType = if (entity.community.type == "official_bbs") "综合论坛" else "游戏论坛"
|
||||
val tabInfo = "${path}tab"
|
||||
val commentType = when (entity.type) {
|
||||
"community_article" -> "帖子评论"
|
||||
"video" -> "视频帖评论"
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE ->"图文评论"
|
||||
else -> "提问帖评论"
|
||||
}
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
@ -539,14 +528,6 @@ class ForumArticleAskItemViewHolder(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, entity.id)
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,12 +544,11 @@ class ForumArticleAskItemViewHolder(
|
||||
"community_article" -> "帖子"
|
||||
"video" -> "视频帖"
|
||||
"question" -> "提问帖"
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> "图文"
|
||||
else -> "提问帖评论"
|
||||
}
|
||||
val sequence = position + 1
|
||||
val bbsId = entity.community.id
|
||||
val bbsType = entity.community.typeChinese
|
||||
val bbsType = if (entity.community.type == "official_bbs") "综合论坛" else "游戏论坛"
|
||||
val tabInfo = "${path}tab"
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
"click_forum_detail_like",
|
||||
|
||||
@ -16,7 +16,6 @@ import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.viewholder.FooterViewHolder
|
||||
import com.gh.gamecenter.core.utils.MtaHelper
|
||||
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
|
||||
import com.gh.gamecenter.feature.entity.ArticleEntity
|
||||
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
|
||||
@ -72,10 +71,7 @@ class ForumArticleListAdapter(
|
||||
topMargin = if (position == 0) 8F.dip2px() else 0
|
||||
}
|
||||
if (position == 0) {
|
||||
root.background =
|
||||
com.gh.gamecenter.common.R.drawable.background_shape_white_radius_12_top_only.toDrawable(
|
||||
mContext
|
||||
)
|
||||
root.background = com.gh.gamecenter.common.R.drawable.background_shape_white_radius_12_top_only.toDrawable(mContext)
|
||||
} else {
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(mContext))
|
||||
}
|
||||
@ -102,7 +98,6 @@ class ForumArticleListAdapter(
|
||||
"community_article" -> "帖子"
|
||||
"video" -> "视频帖"
|
||||
"question" -> "提问帖"
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> "图文"
|
||||
else -> "提问帖评论"
|
||||
}
|
||||
val bbsType = if (community.type == "official_bbs") "综合论坛" else "游戏论坛"
|
||||
@ -141,7 +136,6 @@ class ForumArticleListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"video" -> {
|
||||
MtaHelper.onEvent(
|
||||
"论坛首页",
|
||||
@ -163,7 +157,6 @@ class ForumArticleListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"question" -> {
|
||||
MtaHelper.onEvent(
|
||||
"论坛首页",
|
||||
@ -187,7 +180,6 @@ class ForumArticleListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"answer" -> {
|
||||
MtaHelper.onEvent(
|
||||
"论坛首页",
|
||||
@ -221,12 +213,7 @@ class ForumArticleListAdapter(
|
||||
footerViewHolder.initItemPadding()
|
||||
footerViewHolder.initFooterViewHolder(viewModel, mIsLoading, mIsNetworkError, mIsOver)
|
||||
footerViewHolder.hint.textSize = 12f
|
||||
footerViewHolder.hint.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
mContext,
|
||||
com.gh.gamecenter.common.R.color.aaaaaa
|
||||
)
|
||||
)
|
||||
footerViewHolder.hint.setTextColor(ContextCompat.getColor(mContext, com.gh.gamecenter.common.R.color.aaaaaa))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,19 +2,14 @@ package com.gh.gamecenter.forum.home.follow
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.ActivityResultRegistry
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.activity.result.contract.ActivityResultContracts.GetContent
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.common.util.SyncDataBetweenPageHelper
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity
|
||||
import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
import com.gh.gamecenter.feature.entity.ArticleEntity
|
||||
@ -240,15 +235,6 @@ class FollowActivityResultLauncher(
|
||||
questionsDetailLauncher.launch(LauncherDestination(position, historyEntity = entity))
|
||||
}
|
||||
|
||||
entity.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, entity.id)
|
||||
.appendQueryParameter(EntranceConsts.KEY_SOURCE_ENTRANCE, "关注-个人动态")
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
}
|
||||
|
||||
else -> {
|
||||
commentEntityLauncher.launch(LauncherDestination(position, historyEntity = entity))
|
||||
}
|
||||
@ -272,14 +258,6 @@ class FollowActivityResultLauncher(
|
||||
"answer" -> {
|
||||
questionsDetailLauncher.launch(LauncherDestination(position, answerEntity = answerEntity))
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_SOURCE_ENTRANCE, "关注-论坛动态")
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
package com.gh.gamecenter.forum.home.follow
|
||||
|
||||
import com.gh.gamecenter.entity.HistoryGameEntity
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity
|
||||
import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
import com.gh.gamecenter.feature.entity.Count
|
||||
import com.gh.gamecenter.feature.entity.MeEntity
|
||||
|
||||
abstract class FollowDynamicItem {
|
||||
|
||||
@ -20,14 +19,6 @@ abstract class FollowDynamicItem {
|
||||
|
||||
protected open fun doAreContentsTheSame(other: FollowDynamicItem) = this == other
|
||||
|
||||
open val id = ""
|
||||
|
||||
open val type = ""
|
||||
|
||||
open var count: Count = Count()
|
||||
|
||||
open val me = MeEntity()
|
||||
|
||||
companion object {
|
||||
|
||||
const val FOLLOW_DYNAMIC_ITEM_TYPE_FOOTER = -1
|
||||
@ -48,21 +39,6 @@ data class FollowDynamicPersonalItem(
|
||||
&& data.id == other.data.id
|
||||
}
|
||||
|
||||
override val id: String
|
||||
get() = data.id
|
||||
|
||||
override val type: String
|
||||
get() = data.type
|
||||
|
||||
override var count: Count
|
||||
get() = data.count
|
||||
set(value) {
|
||||
data.count = value
|
||||
}
|
||||
|
||||
override val me: MeEntity
|
||||
get() = data.me
|
||||
|
||||
}
|
||||
|
||||
data class FollowDynamicBbsItem(
|
||||
@ -77,20 +53,6 @@ data class FollowDynamicBbsItem(
|
||||
&& data.id == other.data.id
|
||||
}
|
||||
|
||||
override val id: String
|
||||
get() = data.id
|
||||
|
||||
override val type: String
|
||||
get() = data.type
|
||||
|
||||
override var count: Count
|
||||
get() = data.count
|
||||
set(value) {
|
||||
data.count = value
|
||||
}
|
||||
|
||||
override val me: MeEntity
|
||||
get() = data.me
|
||||
}
|
||||
|
||||
object FollowDynamicFooterItem : FollowDynamicItem() {
|
||||
|
||||
@ -28,6 +28,8 @@ import com.gh.gamecenter.forum.home.follow.FollowDynamicPersonalItem
|
||||
import com.gh.gamecenter.forum.home.follow.viewholder.FollowFooterViewHolder
|
||||
import com.gh.gamecenter.forum.home.follow.viewholder.FollowInvalidViewHolder
|
||||
import com.gh.gamecenter.forum.home.follow.viewmodel.FollowDynamicListViewModel
|
||||
import com.gh.gamecenter.forum.home.follow.viewmodel.FollowDynamicViewModel
|
||||
import com.gh.gamecenter.forum.search.CommunitySearchEventListener
|
||||
import com.gh.gamecenter.personalhome.PersonalItemViewHolder
|
||||
|
||||
class FollowDynamicAdapter(
|
||||
|
||||
@ -3,8 +3,11 @@ package com.gh.gamecenter.forum.home.follow.fragment
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.children
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
@ -13,29 +16,23 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.BaseFragment
|
||||
import com.gh.gamecenter.common.base.fragment.ToolbarFragment
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.FragmentFollowDynamicListBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.feature.entity.ForumVideoEntity
|
||||
import com.gh.gamecenter.forum.detail.ForumDetailActivity
|
||||
import com.gh.gamecenter.forum.home.follow.FollowActivityResultLauncher
|
||||
import com.gh.gamecenter.forum.home.follow.FollowDynamicBbsItem
|
||||
import com.gh.gamecenter.forum.home.follow.FollowDynamicItem
|
||||
import com.gh.gamecenter.forum.home.follow.FollowDynamicPersonalItem
|
||||
import com.gh.gamecenter.forum.home.follow.adapter.FollowDynamicAdapter
|
||||
import com.gh.gamecenter.forum.home.follow.viewmodel.FollowDynamicListViewModel
|
||||
import com.gh.gamecenter.forum.home.follow.viewmodel.FollowDynamicViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.gh.gamecenter.personalhome.home.UserHistoryAdapter.Companion.USER_HISTORY_PAYLOADS_VOTE_CHANGED
|
||||
import com.gh.gamecenter.qa.BbsType
|
||||
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
|
||||
import com.gh.gamecenter.qa.entity.QuestionsDetailEntity
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class FollowDynamicListFragment : BaseFragment<Unit>() {
|
||||
|
||||
@ -270,99 +267,10 @@ class FollowDynamicListFragment : BaseFragment<Unit>() {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
when (changed) {
|
||||
is EBImageArticleChanged.VoteChanged -> {
|
||||
updateImageArticleItem(changed.id, true) {
|
||||
it.id
|
||||
val newCount = it.count
|
||||
newCount.vote = changed.count
|
||||
it.count = newCount
|
||||
it.me.isCommunityArticleVote = changed.isVoted
|
||||
it.me.isVoted = changed.isVoted
|
||||
it.count = newCount
|
||||
}
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.CommentChanged -> {
|
||||
updateImageArticleItem(changed.id, true) {
|
||||
val newCount = it.count
|
||||
newCount.comment = changed.count
|
||||
it.count = newCount
|
||||
}
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataDeleted -> {
|
||||
viewModel.deleteImageArticle(changed.imageArticleId)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataChanged -> {
|
||||
val imageArticle = changed.data
|
||||
updateImageArticleItem(changed.data.id, false) {
|
||||
when (it) {
|
||||
is FollowDynamicPersonalItem -> {
|
||||
it.data.title = imageArticle.title
|
||||
it.data.brief = imageArticle.content
|
||||
it.data.images = imageArticle.images
|
||||
it.data.imagesInfo = imageArticle.imagesInfos
|
||||
it.data.community = imageArticle.community?.toCommunityEntity() ?: CommunityEntity()
|
||||
it.data.sections = imageArticle.sections
|
||||
it.count = imageArticle.count
|
||||
it.data.user = imageArticle.user
|
||||
it.data.time = imageArticle.time.update
|
||||
it.data.status = imageArticle.status
|
||||
}
|
||||
|
||||
is FollowDynamicBbsItem -> {
|
||||
it.data.title = imageArticle.title
|
||||
it.data.brief = imageArticle.content
|
||||
it.data.images = imageArticle.images
|
||||
it.data.imagesInfo = imageArticle.imagesInfos
|
||||
it.data.community = imageArticle.community?.toCommunityEntity() ?: CommunityEntity()
|
||||
it.data.sections = imageArticle.sections
|
||||
it.count = imageArticle.count
|
||||
it.data.user = imageArticle.user
|
||||
it.data.time = imageArticle.time.update
|
||||
it.data.status = imageArticle.status
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateImageArticleItem(
|
||||
id: String,
|
||||
hasPayload: Boolean,
|
||||
block: (FollowDynamicItem) -> Unit
|
||||
) {
|
||||
val dataList = adapter.currentList
|
||||
val position =
|
||||
dataList.indexOfFirst {
|
||||
it.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE && it.id == id
|
||||
}
|
||||
if (position != -1) {
|
||||
val item = dataList[position]
|
||||
block(item)
|
||||
if (hasPayload) {
|
||||
adapter.notifyItemChanged(position, USER_HISTORY_PAYLOADS_VOTE_CHANGED)
|
||||
} else {
|
||||
adapter.notifyItemChanged(position)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
context?.let {
|
||||
binding.vHeaderBackground.background =
|
||||
com.gh.gamecenter.common.R.drawable.background_shape_white_radius_8_top_only.toDrawable(it)
|
||||
binding.vHeaderBackground.background = com.gh.gamecenter.common.R.drawable.background_shape_white_radius_8_top_only.toDrawable(it)
|
||||
}
|
||||
binding.rvDynamic.tryToClearRecycler()
|
||||
binding.rvDynamic.recycledViewPool.clear()
|
||||
|
||||
@ -35,7 +35,6 @@ import com.gh.gamecenter.core.provider.IVisitManagerProvider
|
||||
import com.gh.gamecenter.core.utils.MD5Utils
|
||||
import com.gh.gamecenter.databinding.FragmentFollowHomeBinding
|
||||
import com.gh.gamecenter.entity.FollowUserEntity
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.eventbus.EBUserFollow
|
||||
import com.gh.gamecenter.feature.provider.IMessageDetailProvider
|
||||
import com.gh.gamecenter.forum.home.CommunityHomeFragment
|
||||
@ -70,7 +69,6 @@ class FollowHomeFragment : LazyFragment(), IScrollable {
|
||||
ownerProducer = { requireParentFragment() }
|
||||
)
|
||||
|
||||
|
||||
private lateinit var userViewModel: UserViewModel
|
||||
|
||||
private var userId: String? = null
|
||||
@ -456,30 +454,6 @@ class FollowHomeFragment : LazyFragment(), IScrollable {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
when (changed) {
|
||||
is EBImageArticleChanged.VoteChanged -> {
|
||||
viewModel.voteChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.CommentChanged ->{
|
||||
viewModel.commentChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataChanged -> {
|
||||
viewModel.itemChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataDeleted -> {
|
||||
viewModel.itemDeleted(changed)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mScrollCalculatorHelper?.currentPlayer?.release()
|
||||
|
||||
@ -7,7 +7,6 @@ import com.gh.gamecenter.core.utils.UrlFilterUtils
|
||||
import com.gh.gamecenter.entity.FollowCommonContentCollection
|
||||
import com.gh.gamecenter.entity.FollowDynamicEntity
|
||||
import com.gh.gamecenter.entity.FollowDynamicEntity.Companion.FOLLOW_UPDATE_TYPE_ARTICLE
|
||||
import com.gh.gamecenter.entity.FollowDynamicEntity.Companion.FOLLOW_UPDATE_TYPE_IMAGE_ARTICLE
|
||||
import com.gh.gamecenter.entity.FollowDynamicEntity.Companion.FOLLOW_UPDATE_TYPE_LIBAO
|
||||
import com.gh.gamecenter.entity.FollowDynamicEntity.Companion.FOLLOW_UPDATE_TYPE_LIBAO_EXCHANGE
|
||||
import com.gh.gamecenter.entity.FollowDynamicEntity.Companion.FOLLOW_UPDATE_TYPE_USER_POST
|
||||
|
||||
@ -2,17 +2,12 @@ package com.gh.gamecenter.forum.home.follow.viewholder
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.ArticleEntity
|
||||
import com.gh.gamecenter.forum.home.ForumArticleAskItemViewHolder
|
||||
import com.gh.gamecenter.forum.search.CommunitySearchEventListener
|
||||
@ -34,13 +29,13 @@ class FollowPostCardViewHolder(
|
||||
|
||||
fun bind(data: ArticleEntity, position: Int) {
|
||||
val articleEntity = data
|
||||
|
||||
viewHolder.binding.run {
|
||||
root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
topMargin = if (position == 0) 8F.dip2px() else 0
|
||||
}
|
||||
if (position == 0) {
|
||||
root.background =
|
||||
com.gh.gamecenter.common.R.drawable.background_shape_white_radius_12_top_only.toDrawable(context)
|
||||
root.background = com.gh.gamecenter.common.R.drawable.background_shape_white_radius_12_top_only.toDrawable(context)
|
||||
} else {
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(context))
|
||||
}
|
||||
@ -123,15 +118,6 @@ class FollowPostCardViewHolder(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, articleEntity.id)
|
||||
.appendQueryParameter(EntranceConsts.KEY_SOURCE_ENTRANCE, "社区-关注")
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.gamecenter.forum.home.follow.viewmodel
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
@ -7,7 +8,6 @@ import com.gh.common.util.ErrorHelper
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.observableToMain
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity
|
||||
import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
import com.gh.gamecenter.forum.home.follow.FollowDynamicItem
|
||||
@ -119,15 +119,5 @@ class FollowDynamicListViewModel : ViewModel() {
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
fun deleteImageArticle(imageArticleId: String) {
|
||||
val oldData = dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val hasRemoved =
|
||||
newData.removeAll { it.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE && it.id == imageArticleId }
|
||||
if (hasRemoved) {
|
||||
_dataList.value = newData
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -8,7 +8,6 @@ import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.common.util.CheckLoginUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.retrofit.JSONObjectResponse
|
||||
@ -17,8 +16,6 @@ import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.observableToMain
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.entity.FollowUserEntity
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.eventbus.EBUserFollow
|
||||
import com.gh.gamecenter.feature.entity.*
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
@ -315,71 +312,5 @@ class FollowHomeViewModel(application: Application) : AndroidViewModel(applicati
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
fun voteChanged(changed: EBImageArticleChanged.VoteChanged) {
|
||||
notifyImageArticleItemChanged(changed.id) {
|
||||
FollowPostCardItem(
|
||||
data = it.copy(
|
||||
_me = it.me.copy(isCommunityArticleVote = changed.isVoted),
|
||||
_count = it.count.copy(vote = changed.count)
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun commentChanged(changed: EBImageArticleChanged.CommentChanged) {
|
||||
notifyImageArticleItemChanged(changed.id) {
|
||||
FollowPostCardItem(
|
||||
data = it.copy(
|
||||
_count = it.count.copy(comment = changed.count)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun itemChanged(changed: EBImageArticleChanged.DataChanged) {
|
||||
val imageArticle = changed.data
|
||||
notifyImageArticleItemChanged(imageArticle.id) { _ ->
|
||||
val newArticle = ArticleEntity(
|
||||
_id = imageArticle.id,
|
||||
_title = imageArticle.title,
|
||||
content = imageArticle.content,
|
||||
_count = imageArticle.count,
|
||||
time = imageArticle.time,
|
||||
_images = imageArticle.images,
|
||||
imagesInfo = imageArticle.imagesInfos,
|
||||
_user = imageArticle.user,
|
||||
_community = imageArticle.community?.toCommunityEntity() ?: CommunityEntity()
|
||||
)
|
||||
FollowPostCardItem(newArticle)
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyImageArticleItemChanged(
|
||||
imageArticleId: String,
|
||||
block: (ArticleEntity) -> FollowPostCardItem
|
||||
) {
|
||||
val oldData = dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val position = newData.indexOfFirst {
|
||||
it is FollowPostCardItem && it.data.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE && it.data.id == imageArticleId
|
||||
}
|
||||
if (position != -1) {
|
||||
val oldImageArticle = (newData[position] as FollowPostCardItem).data
|
||||
val newItem = block(oldImageArticle)
|
||||
newData[position] = newItem
|
||||
_dataList.value = newData
|
||||
}
|
||||
}
|
||||
|
||||
fun itemDeleted(changed: EBImageArticleChanged.DataDeleted) {
|
||||
val oldData = dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val position = newData.indexOfFirst {
|
||||
it is FollowPostCardItem && it.data.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE && it.data.id == changed.imageArticleId
|
||||
}
|
||||
if (position != -1) {
|
||||
newData.removeAt(position)
|
||||
_dataList.value = newData
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend
|
||||
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import com.alibaba.android.arouter.facade.annotation.Autowired
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.forum.home.recommend.fragment.ImageArticleDetailFragment
|
||||
|
||||
@Route(path = RouteConsts.activity.imageArticleDetailActivity)
|
||||
class ImageArticleDetailActivity : BaseActivity() {
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_IMAGE_ARTICLE_ID, desc = "图文 id", required = true)
|
||||
var imageArticleId = ""
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_TOP_COMMENT_ID, desc = "置顶评论 id", required = false)
|
||||
var topCommentId: String? = null
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_SCROLL_TO_COMMENT_AREA, desc = "是否需要自动滚动到评论区域", required = false)
|
||||
var scrollToCommentArea: Boolean = false
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_SOURCE_ENTRANCE, desc = "来源入口", required = false)
|
||||
var sourceEntrance: String = ""
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_RECOMMEND_ID, desc = "推荐 id", required = false)
|
||||
var recommendId: String = ""
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return com.gh.gamecenter.common.R.layout.activity_image_article_detail
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
ARouter.getInstance().inject(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
DisplayUtils.setLightStatusBar(this, true)
|
||||
setStatusBarColor(Color.TRANSPARENT)
|
||||
|
||||
val tag = ImageArticleDetailFragment::class.java.toString()
|
||||
val fragment =
|
||||
supportFragmentManager.findFragmentByTag(tag) ?: ImageArticleDetailFragment().apply {
|
||||
arguments = intent.extras
|
||||
}
|
||||
val transaction = supportFragmentManager.beginTransaction()
|
||||
transaction.replace(R.id.layout_activity_content, fragment, tag)
|
||||
transaction.commitAllowingStateLoss()
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,154 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil.ItemCallback
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.NO_POSITION
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.baselist.PageLoader
|
||||
import com.gh.gamecenter.common.databinding.RefreshFooterviewBinding
|
||||
import com.gh.gamecenter.forum.home.follow.viewholder.FollowFooterViewHolder
|
||||
|
||||
abstract class ImageArticleFooterWrapperAdapter<T, VH : ViewHolder>(diffCallback: ItemCallback<T>) :
|
||||
ListAdapter<T, ViewHolder>(diffCallback) {
|
||||
|
||||
private var pageState: PageLoader.PageState? = null
|
||||
|
||||
private var _recyclerView: RecyclerView? = null
|
||||
|
||||
val dataCount: Int
|
||||
get() = super.getItemCount()
|
||||
|
||||
fun setPageState(pageState: PageLoader.PageState) {
|
||||
this.pageState = pageState
|
||||
_recyclerView?.post {
|
||||
notifyItemChanged(itemCount - 1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return if (dataCount > 0) dataCount + 1 else dataCount
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return if (position < dataCount) ITEM_TYPE_DATA else ITEM_TYPE_FOOTER
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
return if (viewType == ITEM_TYPE_DATA) {
|
||||
onCreateDataViewHolder(parent)
|
||||
} else {
|
||||
onCreateFooterViewHolder(parent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
if (holder.itemViewType == ITEM_TYPE_FOOTER) {
|
||||
onBindFooterViewHolder(holder)
|
||||
} else {
|
||||
onBindDataViewHolder(holder as VH, position)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||
if (payloads.isEmpty()) {
|
||||
onBindViewHolder(holder, position)
|
||||
} else {
|
||||
if (holder.itemViewType != ITEM_TYPE_FOOTER) {
|
||||
onBindDataViewHolder(holder as VH, position, payloads)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun onBindFooterViewHolder(holder: ViewHolder) {
|
||||
if (holder is FollowFooterViewHolder) {
|
||||
holder.initFooterViewHolder(
|
||||
pageState == PageLoader.PageState.PageLoadMoreLoading,
|
||||
pageState == PageLoader.PageState.PageLoadMoreFailure,
|
||||
pageState == PageLoader.PageState.PageLoadCompleted,
|
||||
R.string.load_over_with_click_hint
|
||||
) {
|
||||
if (pageState == PageLoader.PageState.PageLoadCompleted) {
|
||||
_recyclerView?.scrollToPosition(0)
|
||||
} else if (pageState == PageLoader.PageState.PageLoadMoreFailure) {
|
||||
pageState = PageLoader.PageState.PageLoadMoreLoading
|
||||
loadMore()
|
||||
notifyItemChanged(itemCount - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun onCreateDataViewHolder(parent: ViewGroup): VH
|
||||
|
||||
|
||||
open fun onCreateFooterViewHolder(parent: ViewGroup): ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val binding = RefreshFooterviewBinding.inflate(inflater, parent, false)
|
||||
val viewHolder = FollowFooterViewHolder(binding)
|
||||
val layoutParams = binding.root.layoutParams
|
||||
if (layoutParams is StaggeredGridLayoutManager.LayoutParams) {
|
||||
layoutParams.isFullSpan = true
|
||||
binding.root.layoutParams = layoutParams
|
||||
}
|
||||
return viewHolder
|
||||
}
|
||||
|
||||
abstract fun onBindDataViewHolder(holder: VH, position: Int)
|
||||
|
||||
open fun onBindDataViewHolder(holder: VH, position: Int, payloads: MutableList<Any>) {
|
||||
onBindDataViewHolder(holder, position)
|
||||
}
|
||||
|
||||
abstract fun loadMore()
|
||||
|
||||
private val onLoadMoreListener = object : RecyclerView.OnScrollListener() {
|
||||
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
if (dy != 0) {
|
||||
refreshIfNeed(recyclerView)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
refreshIfNeed(recyclerView)
|
||||
}
|
||||
|
||||
private fun refreshIfNeed(recyclerView: RecyclerView) {
|
||||
val layoutManger = recyclerView.layoutManager
|
||||
if (layoutManger is StaggeredGridLayoutManager) {
|
||||
val lastVisibleItemPositions = IntArray(2)
|
||||
layoutManger.findLastVisibleItemPositions(lastVisibleItemPositions)
|
||||
val lastVisibleItemPosition = lastVisibleItemPositions.maxOrNull() ?: NO_POSITION
|
||||
if (lastVisibleItemPosition >= itemCount - 3 // 提前两个开始加载下一页
|
||||
&& pageState is PageLoader.PageState.PageLoadMoreReady
|
||||
) {
|
||||
pageState = PageLoader.PageState.PageLoadMoreLoading
|
||||
loadMore()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
|
||||
_recyclerView = recyclerView
|
||||
recyclerView.addOnScrollListener(onLoadMoreListener)
|
||||
}
|
||||
|
||||
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
|
||||
recyclerView.removeOnScrollListener(onLoadMoreListener)
|
||||
_recyclerView = null
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val ITEM_TYPE_DATA = 0
|
||||
const val ITEM_TYPE_FOOTER = 101
|
||||
}
|
||||
}
|
||||
@ -1,241 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend
|
||||
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.utils.UploadImageUtils
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity
|
||||
import com.gh.gamecenter.entity.PublishImageTextRequest
|
||||
import com.gh.gamecenter.entity.VoteEntity
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageAndTextAdapter
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.retrofit.service.ApiService
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.zhihu.matisse.internal.utils.PathUtils
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.ResponseBody
|
||||
|
||||
class ImageArticleRepository private constructor(
|
||||
private val api: ApiService,
|
||||
private val newApi: ApiService
|
||||
) {
|
||||
|
||||
|
||||
fun loadRecommends(page: Int): Single<List<ImageArticleEntity>> {
|
||||
val version = BuildConfig.VERSION_NAME
|
||||
val channel = HaloApp.getInstance().channel
|
||||
return api.loadImageArticleRecommends(IMAGE_ARTICLE_SORT, page, version, channel)
|
||||
}
|
||||
|
||||
|
||||
fun isShowDragTips() =
|
||||
Single.create<Boolean> {
|
||||
val hasShow = SPUtils.getBoolean(Constants.SP_HAS_SHOW_IMAGE_AND_TEXT_DRAG_TIPS)
|
||||
it.onSuccess(!hasShow)
|
||||
}
|
||||
|
||||
fun saveHasShowDragTips() {
|
||||
SPUtils.setBoolean(Constants.SP_HAS_SHOW_IMAGE_AND_TEXT_DRAG_TIPS, true)
|
||||
}
|
||||
|
||||
fun checkHasSections(bbsId: String) =
|
||||
newApi.getForumSections(bbsId)
|
||||
.map {
|
||||
it.size > 0
|
||||
}
|
||||
|
||||
fun getModeratorsInfo(bbsId: String) =
|
||||
api.getModeratorsInfo(bbsId)
|
||||
.map {
|
||||
it["is_moderators"].asBoolean
|
||||
}
|
||||
|
||||
fun createOrEditDraft(
|
||||
request: PublishImageTextRequest,
|
||||
localImages: List<ImageAndTextAdapter.LocalImage>
|
||||
): Single<ResponseBody> {
|
||||
// 需要先上传本地图片
|
||||
val userId = UserManager.getInstance().userId
|
||||
return updatePic(localImages)
|
||||
.observeOn(Schedulers.io())
|
||||
.flatMap {
|
||||
request.images = it
|
||||
if (request.draftId.isNotBlank()) {
|
||||
// 编辑草稿
|
||||
api.editImageArticleDrafts(userId, request.draftId, request)
|
||||
.toSingleDefault(ResponseBody.create(MediaType.parse("application/json"), "{}"))
|
||||
} else {
|
||||
api.createImageArticleDrafts(userId, request)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun publishImageText(
|
||||
request: PublishImageTextRequest,
|
||||
localImages: List<ImageAndTextAdapter.LocalImage>
|
||||
): Single<ImageArticleEntity> {
|
||||
return updatePic(localImages)
|
||||
.observeOn(Schedulers.io())
|
||||
.flatMap {
|
||||
request.images = it
|
||||
api.publishImageText(request)
|
||||
.flatMap {
|
||||
val view = "detail"
|
||||
val versionName = BuildConfig.VERSION_NAME
|
||||
val channel = HaloApp.getInstance().channel
|
||||
api.loadImageArticleDetail(it["_id"].asString, view, versionName, channel)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun editImageArticle(
|
||||
id: String,
|
||||
request: PublishImageTextRequest,
|
||||
images: List<ImageAndTextAdapter.LocalImage>
|
||||
): Single<ImageArticleEntity> {
|
||||
return updatePic(images)
|
||||
.observeOn(Schedulers.io())
|
||||
.flatMap {
|
||||
request.images = it
|
||||
api.editImageArticle(id, request)
|
||||
.toSingleDefault(id)
|
||||
.flatMap {
|
||||
val view = "detail"
|
||||
val versionName = BuildConfig.VERSION_NAME
|
||||
val channel = HaloApp.getInstance().channel
|
||||
api.loadImageArticleDetail(it, view, versionName, channel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun loadDraft(): Single<List<ImageArticleEntity>> {
|
||||
val userId = UserManager.getInstance().userId
|
||||
val versionName = BuildConfig.VERSION_NAME
|
||||
val channel = HaloApp.getInstance().channel
|
||||
return api.loadImageTextDrafts(userId, versionName, channel)
|
||||
}
|
||||
|
||||
fun deleteDraft(draftId: String): Completable {
|
||||
val userId = UserManager.getInstance().userId
|
||||
return api.deleteImageArticleDraft(userId, draftId)
|
||||
}
|
||||
|
||||
fun loadImageArticleDetail(imageArticleId: String): Single<ImageArticleEntity> {
|
||||
val view = "detail"
|
||||
return api.loadImageArticleDetail(imageArticleId, view, BuildConfig.VERSION_NAME, HaloApp.getInstance().channel)
|
||||
|
||||
}
|
||||
|
||||
fun loadMyImageArticleList(page: Int): Observable<List<PersonalHistoryEntity>> {
|
||||
val userId = UserManager.getInstance().userId
|
||||
val version = BuildConfig.VERSION_NAME
|
||||
val channel = HaloApp.getInstance().channel
|
||||
return api.getPersonalHistory(userId, page, channel, IMAGE_ARTICLE_FILTER)
|
||||
}
|
||||
|
||||
private fun updatePic(localImages: List<ImageAndTextAdapter.LocalImage>): Single<List<String>> =
|
||||
Single.create {
|
||||
// 已上传的图片
|
||||
val urls = localImages.mapNotNull { image -> image.url }
|
||||
val uris = localImages.mapNotNull { image -> image.uri }
|
||||
if (uris.isEmpty()) {
|
||||
it.onSuccess(urls)
|
||||
return@create
|
||||
}
|
||||
// 需要上传的图片
|
||||
val localPaths = uris.map { uri -> PathUtils.getPath(HaloApp.getInstance(), uri) }
|
||||
UploadImageUtils.compressAndUploadImageList(
|
||||
UploadImageUtils.UploadType.community_article,
|
||||
localPaths,
|
||||
false,
|
||||
object : UploadImageUtils.OnUploadImageListListener {
|
||||
override fun onSuccess(
|
||||
imageUrlMap: LinkedHashMap<String, String>,
|
||||
errorMap: Map<String, Exception>
|
||||
) {
|
||||
val finalUrls = urls + imageUrlMap.values
|
||||
it.onSuccess(finalUrls)
|
||||
}
|
||||
|
||||
override fun onSingleSuccess(imageUrlMap: Map<String, String>) = Unit
|
||||
|
||||
override fun onError(errorMap: Map<String, Exception>) {
|
||||
// 图片上传失败,忽略
|
||||
|
||||
}
|
||||
|
||||
override fun onProgress(total: Long, progress: Long) = Unit
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
fun getSingleCommentById(commentId: String): Single<CommentEntity> {
|
||||
return api.getImageArticleCommentDetail(
|
||||
commentId,
|
||||
BuildConfig.VERSION_NAME,
|
||||
HaloApp.getInstance().channel,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
}
|
||||
|
||||
fun followBbs(communityId: String, isFollow: Boolean) =
|
||||
if (isFollow) {
|
||||
api.followForum(communityId)
|
||||
} else {
|
||||
api.unFollowForum(communityId)
|
||||
}
|
||||
|
||||
fun collect(imageArticleId: String, isCollected: Boolean) =
|
||||
if (isCollected) {
|
||||
api.collectImageArticle(imageArticleId)
|
||||
.flatMapCompletable {
|
||||
Completable.complete()
|
||||
}
|
||||
} else {
|
||||
api.cancelImageArticleCollection(imageArticleId)
|
||||
}
|
||||
|
||||
fun voteImageArticle(imageArticleId: String, vote: Boolean): Single<VoteEntity> = if (vote) {
|
||||
api.voteArticleImage(imageArticleId)
|
||||
} else {
|
||||
api.unVoteArticleImage(imageArticleId)
|
||||
}
|
||||
|
||||
fun applyHighlightForImageArticle(imageArticleId: String): Completable =
|
||||
api.applyHighlightForImageArticle(imageArticleId)
|
||||
|
||||
fun addHighlight(isAdd: Boolean, imageArticleId: String) =
|
||||
if (isAdd) {
|
||||
api.addHighlightForImageArticle(imageArticleId)
|
||||
} else {
|
||||
api.cancelHighlightForImageArticle(imageArticleId)
|
||||
}
|
||||
|
||||
fun deleteOrHideImageArticle(imageArticleId: String) =
|
||||
api.deleteOrHideImageArticle(imageArticleId)
|
||||
|
||||
fun followUser(follow: Boolean, userId: String) =
|
||||
if (follow) {
|
||||
api.postFollowing(userId)
|
||||
} else {
|
||||
api.deleteFollowing(userId)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val IMAGE_ARTICLE_FILTER = "scene:question_answer,type:image_article"
|
||||
private const val IMAGE_ARTICLE_SORT = "time.comment:-1"
|
||||
|
||||
fun newInstance() =
|
||||
ImageArticleRepository(RetrofitManager.getInstance().api, RetrofitManager.getInstance().newApi)
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend
|
||||
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.ToolbarFragment
|
||||
|
||||
class ImageArticleRequestPermissionFragment : ToolbarFragment() {
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return R.layout.fragment_image_article_request_permission
|
||||
}
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend
|
||||
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.VoteEntity
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
class ImageArticleUseCase(
|
||||
private val repository: ImageArticleRepository,
|
||||
private val compositeDisposable: CompositeDisposable
|
||||
) {
|
||||
|
||||
fun voteImageArticle(imageArticleId: String, isVote: Boolean) {
|
||||
repository.voteImageArticle(imageArticleId, isVote)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<VoteEntity>() {
|
||||
override fun onSuccess(data: VoteEntity) {
|
||||
notifyVoteChanged(imageArticleId, isVote, data.vote)
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
|
||||
fun notifyVoteChanged(id: String, isVoted: Boolean, count: Int) {
|
||||
EventBus.getDefault().post(EBImageArticleChanged.VoteChanged(id, isVoted, count))
|
||||
}
|
||||
|
||||
fun notifyCommentChanged(id: String, count: Int) {
|
||||
EventBus.getDefault().post(EBImageArticleChanged.CommentChanged(id, count))
|
||||
}
|
||||
|
||||
fun notifyDataDeleted(id: String) {
|
||||
EventBus.getDefault().post(EBImageArticleChanged.DataDeleted(id))
|
||||
}
|
||||
|
||||
fun notifyDataCreated(data: ImageArticleEntity, draftId: String = "") {
|
||||
EventBus.getDefault().post(EBImageArticleChanged.DataCreated(data, draftId))
|
||||
}
|
||||
|
||||
fun notifyDataEdited(data: ImageArticleEntity) {
|
||||
EventBus.getDefault().post(EBImageArticleChanged.DataChanged(data))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,209 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.activity.result.ActivityResultCallback
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.activity.viewModels
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.alibaba.android.arouter.facade.annotation.Autowired
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.utils.PermissionHelper
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.feature.selector.ChooseType
|
||||
import com.gh.gamecenter.feature.selector.LocalMediaActivity
|
||||
import com.gh.gamecenter.forum.home.CommunityHomeFragment.Companion.IMAGE_ARTICLE_REQUEST_CODE
|
||||
import com.gh.gamecenter.forum.home.recommend.fragment.ImageArticleDraftFragment
|
||||
import com.gh.gamecenter.forum.home.recommend.fragment.PublishImageArticleFragment
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.PublishImageArticleActivityViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.zhihu.matisse.Matisse
|
||||
|
||||
@Route(path = RouteConsts.activity.publishImageArticleActivity)
|
||||
class PublishImageArticleActivity : BaseActivity() {
|
||||
|
||||
private val viewModel by viewModels<PublishImageArticleActivityViewModel>()
|
||||
|
||||
private lateinit var chooseImageLauncher: ActivityResultLauncher<Int>
|
||||
|
||||
private var isFirstEnter = true
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_IMAGE_ARTICLE_ENTITY, desc = "编辑图文实体", required = false)
|
||||
var imageArticleEntity: ImageArticleEntity? = null
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_COMMUNITY_DATA, desc = "绑定的社区实体", required = false)
|
||||
var communityEntity: CommunityEntity? = null
|
||||
|
||||
private lateinit var tvTitle: TextView
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return R.layout.activity_publish_image_article
|
||||
}
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
ARouter.getInstance().inject(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
DisplayUtils.setLightStatusBar(this, true)
|
||||
setStatusBarColor(Color.TRANSPARENT)
|
||||
|
||||
tvTitle = findViewById(R.id.tv_title)
|
||||
val ivBack = findViewById<ImageView>(R.id.iv_back)
|
||||
ivBack.setOnClickListener {
|
||||
val fragment = supportFragmentManager.fragments.lastOrNull()
|
||||
if(fragment is PublishImageArticleFragment){
|
||||
SensorsBridge.trackEvent("ArticleCancelclick")
|
||||
}
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
supportFragmentManager.addOnBackStackChangedListener {
|
||||
val fragment = supportFragmentManager.fragments.lastOrNull()
|
||||
val titleResId = if (fragment is ImageArticleDraftFragment) {
|
||||
R.string.image_article_draft
|
||||
} else {
|
||||
R.string.post_image_and_text
|
||||
}
|
||||
tvTitle.setText(titleResId)
|
||||
}
|
||||
|
||||
chooseImageLauncher = registerForActivityResult(object : ActivityResultContract<Int, Intent?>() {
|
||||
override fun createIntent(context: Context, input: Int): Intent {
|
||||
return LocalMediaActivity.getIntent(
|
||||
context,
|
||||
ChooseType.IMAGE,
|
||||
input,
|
||||
"图文动态"
|
||||
)
|
||||
}
|
||||
|
||||
override fun parseResult(resultCode: Int, intent: Intent?): Intent? {
|
||||
return intent
|
||||
}
|
||||
}, ActivityResultCallback<Intent?> {
|
||||
if (it != null) {
|
||||
val uris = Matisse.obtainResult(it)
|
||||
if (uris.isEmpty()) {
|
||||
if (isFirstEnter) {
|
||||
finish()
|
||||
}
|
||||
|
||||
} else {
|
||||
viewModel.addImages(uris)
|
||||
// 打开发布页
|
||||
if (isFirstEnter) {
|
||||
replaceFragment(true) {
|
||||
PublishImageArticleFragment.newInstance()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isFirstEnter) {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
if (imageArticleEntity == null) {
|
||||
// 新建图文,优先进入图库选择页
|
||||
replaceFragment(false, ::ImageArticleRequestPermissionFragment)
|
||||
PermissionHelper.checkStoragePermissionBeforeActionForResult(this) { grant ->
|
||||
if (grant) {
|
||||
chooseImage(9)
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 编辑图文草稿,不用弹出授权页,直接进入发布页
|
||||
replaceFragment(true) {
|
||||
PublishImageArticleFragment.newInstance()
|
||||
}
|
||||
}
|
||||
SensorsBridge.trackEvent(
|
||||
"ViewPostArticle",
|
||||
"source_entrance",
|
||||
mEntrance,
|
||||
"article_type",
|
||||
"图文",
|
||||
"bbs_type",
|
||||
imageArticleEntity?.community?.type ?: communityEntity?.type ?: "",
|
||||
"bbs_id",
|
||||
imageArticleEntity?.community?.id ?: communityEntity?.id ?: ""
|
||||
)
|
||||
|
||||
with(viewModel) {
|
||||
val lifecycleOwner = this@PublishImageArticleActivity
|
||||
chooseImageAction.observe(lifecycleOwner, EventObserver {
|
||||
isFirstEnter = false
|
||||
PermissionHelper.checkStoragePermissionBeforeActionForResult(this@PublishImageArticleActivity) { grant ->
|
||||
if (grant) {
|
||||
this@PublishImageArticleActivity.chooseImage(it)
|
||||
}
|
||||
}
|
||||
NewLogUtils.logChooseMedia(
|
||||
"view_media",
|
||||
"图文",
|
||||
"图片"
|
||||
)
|
||||
})
|
||||
|
||||
draftBoxDestination.observe(lifecycleOwner, EventObserver {
|
||||
replaceFragment(true) {
|
||||
ImageArticleDraftFragment.newInstance(true)
|
||||
}
|
||||
})
|
||||
|
||||
setEditImageArticle(imageArticleEntity)
|
||||
communityEntity?.let(::setCommunity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun chooseImage(limit: Int) {
|
||||
try {
|
||||
chooseImageLauncher.launch(limit)
|
||||
} catch (e: Exception) {
|
||||
toast(R.string.media_image_hint)
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified T : Fragment> replaceFragment(addBackStack: Boolean = true, creator: () -> T) {
|
||||
val tag = T::class.java.toString()
|
||||
val fragment = supportFragmentManager.findFragmentByTag(tag) ?: creator()
|
||||
val transaction = supportFragmentManager.beginTransaction()
|
||||
transaction.replace(R.id.layout_activity_content, fragment, tag)
|
||||
if (addBackStack) {
|
||||
transaction.addToBackStack(tag)
|
||||
}
|
||||
transaction.commitAllowingStateLoss()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun getIntent(context: Context, entrance: String): Intent {
|
||||
val intent = Intent(context, PublishImageArticleActivity::class.java)
|
||||
intent.putExtra(EntranceConsts.KEY_ENTRANCE, entrance)
|
||||
return intent
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,107 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.adapter
|
||||
|
||||
import android.net.Uri
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil.ItemCallback
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.display
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.utils.visibleIf
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.databinding.RecyclerImageAndTextBinding
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.PublishImageArticleViewModel
|
||||
|
||||
open class ImageAndTextAdapter(
|
||||
private val viewModel: PublishImageArticleViewModel,
|
||||
private val startDrag: (ViewHolder) -> Unit
|
||||
) :
|
||||
ListAdapter<ImageAndTextAdapter.LocalImage, ImageAndTextAdapter.ImageViewHolder>(
|
||||
createItemDiffCallback()
|
||||
) {
|
||||
|
||||
override fun submitList(list: List<LocalImage>?) {
|
||||
val size = list?.size ?: 0
|
||||
if (size < 9 && list != null) {
|
||||
super.submitList(list + LocalImage(INVALID_ID, false, showClose = false))
|
||||
} else {
|
||||
super.submitList(list)
|
||||
}
|
||||
}
|
||||
|
||||
public override fun getItem(position: Int): LocalImage {
|
||||
return super.getItem(position)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder {
|
||||
return ImageViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
with(holder.binding) {
|
||||
tvCover.visibleIf(item.isCover)
|
||||
ivClose.visibleIf(item.showClose) {
|
||||
ivClose.setOnClickListener {
|
||||
if (itemCount <= 2) {
|
||||
ToastUtils.showToast(root.context.getString(R.string.post_image_limit))
|
||||
return@setOnClickListener
|
||||
}
|
||||
viewModel.removeImage(holder.bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
if (item.id != INVALID_ID) {
|
||||
if (item.uri != null) {
|
||||
ivIcon.setImageURI(item.uri)
|
||||
} else {
|
||||
ivIcon.display(item.url)
|
||||
}
|
||||
|
||||
ivIcon.setOnClickListener(null)
|
||||
ivIcon.setOnLongClickListener {
|
||||
startDrag(holder)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
} else {
|
||||
ivIcon.setImageResource(R.drawable.ic_image_and_text_add)
|
||||
ivIcon.setOnClickListener {
|
||||
viewModel.chooseImage()
|
||||
}
|
||||
root.setOnLongClickListener(null)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val INVALID_ID = -1
|
||||
|
||||
private fun createItemDiffCallback() = object : ItemCallback<LocalImage>() {
|
||||
|
||||
override fun areItemsTheSame(oldItem: LocalImage, newItem: LocalImage): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: LocalImage, newItem: LocalImage): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
data class LocalImage(
|
||||
val id: Int,
|
||||
var isCover: Boolean,
|
||||
var showClose: Boolean,
|
||||
val uri: Uri? = null, // 本地图片
|
||||
val url: String? = null // 线上图片
|
||||
)
|
||||
|
||||
data class ImageViewHolder(
|
||||
val binding: RecyclerImageAndTextBinding
|
||||
) : RecyclerView.ViewHolder(binding.root)
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.adapter
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.databinding.RecyclerImageArticleDetailBannerBinding
|
||||
|
||||
class ImageArticleDetailBannerAdapter : ListAdapter<String, ImageArticleDetailBannerAdapter.BannerViewHolder>(
|
||||
createDiffCallback()
|
||||
) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BannerViewHolder {
|
||||
return BannerViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: BannerViewHolder, position: Int) {
|
||||
with(holder.binding) {
|
||||
ImageUtils.display(ivBanner, getItem(position))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun createDiffCallback() = object : DiffUtil.ItemCallback<String>() {
|
||||
override fun areItemsTheSame(oldItem: String, newItem: String): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: String, newItem: String): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class BannerViewHolder(val binding: RecyclerImageArticleDetailBannerBinding) : ViewHolder(binding.root)
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.adapter
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentAdapter
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentAdapter.AdapterType
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
|
||||
|
||||
class ImageArticleDetailCommentAdapter(
|
||||
context: Context,
|
||||
private val viewModel: BaseCommentViewModel,
|
||||
type: AdapterType,
|
||||
entrance: String
|
||||
) : BaseCommentAdapter(context, viewModel, type, entrance) {
|
||||
}
|
||||
@ -1,79 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.DiffUtil.ItemCallback
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.gh.common.util.NewsUtils
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.databinding.RecyclerImageArticleDraftBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.ImageArticleDraftViewModel
|
||||
import com.lzf.easyfloat.utils.DisplayUtils
|
||||
|
||||
class ImageArticleDraftAdapter(
|
||||
private val context: Context,
|
||||
private val viewModel: ImageArticleDraftViewModel
|
||||
) :
|
||||
ListAdapter<ImageArticleEntity, ImageArticleDraftAdapter.DraftViewHolder>(createDiffCallback()) {
|
||||
|
||||
private val itemWidth by lazy {
|
||||
(DisplayUtils.getScreenWidth(context) - 20F.dip2px()) / 2F
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DraftViewHolder {
|
||||
return DraftViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: DraftViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
with(holder.binding) {
|
||||
val title = item.title.ifBlank { item.content }
|
||||
tvTitle.goneIf(title.isBlank()) {
|
||||
tvTitle.text = title
|
||||
}
|
||||
|
||||
val imageInfo = item.imagesInfos.firstOrNull()
|
||||
val imageRadio = ImageArticleEntity.getImageRadio(imageInfo, DRAFT_RADIO_MIN, DRAFT_RADIO_MAX)
|
||||
ivCover.updateLayoutParams {
|
||||
height = (itemWidth * imageRadio).toInt()
|
||||
}
|
||||
ImageUtils.display(ivCover, item.images.firstOrNull() ?: "")
|
||||
tvTime.text = NewsUtils.getFormattedTime(item.time.update)
|
||||
vDelete.setOnClickListener {
|
||||
viewModel.showDeleteDraftDialog(item.id)
|
||||
}
|
||||
|
||||
root.setOnClickListener {
|
||||
viewModel.editDraft(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val DRAFT_RADIO_MIN = 0.75F
|
||||
const val DRAFT_RADIO_MAX = 1.33F
|
||||
|
||||
private fun createDiffCallback() = object : ItemCallback<ImageArticleEntity>() {
|
||||
override fun areItemsTheSame(oldItem: ImageArticleEntity, newItem: ImageArticleEntity): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: ImageArticleEntity,
|
||||
newItem: ImageArticleEntity
|
||||
): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
data class DraftViewHolder(val binding: RecyclerImageArticleDraftBinding) : ViewHolder(binding.root)
|
||||
}
|
||||
@ -1,193 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.DiffUtil.ItemCallback
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.RecyclerRecommendHomeBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleFooterWrapperAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDraftAdapter.Companion.DRAFT_RADIO_MAX
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDraftAdapter.Companion.DRAFT_RADIO_MIN
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.RecommendHomeAdapter.Companion.PAYLOADS_CHANGED_COVER
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.RecommendHomeAdapter.Companion.PAYLOADS_CHANGED_TITLE
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.RecommendHomeAdapter.Companion.PAYLOADS_CHANGED_VOTE
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.MyImageArticleListViewModel
|
||||
import com.lzf.easyfloat.utils.DisplayUtils
|
||||
|
||||
class MyImageArticleAdapter(
|
||||
private val context: Context,
|
||||
private val viewModel: MyImageArticleListViewModel
|
||||
) :
|
||||
ImageArticleFooterWrapperAdapter<PersonalHistoryEntity, MyImageArticleAdapter.MyImageArticleViewHolder>(
|
||||
createDiffCallback()
|
||||
) {
|
||||
|
||||
override fun onCreateDataViewHolder(parent: ViewGroup): MyImageArticleViewHolder {
|
||||
return MyImageArticleViewHolder(parent.toBinding(), object : MyImageArticleViewHolder.OnMyArticleImageListener {
|
||||
override fun navigateToImageArticleDetailPage(item: PersonalHistoryEntity, position: Int) {
|
||||
viewModel.navigateToImageArticleDetailPage(item.id)
|
||||
}
|
||||
|
||||
override fun voteImageArticle(id: String, vote: Boolean) {
|
||||
viewModel.useCase.voteImageArticle(id, vote)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
override fun onBindDataViewHolder(holder: MyImageArticleViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
holder.bind(item, position)
|
||||
|
||||
}
|
||||
|
||||
override fun onBindDataViewHolder(holder: MyImageArticleViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||
val item = getItem(position)
|
||||
holder.bind(item, position, payloads)
|
||||
}
|
||||
|
||||
override fun loadMore() {
|
||||
viewModel.loadMore()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun createDiffCallback() = object : ItemCallback<PersonalHistoryEntity>() {
|
||||
override fun areItemsTheSame(oldItem: PersonalHistoryEntity, newItem: PersonalHistoryEntity): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: PersonalHistoryEntity, newItem: PersonalHistoryEntity): Boolean {
|
||||
return oldItem.title == newItem.title
|
||||
&& oldItem.brief == newItem.brief
|
||||
&& oldItem.user.id == newItem.user.id
|
||||
&& oldItem.user.icon == newItem.user.icon
|
||||
&& oldItem.user.name == newItem.user.name
|
||||
&& oldItem.count.vote == newItem.count.vote
|
||||
&& oldItem.status == newItem.status
|
||||
}
|
||||
|
||||
override fun getChangePayload(oldItem: PersonalHistoryEntity, newItem: PersonalHistoryEntity): Any {
|
||||
val payloads = mutableListOf<String>()
|
||||
if (oldItem.images.firstOrNull() != newItem.images.firstOrNull()
|
||||
|| oldItem.imagesInfo.firstOrNull() != newItem.imagesInfo.firstOrNull()
|
||||
) {
|
||||
payloads.add(PAYLOADS_CHANGED_COVER)
|
||||
}
|
||||
|
||||
val oldTitle = oldItem.title.ifBlank { oldItem.content }
|
||||
val newTitle = newItem.title.ifBlank { newItem.content }
|
||||
if (oldTitle != newTitle) {
|
||||
payloads.add(PAYLOADS_CHANGED_TITLE)
|
||||
}
|
||||
|
||||
if (oldItem.me.isCommunityArticleVote != newItem.me.isCommunityArticleVote
|
||||
|| oldItem.count.vote != newItem.count.vote
|
||||
) {
|
||||
payloads.add(PAYLOADS_CHANGED_VOTE)
|
||||
}
|
||||
return payloads
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class MyImageArticleViewHolder(
|
||||
val binding: RecyclerRecommendHomeBinding,
|
||||
private val listener: OnMyArticleImageListener
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
private val itemWidth by lazy {
|
||||
(DisplayUtils.getScreenWidth(itemView.context) - 20F.dip2px()) / 2F
|
||||
}
|
||||
|
||||
fun bind(item: PersonalHistoryEntity, position: Int, payloads: List<Any?>? = null) {
|
||||
fun setCover() {
|
||||
val imageInfo = item.imagesInfo.firstOrNull()
|
||||
val imageRadio = ImageArticleEntity.getImageRadio(imageInfo, DRAFT_RADIO_MIN, DRAFT_RADIO_MAX)
|
||||
binding.ivCover.updateLayoutParams {
|
||||
height = (itemWidth * imageRadio).toInt()
|
||||
}
|
||||
binding.ivCover.display(item.images.firstOrNull())
|
||||
}
|
||||
|
||||
fun setTitle() {
|
||||
val title = item.title.ifBlank { item.content }
|
||||
binding.tvTitle.goneIf(title.isBlank()) {
|
||||
binding.tvTitle.text = title
|
||||
}
|
||||
}
|
||||
|
||||
fun setVote() {
|
||||
binding.voteState.setVote(item.me.isCommunityArticleVote, item.count.vote, item.status)
|
||||
}
|
||||
|
||||
with(binding) {
|
||||
if (payloads.isNullOrEmpty()) {
|
||||
ivIcon.displayGameIcon(item.user.icon, null)
|
||||
tvAuthorName.text = item.user.name
|
||||
|
||||
setTitle()
|
||||
|
||||
setCover()
|
||||
|
||||
setVote()
|
||||
|
||||
} else {
|
||||
payloads.filterIsInstance<List<String>>()
|
||||
.flatten()
|
||||
.forEach { change ->
|
||||
when (change) {
|
||||
PAYLOADS_CHANGED_COVER -> {
|
||||
setCover()
|
||||
}
|
||||
|
||||
PAYLOADS_CHANGED_TITLE -> {
|
||||
setTitle()
|
||||
}
|
||||
|
||||
PAYLOADS_CHANGED_VOTE -> {
|
||||
binding.voteState.setVote(
|
||||
item.me.isCommunityArticleVote,
|
||||
item.count.vote,
|
||||
item.status
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
root.setOnClickListener {
|
||||
listener.navigateToImageArticleDetailPage(item, position)
|
||||
}
|
||||
|
||||
setVote()
|
||||
voteState.setOnClickListener {
|
||||
val vote = !item.me.isCommunityArticleVote
|
||||
SensorsBridge.trackArticleLikeClick(
|
||||
customerType = item.user.auth?.text ?: "",
|
||||
articleId = item.id,
|
||||
bbsId = item.community.id,
|
||||
bbsType = item.community.typeChinese,
|
||||
activityTag = "",
|
||||
gameForumType = item.community.game?.categoryChinese ?: "",
|
||||
articleType = "图文",
|
||||
buttonName = if (item.me.isCommunityArticleVote) "取消点赞" else "赞同"
|
||||
)
|
||||
listener.voteImageArticle(item.id, vote)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnMyArticleImageListener {
|
||||
|
||||
fun navigateToImageArticleDetailPage(item: PersonalHistoryEntity, position: Int)
|
||||
|
||||
fun voteImageArticle(id: String, vote: Boolean)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,269 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.util.SparseArray
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.DiffUtil.ItemCallback
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.gh.common.exposure.IExposable
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.common.util.NewLogUtils.LOG_STORE_BBS
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.RecyclerRecommendHomeBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleFooterWrapperAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDraftAdapter.Companion.DRAFT_RADIO_MAX
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDraftAdapter.Companion.DRAFT_RADIO_MIN
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.ImageArticleHomeViewModel
|
||||
import com.lzf.easyfloat.utils.DisplayUtils
|
||||
|
||||
class RecommendHomeAdapter(
|
||||
private val context: Context,
|
||||
private val viewModel: ImageArticleHomeViewModel
|
||||
) :
|
||||
ImageArticleFooterWrapperAdapter<ImageArticleEntity, RecommendHomeAdapter.RecommendHomeViewHolder>(
|
||||
createDiffCallback()
|
||||
), IExposable {
|
||||
|
||||
private val viewHolderSet = mutableSetOf<RecommendHomeViewHolder>()
|
||||
private val exposureEventSparseArray: SparseArray<ExposureEvent> = SparseArray()
|
||||
|
||||
override fun onViewAttachedToWindow(holder: ViewHolder) {
|
||||
if (holder is RecommendHomeViewHolder) {
|
||||
viewHolderSet.add(holder)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onViewDetachedFromWindow(holder: ViewHolder) {
|
||||
viewHolderSet.remove(holder)
|
||||
}
|
||||
|
||||
override fun onCreateDataViewHolder(parent: ViewGroup): RecommendHomeViewHolder {
|
||||
return RecommendHomeViewHolder(parent.toBinding(), object : OnImageArticleListener {
|
||||
override fun navigateToImageArticleDetailPage(imageArticleEntity: ImageArticleEntity) {
|
||||
viewModel.navigateToImageArticleDetailPage(imageArticleEntity)
|
||||
}
|
||||
|
||||
override fun voteImageArticle(position: Int, item: ImageArticleEntity) {
|
||||
val vote = !item.me.isCommunityArticleVote
|
||||
SensorsBridge.trackArticleLikeClick(
|
||||
customerType = item.user.auth?.text ?: "",
|
||||
articleId = item.id,
|
||||
bbsId = item.community?.id ?: "",
|
||||
bbsType = item.community?.typeChinese ?: "综合论坛",
|
||||
activityTag = "",
|
||||
gameForumType = item.community?.game?.categoryChinese ?: "",
|
||||
articleType = "图文",
|
||||
buttonName = if (item.me.isCommunityArticleVote) "取消点赞" else "赞同"
|
||||
)
|
||||
|
||||
NewLogUtils.logRecommendFeedContentClick(
|
||||
"click_for_you_like",
|
||||
"图文",
|
||||
item.id,
|
||||
position + 1,
|
||||
item.community?.id ?: "",
|
||||
item.community?.typeChinese ?: "",
|
||||
item.user.id ?: ""
|
||||
)
|
||||
viewModel.useCase.voteImageArticle(item.id, vote)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
override fun onBindDataViewHolder(holder: RecommendHomeViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
val exposureEvent = ExposureEvent.createEvent(null, listOf())
|
||||
.apply {
|
||||
jsonExposure = NewLogUtils.getCommunityExposureJsonObject(
|
||||
item.id,
|
||||
item.community?.id ?: "",
|
||||
item.community?.typeChinese ?: "",
|
||||
position + 1,
|
||||
"社区推荐信息流"
|
||||
)
|
||||
logStore = LOG_STORE_BBS
|
||||
}
|
||||
exposureEventSparseArray.append(position, exposureEvent)
|
||||
holder.bind(item, position)
|
||||
}
|
||||
|
||||
override fun onBindDataViewHolder(holder: RecommendHomeViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||
holder.bind(getItem(position), position, payloads)
|
||||
}
|
||||
|
||||
override fun loadMore() {
|
||||
viewModel.loadMore()
|
||||
}
|
||||
|
||||
fun notifyItemChanged(result: ImageArticleEntity) {
|
||||
val position = currentList.indexOfFirst { it.id == result.id }
|
||||
if (position != -1) {
|
||||
val newData = currentList.toMutableList()
|
||||
newData[position] = result
|
||||
submitList(newData)
|
||||
}
|
||||
}
|
||||
|
||||
fun onDarkModeChanged() {
|
||||
viewHolderSet.forEach {
|
||||
it.binding.root.setCardBackgroundColor(
|
||||
com.gh.gamecenter.common.R.color.ui_surface.toColor(
|
||||
it.itemView.context
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getEventByPosition(pos: Int): ExposureEvent? {
|
||||
val event = exposureEventSparseArray.get(pos)
|
||||
return event
|
||||
}
|
||||
|
||||
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? = null
|
||||
|
||||
companion object {
|
||||
|
||||
const val PAYLOADS_CHANGED_COVER = "payloads_changed_cover"
|
||||
const val PAYLOADS_CHANGED_TITLE = "payloads_changed_title"
|
||||
const val PAYLOADS_CHANGED_VOTE = "payloads_changed_vote"
|
||||
const val PAYLOADS_CHANGED_DARK_MODE = "payloads_changed_dark_mode"
|
||||
|
||||
fun createDiffCallback() = object : ItemCallback<ImageArticleEntity>() {
|
||||
override fun areItemsTheSame(oldItem: ImageArticleEntity, newItem: ImageArticleEntity): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: ImageArticleEntity, newItem: ImageArticleEntity): Boolean {
|
||||
return oldItem.title == newItem.title
|
||||
&& oldItem.content == newItem.content
|
||||
&& oldItem.user.id == newItem.user.id
|
||||
&& oldItem.user.icon == newItem.user.icon
|
||||
&& oldItem.user.name == newItem.user.name
|
||||
&& oldItem.count.vote == newItem.count.vote
|
||||
|
||||
}
|
||||
|
||||
override fun getChangePayload(oldItem: ImageArticleEntity, newItem: ImageArticleEntity): Any? {
|
||||
val payloads = mutableListOf<String>()
|
||||
if (oldItem.images.firstOrNull() != newItem.images.firstOrNull()
|
||||
|| oldItem.imagesInfos.firstOrNull() != newItem.imagesInfos.firstOrNull()
|
||||
) {
|
||||
payloads.add(PAYLOADS_CHANGED_COVER)
|
||||
}
|
||||
|
||||
val oldTitle = oldItem.title.ifBlank { oldItem.content }
|
||||
val newTitle = newItem.title.ifBlank { newItem.content }
|
||||
if (oldTitle != newTitle) {
|
||||
payloads.add(PAYLOADS_CHANGED_TITLE)
|
||||
}
|
||||
|
||||
if (oldItem.me.isCommunityArticleVote != newItem.me.isCommunityArticleVote
|
||||
|| oldItem.count.vote != newItem.count.vote
|
||||
) {
|
||||
payloads.add(PAYLOADS_CHANGED_VOTE)
|
||||
}
|
||||
return payloads
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class RecommendHomeViewHolder(
|
||||
val binding: RecyclerRecommendHomeBinding,
|
||||
private val listener: OnImageArticleListener
|
||||
) : ViewHolder(binding.root) {
|
||||
|
||||
private val itemWidth by lazy {
|
||||
(DisplayUtils.getScreenWidth(itemView.context) - 20F.dip2px()) / 2F
|
||||
}
|
||||
|
||||
fun bind(item: ImageArticleEntity, position: Int, payloads: MutableList<Any> = mutableListOf()) {
|
||||
fun setCover() {
|
||||
val imageInfo = item.imagesInfos.firstOrNull()
|
||||
val imageRadio = ImageArticleEntity.getImageRadio(imageInfo, DRAFT_RADIO_MIN, DRAFT_RADIO_MAX)
|
||||
binding.ivCover.updateLayoutParams {
|
||||
height = (itemWidth * imageRadio).toInt()
|
||||
}
|
||||
binding.ivCover.display(item.images.firstOrNull())
|
||||
}
|
||||
|
||||
fun setTitle() {
|
||||
val title = item.title.ifBlank { item.content }
|
||||
binding.tvTitle.goneIf(title.isBlank()) {
|
||||
binding.tvTitle.text = title
|
||||
}
|
||||
}
|
||||
|
||||
fun setVote() {
|
||||
binding.voteState.setVote(item.me.isCommunityArticleVote, item.count.vote, item.status)
|
||||
}
|
||||
|
||||
binding.root.setCardBackgroundColor(
|
||||
com.gh.gamecenter.common.R.color.ui_surface.toColor(
|
||||
itemView.context
|
||||
)
|
||||
)
|
||||
with(binding) {
|
||||
if (payloads.isEmpty()) {
|
||||
ivIcon.displayGameIcon(item.user.icon, null)
|
||||
tvAuthorName.text = item.user.name
|
||||
|
||||
setTitle()
|
||||
|
||||
setCover()
|
||||
|
||||
setVote()
|
||||
|
||||
} else {
|
||||
payloads.filterIsInstance<List<String>>()
|
||||
.flatten()
|
||||
.forEach { change ->
|
||||
when (change) {
|
||||
PAYLOADS_CHANGED_COVER -> {
|
||||
setCover()
|
||||
}
|
||||
|
||||
PAYLOADS_CHANGED_TITLE -> {
|
||||
setTitle()
|
||||
}
|
||||
|
||||
PAYLOADS_CHANGED_VOTE -> {
|
||||
setVote()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
root.setOnClickListener {
|
||||
NewLogUtils.logRecommendFeedContentClick(
|
||||
"click_for_you_content",
|
||||
"图文",
|
||||
item.id,
|
||||
position + 1,
|
||||
item.community?.id ?: "",
|
||||
item.community?.typeChinese ?: "",
|
||||
item.user.id ?: ""
|
||||
)
|
||||
listener.navigateToImageArticleDetailPage(item)
|
||||
}
|
||||
voteState.setOnClickListener {
|
||||
listener.voteImageArticle(position, item)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnImageArticleListener {
|
||||
|
||||
fun navigateToImageArticleDetailPage(imageArticleEntity: ImageArticleEntity)
|
||||
|
||||
fun voteImageArticle(position: Int, item: ImageArticleEntity)
|
||||
}
|
||||
}
|
||||
@ -1,136 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.baselist.ListAdapter
|
||||
import com.gh.gamecenter.common.baselist.ListFragment
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.viewModelProvider
|
||||
import com.gh.gamecenter.common.view.CustomDividerItemDecoration
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDetailCommentAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.ImageArticleCommentViewModel
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.ImageArticleDetailViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.gh.gamecenter.qa.article.detail.CommentItemData
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentAdapter
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
class ImageArticleCommentFragment : ListFragment<CommentItemData, ImageArticleCommentViewModel>() {
|
||||
|
||||
var imageArticleId = ""
|
||||
|
||||
var topCommentId: String? = ""
|
||||
|
||||
private val parentViewModel by viewModels<ImageArticleDetailViewModel>(ownerProducer = { parentFragment ?: this })
|
||||
|
||||
private val adapter by lazy {
|
||||
ImageArticleDetailCommentAdapter(
|
||||
requireContext(),
|
||||
mListViewModel,
|
||||
BaseCommentAdapter.AdapterType.COMMENT,
|
||||
mEntrance
|
||||
)
|
||||
}
|
||||
|
||||
override fun provideListAdapter(): ListAdapter<*> = adapter
|
||||
|
||||
override fun provideListViewModel(): ImageArticleCommentViewModel {
|
||||
return viewModelProvider(
|
||||
ImageArticleCommentViewModel.Factory(
|
||||
HaloApp.getInstance().application,
|
||||
imageArticleId,
|
||||
topCommentId ?: ""
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getItemDecoration(): RecyclerView.ItemDecoration {
|
||||
|
||||
val drawable = ContextCompat.getDrawable(requireContext(), R.drawable.divider_article_detail_comment)
|
||||
val itemDecoration = CustomDividerItemDecoration(
|
||||
requireContext(),
|
||||
notDecorateTheFirstItem = true,
|
||||
notDecorateTheLastItem = true
|
||||
)
|
||||
|
||||
itemDecoration.setDrawable(drawable!!)
|
||||
mItemDecoration = itemDecoration
|
||||
return itemDecoration
|
||||
}
|
||||
|
||||
override fun addSyncPageObserver() = true
|
||||
|
||||
override fun provideSyncAdapter() = adapter
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return R.layout.fragment_list_article_detail_comment
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
ARouter.getInstance().inject(this)
|
||||
arguments?.let {
|
||||
imageArticleId = it.getString(EntranceConsts.KEY_IMAGE_ARTICLE_ID) ?: ""
|
||||
topCommentId = it.getString(EntranceConsts.KEY_TOP_COMMENT_ID) ?: ""
|
||||
}
|
||||
super.onCreate(savedInstanceState)
|
||||
with(parentViewModel) {
|
||||
sortType.observe(this@ImageArticleCommentFragment, EventObserver {
|
||||
mListViewModel.changeSort(it)
|
||||
})
|
||||
|
||||
insertNewestCommentAction.observe(this@ImageArticleCommentFragment, EventObserver {
|
||||
mListViewModel.insertNewestComment(it)
|
||||
})
|
||||
|
||||
commentCount.observe(this@ImageArticleCommentFragment) {
|
||||
mListViewModel.commentCount = it
|
||||
}
|
||||
|
||||
imageArticleDetailEntity.observe(this@ImageArticleCommentFragment) {
|
||||
mListViewModel.topItemData = CommentItemData(imageArticleDetail = it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mListRefresh?.isEnabled = false
|
||||
|
||||
with(mListViewModel) {
|
||||
updateCommentCountAction.observe(viewLifecycleOwner, EventObserver {
|
||||
parentViewModel.updateComment("", commentCount)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLoadError() {
|
||||
super.onLoadError()
|
||||
mListRv.goneIf(false)
|
||||
}
|
||||
|
||||
override fun onLoadNotFound() {
|
||||
super.onLoadNotFound()
|
||||
mListRv.goneIf(false)
|
||||
}
|
||||
|
||||
override fun onLoadEmpty() {
|
||||
super.onLoadEmpty()
|
||||
mListRv.goneIf(false)
|
||||
}
|
||||
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
if (mListRv != null) {
|
||||
mListRv.removeItemDecoration(mItemDecoration)
|
||||
mListRv.addItemDecoration(itemDecoration)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,938 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.Path
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.widget.TextViewCompat
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.common.browse.ValueBrowseTimer
|
||||
import com.gh.common.browse.asObserver
|
||||
import com.gh.common.browse.withLifecycle
|
||||
import com.gh.common.databind.BindingAdapters
|
||||
import com.gh.common.util.BbsReportHelper
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.DownloadItemUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.common.util.NewsUtils
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.GameDetailActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
|
||||
import com.gh.gamecenter.common.base.fragment.BaseFragment
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.entity.AdditionalParamsEntity
|
||||
import com.gh.gamecenter.common.entity.NormalShareEntity
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.databinding.FragmentImageArticleDetailBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.MenuItemEntity
|
||||
import com.gh.gamecenter.eventbus.EBDownloadStatus
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.ImageInfo
|
||||
import com.gh.gamecenter.feature.entity.Permissions
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDetailBannerAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.ImageArticleDetailViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.qa.comment.CommentActivity
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
|
||||
import com.gh.gamecenter.qa.dialog.MoreFunctionPanelDialog
|
||||
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
|
||||
import com.lightgame.download.DataWatcher
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class ImageArticleDetailFragment : BaseFragment<Unit>() {
|
||||
|
||||
private val viewModel by viewModels<ImageArticleDetailViewModel>()
|
||||
|
||||
private var imageArticleId = ""
|
||||
|
||||
private var topCommentId: String? = null
|
||||
|
||||
var scrollToCommentArea: Boolean = false
|
||||
|
||||
private var recommendId: String = ""
|
||||
|
||||
private var showIndicator = false
|
||||
|
||||
private var sourceEntrance = ""
|
||||
|
||||
private val binding: FragmentImageArticleDetailBinding by lazy {
|
||||
FragmentImageArticleDetailBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
private val adapter by lazy {
|
||||
ImageArticleDetailBannerAdapter()
|
||||
}
|
||||
|
||||
private val handler = object : Handler(Looper.getMainLooper()) {
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
if (msg.what == HIDE_BANNER_NUMBER_INDICATOR) {
|
||||
binding.llNumberIndicator.goneIf(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val dataWatcher = object : DataWatcher() {
|
||||
override fun onDataChanged(downloadEntity: DownloadEntity) {
|
||||
setDownloadButton(viewModel.imageArticleDetailEntity.value?.community?.game)
|
||||
}
|
||||
|
||||
override fun onDataInit(downloadEntity: DownloadEntity) {
|
||||
onDataChanged(downloadEntity)
|
||||
}
|
||||
}
|
||||
|
||||
private val browseTimer = ValueBrowseTimer<ImageArticleEntity>()
|
||||
.withLifecycle(this)
|
||||
.withStart {
|
||||
SensorsBridge.trackArticleDetailsBrowsing(
|
||||
bbsId = it?.community?.id ?: "",
|
||||
bbsType = it?.community?.typeChinese ?: "",
|
||||
customerType = it?.user?.auth?.text ?: "",
|
||||
gameForumType = it?.community?.game?.categoryChinese ?: "",
|
||||
activityTag = "",
|
||||
articleType = "图文",
|
||||
sourceEntrance = sourceEntrance,
|
||||
articleId = it?.id ?: ""
|
||||
)
|
||||
}
|
||||
.withResult { detail, time ->
|
||||
SensorsBridge.trackArticleBrowsingDuration(
|
||||
bbsId = detail?.community?.id ?: "",
|
||||
bbsType = detail?.community?.typeChinese ?: "",
|
||||
customerType = detail?.user?.auth?.text ?: "",
|
||||
gameForumType = detail?.community?.game?.categoryChinese ?: "",
|
||||
activityTag = "",
|
||||
articleId = detail?.id ?: "",
|
||||
articleType = "图文",
|
||||
stayLength = time / 1000.0,
|
||||
sourceEntrance = sourceEntrance
|
||||
)
|
||||
|
||||
NewLogUtils.logJumpNoteDetail(
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: "",
|
||||
stayTime = time / 1000
|
||||
)
|
||||
}
|
||||
|
||||
override fun getInflatedLayout() = binding.root
|
||||
|
||||
override fun getLayoutId() = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
arguments?.let {
|
||||
imageArticleId = it.getString(EntranceConsts.KEY_IMAGE_ARTICLE_ID) ?: ""
|
||||
topCommentId = it.getString(EntranceConsts.KEY_TOP_COMMENT_ID) ?: ""
|
||||
scrollToCommentArea = it.getBoolean(EntranceConsts.KEY_SCROLL_TO_COMMENT_AREA)
|
||||
sourceEntrance = it.getString(EntranceConsts.KEY_SOURCE_ENTRANCE) ?: ""
|
||||
recommendId = it.getString(EntranceConsts.KEY_RECOMMEND_ID) ?: ""
|
||||
}
|
||||
super.onCreate(savedInstanceState)
|
||||
viewModel.imageArticleDetailEntity.observe(this, browseTimer.asObserver())
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val tag = ImageArticleDetailFragment::class.java.name
|
||||
val fragment =
|
||||
childFragmentManager.findFragmentByTag(tag) ?: ImageArticleCommentFragment()
|
||||
fragment.arguments = arguments
|
||||
childFragmentManager.beginTransaction()
|
||||
.replace(R.id.fcv_comment_container, fragment, tag)
|
||||
.commitNowAllowingStateLoss()
|
||||
|
||||
with(viewModel) {
|
||||
|
||||
pageStatus.observe(viewLifecycleOwner) {
|
||||
binding.reuseNoConnection.root.goneIf(it != LoadStatus.INIT_FAILED)
|
||||
binding.clContent.goneIf(it != LoadStatus.INIT_LOADED)
|
||||
binding.inputContainer.root.goneIf(it != LoadStatus.INIT_LOADED)
|
||||
binding.layoutLoading.root.goneIf(it != LoadStatus.INIT_LOADING)
|
||||
binding.reuseNoneData.root.goneIf(it != LoadStatus.INIT_EMPTY)
|
||||
if (it == LoadStatus.INIT_EMPTY) {
|
||||
toast(com.gh.gamecenter.common.R.string.content_delete_toast)
|
||||
}
|
||||
}
|
||||
|
||||
imageArticleDetailEntity.observe(viewLifecycleOwner) {
|
||||
NewLogUtils.logViewNoteDetail(
|
||||
it.id,
|
||||
it.community?.id ?: "",
|
||||
it.community?.typeChinese ?: "",
|
||||
it.user.id ?: ""
|
||||
)
|
||||
fillUi(it)
|
||||
}
|
||||
|
||||
isUserFollowed.observe(viewLifecycleOwner) {
|
||||
binding.ctvFollow.isChecked = it
|
||||
binding.ctvFollow.setText(
|
||||
if (it) {
|
||||
R.string.concerned
|
||||
} else {
|
||||
R.string.follow
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
commentCount.observe(viewLifecycleOwner) {
|
||||
binding.inputContainer.bottomCommentTv.text = if (it == 0) {
|
||||
R.string.comment.toResString()
|
||||
} else {
|
||||
"$it"
|
||||
}
|
||||
binding.tvCommentCount.text = "$it"
|
||||
}
|
||||
|
||||
vote.observe(viewLifecycleOwner) {
|
||||
val (isVoted, count) = it
|
||||
val (imageDrawableResId, textColorResId) = if (isVoted) {
|
||||
R.drawable.ic_article_detail_liked_bottom_bar to com.gh.gamecenter.common.R.color.text_theme
|
||||
} else {
|
||||
R.drawable.ic_article_detail_like_bottom_bar to com.gh.gamecenter.common.R.color.text_secondary
|
||||
}
|
||||
binding.inputContainer.bottomLikeIv.setImageResource(imageDrawableResId)
|
||||
binding.inputContainer.bottomLikeTv.setTextColor(textColorResId.toColor(requireContext()))
|
||||
binding.inputContainer.bottomLikeTv.text = if (count == 0) {
|
||||
R.string.agree.toResString()
|
||||
} else {
|
||||
"$count"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
isBbsFollowed.observe(viewLifecycleOwner) {
|
||||
binding.ctvFollowBbs.isChecked = it
|
||||
binding.ctvFollowBbs.setText(
|
||||
if (it) {
|
||||
R.string.concerned
|
||||
} else {
|
||||
R.string.follow
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
isFavorite.observe(viewLifecycleOwner) {
|
||||
val (drawableResId, textColorResId) = if (it) {
|
||||
R.drawable.ic_article_detail_stared_bottom_bar to com.gh.gamecenter.common.R.color.text_theme
|
||||
} else {
|
||||
R.drawable.ic_article_detail_star_bottom_bar to com.gh.gamecenter.common.R.color.text_secondary
|
||||
}
|
||||
binding.inputContainer.bottomStarIv.setImageResource(drawableResId)
|
||||
binding.inputContainer.bottomStarTv.setTextColor(textColorResId.toColor(requireContext()))
|
||||
binding.inputContainer.bottomStarTv.setText(
|
||||
if (it) {
|
||||
R.string.already_saved
|
||||
} else {
|
||||
R.string.menu_collect
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
applyHighlightAction.observe(viewLifecycleOwner, EventObserver {
|
||||
val toastResId = if (it) {
|
||||
R.string.apply_successfully
|
||||
} else {
|
||||
R.string.apply_failure
|
||||
}
|
||||
ToastUtils.showToast(toastResId.toResString())
|
||||
})
|
||||
|
||||
addHighlightAction.observe(viewLifecycleOwner, EventObserver {
|
||||
ToastUtils.showToast(it.toResString())
|
||||
})
|
||||
|
||||
deleteOrHideImageArticleSuccessfully.observe(viewLifecycleOwner, EventObserver {
|
||||
val (isSuccess, toastResId) = it
|
||||
ToastUtils.showToast(toastResId.toResString())
|
||||
if (isSuccess) {
|
||||
EventBus.getDefault().post(EBImageArticleChanged.DataDeleted(imageArticleId))
|
||||
requireActivity().finish()
|
||||
}
|
||||
})
|
||||
|
||||
loadImageArticleDetail(this@ImageArticleDetailFragment.imageArticleId, recommendId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun initView(view: View?) {
|
||||
super.initView(view)
|
||||
binding.vpBanner.adapter = adapter
|
||||
binding.vpBanner.offscreenPageLimit = 2
|
||||
|
||||
binding.vMore.setOnClickListener {
|
||||
showMoreItemDialog()
|
||||
}
|
||||
binding.sfvOrder.setItemList(
|
||||
listOf(R.string.positive_older.toResString(), R.string.reverse_order.toResString()), 0
|
||||
)
|
||||
|
||||
binding.inputContainer.replyTv.setText(R.string.message_detail_comment_hint2)
|
||||
binding.inputContainer.replyTv.setRoundedColorBackground(com.gh.gamecenter.common.R.color.ui_container_2, 19F)
|
||||
binding.inputContainer.replyTv.setDebouncedClickListener {
|
||||
NewLogUtils.logCommentClick(
|
||||
"click_comment_area_comment_input_box",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
viewModel.imageArticleDetailEntity.value?.id
|
||||
?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
clickToastByStatus(viewModel.imageArticleDetailEntity.value?.status ?: "") {
|
||||
val imageArticle = viewModel.imageArticleDetailEntity.value ?: return@clickToastByStatus
|
||||
val intent = CommentActivity.getImageArticleCommentIntent(
|
||||
requireContext(),
|
||||
imageArticle.id,
|
||||
imageArticle.communityId,
|
||||
viewModel.commentCount.value
|
||||
)
|
||||
startActivityForResult(intent, CommentActivity.REQUEST_CODE)
|
||||
}
|
||||
}
|
||||
binding.inputContainer.bottomCommentIv.setOnClickListener {
|
||||
binding.appBar.setExpanded(false, true)
|
||||
NewLogUtils.logCommentAreaEnter("图文")
|
||||
}
|
||||
binding.inputContainer.bottomCommentTv.setOnClickListener { binding.inputContainer.bottomCommentIv.performClick() }
|
||||
|
||||
binding.inputContainer.bottomStarIv.setOnClickListener {
|
||||
requireContext().ifLogin(entrance = "帖子详情-收藏") {
|
||||
clickToastByStatus(viewModel.imageArticleDetailEntity.value?.status ?: "") {
|
||||
viewModel.collect()
|
||||
}
|
||||
NewLogUtils.logCommentClick(
|
||||
"click_comment_area_collect",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
binding.inputContainer.bottomStarTv.setOnClickListener { binding.inputContainer.bottomStarIv.performClick() }
|
||||
|
||||
binding.inputContainer.bottomLikeIv.setOnClickListener {
|
||||
requireContext().ifLogin("帖子详情-赞同") {
|
||||
clickToastByStatus(viewModel.imageArticleDetailEntity.value?.status ?: "") {
|
||||
viewModel.vote()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.inputContainer.bottomLikeTv.setOnClickListener { binding.inputContainer.bottomLikeIv.performClick() }
|
||||
|
||||
binding.sfvOrder.setOnCheckedCallback {
|
||||
val newSort = if (it == 0) {
|
||||
BaseCommentViewModel.SortType.OLDEST
|
||||
} else {
|
||||
BaseCommentViewModel.SortType.LATEST
|
||||
}
|
||||
viewModel.changeSort(newSort)
|
||||
}
|
||||
binding.ctvFollow.setOnClickListener {
|
||||
ifLogin("图文详情-关注") {
|
||||
viewModel.followUser()
|
||||
}
|
||||
NewLogUtils.logClickNoteDetailFollow(
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
!(viewModel.isUserFollowed.value ?: false)
|
||||
)
|
||||
}
|
||||
binding.vBack.setOnClickListener {
|
||||
activity?.finish()
|
||||
}
|
||||
binding.ivAvatar.setOnClickListener {
|
||||
DirectUtils.directToHomeActivity(
|
||||
requireContext(),
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id,
|
||||
1,
|
||||
mEntrance,
|
||||
"图文详情"
|
||||
)
|
||||
NewLogUtils.logClickNoteDetailProfilePhoto(
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
binding.tvName.setOnClickListener {
|
||||
DirectUtils.directToHomeActivity(
|
||||
requireContext(),
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id,
|
||||
1,
|
||||
mEntrance,
|
||||
"图文详情"
|
||||
)
|
||||
NewLogUtils.logClickNoteDetailNickname(
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
binding.vpBanner.registerOnPageChangeCallback(object : OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
showNumberIndicator(position)
|
||||
}
|
||||
})
|
||||
|
||||
binding.reuseNoConnection.connectionReloadTv.setOnClickListener {
|
||||
viewModel.loadImageArticleDetail(imageArticleId, recommendId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fillUi(imageArticle: ImageArticleEntity) {
|
||||
binding.tvTitle.goneIf(imageArticle.title.isBlank()) {
|
||||
binding.tvTitle.text = imageArticle.title
|
||||
}
|
||||
binding.tvContent.goneIf(imageArticle.content.isBlank()) {
|
||||
binding.tvContent.text = imageArticle.content
|
||||
}
|
||||
|
||||
binding.ivAvatar.display(imageArticle.user.border, imageArticle.user.icon, imageArticle.user.auth?.icon)
|
||||
binding.tvName.text = imageArticle.user.name
|
||||
if (imageArticle.user.auth == null) {
|
||||
binding.tvAuth.goneIf(true)
|
||||
TextViewCompat.setTextAppearance(binding.tvName, com.gh.gamecenter.common.R.style.TextHeadline)
|
||||
} else {
|
||||
binding.tvAuth.goneIf(false)
|
||||
binding.tvAuth.text = imageArticle.user.auth?.text
|
||||
TextViewCompat.setTextAppearance(binding.tvName, com.gh.gamecenter.common.R.style.TextBody2)
|
||||
}
|
||||
|
||||
binding.ctvFollow.goneIf(imageArticle.me.isContentOwner)
|
||||
binding.tvTime.text = NewsUtils.getFormattedTime(imageArticle.time.edit)
|
||||
|
||||
val imagesSize = imageArticle.images.size
|
||||
showIndicator = imagesSize >= SHOW_DOT_INDICATOR_MIN
|
||||
binding.dorIndicator.goneIf(!showIndicator) {
|
||||
binding.dorIndicator.show(imagesSize)
|
||||
}
|
||||
binding.llNumberIndicator.goneIf(!showIndicator) {
|
||||
binding.tvIndicatorTotal.text = "/${imagesSize}"
|
||||
showNumberIndicator(0)
|
||||
}
|
||||
|
||||
|
||||
setBannerSize(imageArticle.imagesInfos.firstOrNull())
|
||||
adapter.submitList(imageArticle.images)
|
||||
|
||||
val community = imageArticle.community
|
||||
val game = community?.game
|
||||
when {
|
||||
game != null -> {
|
||||
// 显示游戏
|
||||
showGame(game, imageArticle.community.id)
|
||||
}
|
||||
|
||||
community != null -> {
|
||||
showCommunity(community)
|
||||
}
|
||||
|
||||
else -> {
|
||||
binding.clBbsContainer.goneIf(true)
|
||||
binding.clGameContainer.goneIf(true)
|
||||
}
|
||||
}
|
||||
|
||||
if (scrollToCommentArea) {
|
||||
scrollToCommentArea = false
|
||||
binding.appBar.setExpanded(false, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showCommunity(community: ImageArticleEntity.Community) {
|
||||
binding.clBbsContainer.goneIf(false)
|
||||
binding.clGameContainer.goneIf(true)
|
||||
binding.ivBbsIcon.display(community.icon)
|
||||
binding.tvBbsName.text = community.name
|
||||
binding.tvHeat.text = "${community.hot}"
|
||||
binding.clBbsContainer.setOnClickListener {
|
||||
DirectUtils.directForumDetail(requireContext(), community.id, "帖子详情")
|
||||
NewLogUtils.logClickNoteDetailForum(community.id, community.typeChinese)
|
||||
}
|
||||
binding.ctvFollowBbs.setOnClickListener {
|
||||
SensorsBridge.trackFollowForumClick(
|
||||
bbsId = community.id,
|
||||
forumName = community.name,
|
||||
bbsType = community.typeChinese,
|
||||
buttonName = binding.ctvFollowBbs.text.toString(),
|
||||
gameForumType = community.game?.categoryChinese ?: ""
|
||||
)
|
||||
viewModel.followBbs(community.id)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showGame(game: GameEntity, communityId: String) {
|
||||
game.exposureEvent = ExposureEvent.createEventWithSourceConcat(
|
||||
game,
|
||||
listOf(),
|
||||
listOf(ExposureSource("其他"), ExposureSource("图文详情"))
|
||||
)
|
||||
binding.clBbsContainer.goneIf(true)
|
||||
binding.clGameContainer.goneIf(false)
|
||||
binding.ivGameIcon.displayGameIcon(game)
|
||||
binding.tvGameName.text = game.name
|
||||
binding.tvGameRating.goneIf(!(game.commentCount > 3 && game.star >= 7)) {
|
||||
binding.tvGameRating.text = game.star.toString()
|
||||
}
|
||||
BindingAdapters.setGameTags(binding.gtcvGameTags, game)
|
||||
|
||||
setDownloadButton(game)
|
||||
binding.clGameContainer.setOnClickListener {
|
||||
GameDetailActivity.startGameDetailActivity(
|
||||
requireContext(),
|
||||
game,
|
||||
"图文详情",
|
||||
traceEvent = game.exposureEvent
|
||||
)
|
||||
}
|
||||
|
||||
binding.tvGoBbs.setOnClickListener {
|
||||
DirectUtils.directForumDetail(requireContext(), communityId, "帖子详情")
|
||||
}
|
||||
}
|
||||
|
||||
private fun setDownloadButton(gameEntity: GameEntity?) {
|
||||
if (gameEntity == null) return
|
||||
DownloadItemUtils.setOnClickListener(
|
||||
requireContext(), binding.btnDownload,
|
||||
gameEntity, 0, null,
|
||||
mEntrance,
|
||||
location = "视频详情",
|
||||
traceEvent = gameEntity.exposureEvent,
|
||||
clickCallback = {
|
||||
|
||||
},
|
||||
refreshCallback = { setDownloadButton(gameEntity) },
|
||||
allStateClickCallback = null
|
||||
)
|
||||
DownloadItemUtils.updateItem(
|
||||
requireContext(),
|
||||
gameEntity,
|
||||
GameViewHolder(binding.clGameContainer).apply {
|
||||
gameDownloadBtn = binding.btnDownload
|
||||
gameDownloadTips = binding.downloadTipsLottie
|
||||
multiVersionDownloadTv = binding.multiVersionDownloadTv
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun setBannerSize(imageInfo: ImageInfo?) {
|
||||
binding.vpBanner.goneIf(imageInfo == null) {
|
||||
val bannerRadio = ImageArticleEntity.getImageRadio(imageInfo, BANNER_RADIO_MIN, BANNER_RADIO_MAX)
|
||||
binding.vpBanner.updateLayoutParams {
|
||||
height = (resources.displayMetrics.widthPixels * bannerRadio).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun showNumberIndicator(position: Int) {
|
||||
if (showIndicator) {
|
||||
binding.llNumberIndicator.goneIf(false)
|
||||
binding.tvIndicatorPosition.text = "${position + 1}"
|
||||
handler.removeMessages(HIDE_BANNER_NUMBER_INDICATOR)
|
||||
handler.sendEmptyMessageDelayed(HIDE_BANNER_NUMBER_INDICATOR, SHOW_NUMBER_INDICATOR_DURATION)
|
||||
binding.dorIndicator.selectPosition(position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMoreItemDialog() {
|
||||
val imageArticle = viewModel.imageArticleDetailEntity.value ?: return
|
||||
NewLogUtils.logShareEnter("图文详情页")
|
||||
NewLogUtils.logClickNoteDetailMore()
|
||||
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
|
||||
val entities = ArrayList<MenuItemEntity>()
|
||||
// 申请加精
|
||||
val simplifyChoicenessStatus = imageArticle.getSimplifyChoicenessStatus()
|
||||
if (imageArticle.user.id == UserManager.getInstance().userId && !imageArticle.me.isModerator && imageArticle.status == "pass") {
|
||||
val isEnable =
|
||||
simplifyChoicenessStatus != ArticleDetailEntity.STATUS_PASS
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_apply_select_title),
|
||||
if (isEnable)
|
||||
R.drawable.icon_more_panel_essence else R.drawable.icon_more_panel_essence_unenable,
|
||||
isEnable = isEnable
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// 修改
|
||||
if (imageArticle.me.isContentOwner
|
||||
&& imageArticle.status == ArticleDetailEntity.STATUS_PASS
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(getString(R.string.article_detail_more_edit_title), R.drawable.icon_more_panel_edit)
|
||||
)
|
||||
}
|
||||
|
||||
// 举报
|
||||
if (!imageArticle.me.isContentOwner) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_complaint_title),
|
||||
R.drawable.icon_gamedetail_copyright
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val moderatorPermissions = imageArticle.me.moderatorPermissions
|
||||
// 取消精选
|
||||
if (imageArticle.me.isModerator
|
||||
&& imageArticle.status == ArticleDetailEntity.STATUS_PASS
|
||||
) {
|
||||
if (simplifyChoicenessStatus == ArticleDetailEntity.STATUS_PASS) {
|
||||
if ((moderatorPermissions.cancelChoicenessImageArticle) > Permissions.GUEST
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_unselect_title),
|
||||
R.drawable.icon_more_panel_essence_cancel
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if ((moderatorPermissions.choicenessImageArticle) > Permissions.GUEST
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_select_title),
|
||||
R.drawable.icon_more_panel_essence
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 修改活动标签
|
||||
if (imageArticle.me.isModerator &&
|
||||
(moderatorPermissions.updateArticleActivityTag) > Permissions.GUEST &&
|
||||
imageArticle.status == ArticleDetailEntity.STATUS_PASS
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_edit_activity_tag_title),
|
||||
R.drawable.icon_more_panel_modify_label
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// 隐藏/删除
|
||||
if (imageArticle.me.isModerator && moderatorPermissions.hideImageArticle > Permissions.GUEST
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_hide_title),
|
||||
R.drawable.icon_more_panel_delete
|
||||
)
|
||||
)
|
||||
} else {
|
||||
if (imageArticle.me.isContentOwner) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_delete_title),
|
||||
R.drawable.icon_more_panel_delete
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
MoreFunctionPanelDialog.showMoreDialog(
|
||||
requireActivity() as AppCompatActivity,
|
||||
entities,
|
||||
imageArticle.title.ifBlank { imageArticle.content },
|
||||
getShareEntity(imageArticle),
|
||||
imageArticle.status,
|
||||
tag ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getShareEntity(imageArticle: ImageArticleEntity): NormalShareEntity {
|
||||
val params = AdditionalParamsEntity().apply {
|
||||
contentType = "图文"
|
||||
contentId = imageArticle.id
|
||||
bbsId = imageArticle.communityId
|
||||
bbsType = imageArticle.community?.typeChinese ?: "综合论坛"
|
||||
customerType = imageArticle.user.auth?.text ?: ""
|
||||
activityTagName = ""
|
||||
gameForumType = imageArticle.community?.game?.categoryChinese ?: ""
|
||||
refUserId = UserManager.getInstance().userId
|
||||
}
|
||||
return NormalShareEntity(
|
||||
id = imageArticle.id,
|
||||
shareUrl = requireContext().getString(
|
||||
R.string.share_community_image_article_url,
|
||||
imageArticle.shortId
|
||||
),
|
||||
shareIcon = if (imageArticle.images.isNotEmpty()) {
|
||||
imageArticle.images.first()
|
||||
} else {
|
||||
requireContext().getString(R.string.share_ghzs_logo)
|
||||
},
|
||||
shareTitle = imageArticle.title.ifBlank { imageArticle.content }
|
||||
.ifBlank { getString(R.string.image_article) },
|
||||
shareSummary = imageArticle.content,
|
||||
shareEntrance = ShareUtils.ShareEntrance.communityArticle,
|
||||
additionalParams = params
|
||||
)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
DownloadManager.getInstance().addObserver(dataWatcher)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
DownloadManager.getInstance().removeObserver(dataWatcher)
|
||||
}
|
||||
|
||||
//下载被删除事件
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(status: EBDownloadStatus) {
|
||||
if ("delete" == status.status) {
|
||||
setDownloadButton(viewModel.imageArticleDetailEntity.value?.community?.game)
|
||||
}
|
||||
}
|
||||
|
||||
//安装、卸载事件
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(busFour: EBPackage) {
|
||||
setDownloadButton(viewModel.imageArticleDetailEntity.value?.community?.game)
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(reuse: EBReuse) {
|
||||
if (reuse.type == Constants.LOGIN_TAG) { // 登入
|
||||
viewModel.loadImageArticleDetail(imageArticleId, recommendId)
|
||||
|
||||
}
|
||||
val path = Path()
|
||||
path.reset()
|
||||
}
|
||||
|
||||
//
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
viewModel.imageArticleChanged(changed)
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
setDownloadButton(viewModel.imageArticleDetailEntity.value?.community?.game)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
when {
|
||||
requestCode == CommentActivity.REQUEST_CODE && resultCode == Activity.RESULT_OK -> {
|
||||
val commentCount = data?.getIntExtra(CommentActivity.COMMENT_COUNT, 0) ?: 0
|
||||
val commentId = data?.getStringExtra(EntranceConsts.KEY_COMMENT_ID) ?: ""
|
||||
viewModel.updateComment(commentId, commentCount)
|
||||
}
|
||||
|
||||
requestCode == MoreFunctionPanelDialog.REQUEST_CODE && resultCode == Activity.RESULT_OK -> {
|
||||
getItemClickCallback().invoke(data?.getParcelableExtra(EntranceConsts.KEY_DATA))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getItemClickCallback(): (menuItem: MenuItemEntity?) -> Unit {
|
||||
return {
|
||||
when (it?.text) {
|
||||
getString(R.string.article_detail_more_edit_title) -> {
|
||||
val uri = Uri.Builder()
|
||||
.path(RouteConsts.activity.publishImageArticleActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_ENTRANCE, "图文详情")
|
||||
.build()
|
||||
ARouter.getInstance().build(uri)
|
||||
.withParcelable(
|
||||
EntranceConsts.KEY_IMAGE_ARTICLE_ENTITY,
|
||||
viewModel.imageArticleDetailEntity.value
|
||||
)
|
||||
.navigation()
|
||||
|
||||
NewLogUtils.logSharePanelClick(
|
||||
"click_modification",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_complaint_title) -> {
|
||||
ifLogin("图文详情") {
|
||||
BbsReportHelper.showReportDialog(BbsReportHelper.ImageArticleReporter(imageArticleId))
|
||||
}
|
||||
NewLogUtils.logSharePanelClick(
|
||||
"click_report",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_apply_select_title) -> {
|
||||
if (viewModel.imageArticleDetailEntity.value?.getSimplifyChoicenessStatus() == "apply") {
|
||||
ToastUtils.showToast("申请加精审核中")
|
||||
} else {
|
||||
viewModel.applyHighlightForImageArticle()
|
||||
NewLogUtils.logSharePanelClick(
|
||||
"click_apply_essence",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_select_title) -> {
|
||||
if (viewModel.imageArticleDetailEntity.value?.getSimplifyChoicenessStatus() == "apply") {
|
||||
ToastUtils.showToast("加精审核中")
|
||||
} else {
|
||||
showHighlightDialog(true)
|
||||
NewLogUtils.logSharePanelClick(
|
||||
"click_essence",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_unselect_title) -> {
|
||||
showHighlightDialog(false)
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_delete_title),
|
||||
getString(R.string.article_detail_more_hide_title) -> {
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
"提示",
|
||||
"${it.text}帖子后,其中的所有评论及回复都将被${it.text}",
|
||||
it.text,
|
||||
"取消",
|
||||
confirmClickCallback = {
|
||||
viewModel.deleteOrHideImageArticle()
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
NewLogUtils.logSharePanelClick(
|
||||
"click_delete",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_top_title) -> {
|
||||
// TopCommunityCategoryDialog.show(
|
||||
// childFragmentManager
|
||||
// ) { category ->
|
||||
// mViewModel.topCommunityArticle(category.id)
|
||||
// }
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_cancel_top_title) -> {
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
getString(R.string.article_detail_cancel_top_dialog_title),
|
||||
getString(R.string.article_detail_cancel_top_dialog_hint),
|
||||
getString(R.string.article_detail_cancel_top_dialog_confirm),
|
||||
getString(R.string.article_detail_cancel_top_dialog_cancel),
|
||||
confirmClickCallback = {
|
||||
// mViewModel.cancelTopCommunityArticle()
|
||||
},
|
||||
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showHighlightDialog(isHighlight: Boolean) {
|
||||
val imageArticle = viewModel.imageArticleDetailEntity.value ?: return
|
||||
var highlightDialogHintContent = ""
|
||||
val permissions = imageArticle.me.moderatorPermissions
|
||||
if ((isHighlight && permissions.choicenessImageArticle > Permissions.GUEST) ||
|
||||
(!isHighlight && permissions.cancelChoicenessImageArticle > Permissions.GUEST)
|
||||
) {
|
||||
highlightDialogHintContent =
|
||||
if ((isHighlight && permissions.choicenessImageArticle == Permissions.REPORTER) ||
|
||||
(!isHighlight && permissions.cancelChoicenessImageArticle == Permissions.REPORTER)
|
||||
) {
|
||||
"你的操作将提交给小编审核,确定提交吗?"
|
||||
} else {
|
||||
"你的操作将立即生效,确定提交吗?"
|
||||
}
|
||||
}
|
||||
val title = if (isHighlight) "加精帖子" else "取消精选"
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
title,
|
||||
highlightDialogHintContent,
|
||||
"确定",
|
||||
"取消",
|
||||
{
|
||||
viewModel.addHighlight(isHighlight)
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val HIDE_BANNER_NUMBER_INDICATOR = 1
|
||||
private const val SHOW_NUMBER_INDICATOR_DURATION = 5000L
|
||||
private const val SHOW_DOT_INDICATOR_MIN = 2
|
||||
private const val BANNER_RADIO_MIN = 0.5F
|
||||
private const val BANNER_RADIO_MAX = 1.33F
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,166 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.LazyFragment
|
||||
import com.gh.gamecenter.common.baselist.PageLoader
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.utils.DialogHelper
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toResString
|
||||
import com.gh.gamecenter.databinding.FragmentImageArticleDraftBinding
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDraftAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.ImageArticleDraftViewModel
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.PublishImageArticleActivityViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class ImageArticleDraftFragment : LazyFragment() {
|
||||
|
||||
private val viewModel by viewModels<ImageArticleDraftViewModel>()
|
||||
private val activityViewModel by activityViewModels<PublishImageArticleActivityViewModel>()
|
||||
|
||||
private lateinit var binding: FragmentImageArticleDraftBinding
|
||||
|
||||
private var isFromPublishPage = false
|
||||
|
||||
private val adapter by lazy {
|
||||
ImageArticleDraftAdapter(requireContext(), viewModel)
|
||||
}
|
||||
|
||||
override fun getRealLayoutId(): Int {
|
||||
return R.layout.fragment_image_article_draft
|
||||
}
|
||||
|
||||
override fun onRealLayoutInflated(inflatedView: View) {
|
||||
binding = FragmentImageArticleDraftBinding.bind(inflatedView)
|
||||
}
|
||||
|
||||
override fun initRealView() {
|
||||
super.initRealView()
|
||||
isFromPublishPage = arguments?.getBoolean(KEY_IS_FROM_PUBLISH_PAGE) ?: false
|
||||
binding.rvDrafts.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
|
||||
binding.rvDrafts.addItemDecoration(MyItemDecoration())
|
||||
binding.rvDrafts.adapter = adapter
|
||||
|
||||
binding.srlRefresh.setOnRefreshListener {
|
||||
viewModel.loadDraft(true)
|
||||
}
|
||||
|
||||
with(viewModel) {
|
||||
pageState.observe(viewLifecycleOwner) {
|
||||
|
||||
binding.srlRefresh.goneIf(
|
||||
it == PageLoader.PageState.PageNoData || it == PageLoader.PageState.PageInitFailure
|
||||
) {
|
||||
binding.srlRefresh.isRefreshing = false
|
||||
}
|
||||
binding.reuseLlLoading.root.goneIf(it != PageLoader.PageState.PageInitLoading)
|
||||
binding.reuseNoneData.root.goneIf(it != PageLoader.PageState.PageNoData)
|
||||
binding.reuseDataException.root.goneIf(it != PageLoader.PageState.PageInitFailure)
|
||||
|
||||
}
|
||||
|
||||
drafts.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(it)
|
||||
}
|
||||
|
||||
showDeleteDraftDialogAction.observe(viewLifecycleOwner, EventObserver {
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
R.string.warning.toResString(),
|
||||
R.string.delete_image_article_warning.toResString(),
|
||||
com.gh.gamecenter.core.R.string.confirm.toResString(),
|
||||
com.gh.gamecenter.common.R.string.cancel.toResString(),
|
||||
confirmClickCallback = {
|
||||
viewModel.deleteDraft(it)
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
})
|
||||
|
||||
publishImageArticleDestination.observe(viewLifecycleOwner, EventObserver {
|
||||
it.isDraft = true
|
||||
if (isFromPublishPage) {
|
||||
// 如果是从发布页进入草稿箱,则回到发布页,并将草稿数据回传
|
||||
activityViewModel.setEditImageArticle(it)
|
||||
activity?.onBackPressedDispatcher?.onBackPressed()
|
||||
} else {
|
||||
// 否则,直接打开新的发布页
|
||||
val uri = Uri.Builder()
|
||||
.path(RouteConsts.activity.publishImageArticleActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_ENTRANCE, "图文草稿")
|
||||
.build()
|
||||
ARouter.getInstance().build(uri)
|
||||
.withParcelable(EntranceConsts.KEY_IMAGE_ARTICLE_ENTITY, it)
|
||||
.navigation()
|
||||
}
|
||||
})
|
||||
|
||||
loadDraft(false)
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
if (changed is EBImageArticleChanged.DataCreated
|
||||
&& changed.draftId.isNotBlank()
|
||||
) {
|
||||
// 如果时选择的草稿发布,则删除当前选中草稿
|
||||
val draftList = viewModel.drafts.value?.toMutableList()
|
||||
if (draftList != null) {
|
||||
val hasRemoved = draftList.removeAll { it.id == changed.draftId }
|
||||
if (hasRemoved) {
|
||||
if (draftList.isEmpty()) {
|
||||
viewModel.loadDraft(true)
|
||||
} else {
|
||||
adapter.submitList(null)
|
||||
adapter.notifyDataSetChanged()
|
||||
viewModel.updateDrafts(draftList)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyItemDecoration : RecyclerView.ItemDecoration() {
|
||||
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
val layoutParams = view.layoutParams
|
||||
if (layoutParams is StaggeredGridLayoutManager.LayoutParams) {
|
||||
val spanIndex = layoutParams.spanIndex
|
||||
val (left, right) = if (spanIndex == 0) {
|
||||
8F.dip2px() to 2F.dip2px()
|
||||
} else {
|
||||
2F.dip2px() to 8F.dip2px()
|
||||
}
|
||||
outRect.left = left
|
||||
outRect.right = right
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val KEY_IS_FROM_PUBLISH_PAGE = "key_is_from_publish_page"
|
||||
|
||||
fun newInstance(isFromPublishPage: Boolean) =
|
||||
ImageArticleDraftFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putBoolean(KEY_IS_FROM_PUBLISH_PAGE, isFromPublishPage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,282 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.ethanhua.skeleton.Skeleton
|
||||
import com.gh.common.exposure.ExposureListener
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.LazyFragment
|
||||
import com.gh.gamecenter.common.baselist.PageLoader
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.tryToClearRecycler
|
||||
import com.gh.gamecenter.databinding.FragmentImageArticleHomeBinding
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleFooterWrapperAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.RecommendHomeAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.ImageArticleHomeViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class ImageArticleHomeFragment : LazyFragment() {
|
||||
|
||||
private val viewModel: ImageArticleHomeViewModel by viewModels()
|
||||
|
||||
private lateinit var binding: FragmentImageArticleHomeBinding
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
private var isFirstVisible = true
|
||||
|
||||
private val skeletonScreen by lazy {
|
||||
Skeleton.bind(binding.flSkeleton)
|
||||
.shimmer(true)
|
||||
.angle(Constants.SHIMMER_ANGLE)
|
||||
.color(com.gh.gamecenter.common.R.color.ui_skeleton_highlight)
|
||||
.duration(Constants.SHIMMER_DURATION)
|
||||
.maskWidth(Constants.MASK_WIDTH)
|
||||
.gradientCenterColorWidth(Constants.GRADIENT_CENTER_COLOR_WIDTH)
|
||||
.load(R.layout.fragment_image_article_home_skeleton)
|
||||
.show()
|
||||
}
|
||||
|
||||
private val adapter by lazy {
|
||||
RecommendHomeAdapter(requireContext(), viewModel)
|
||||
}
|
||||
|
||||
override fun getRealLayoutId(): Int = R.layout.fragment_image_article_home
|
||||
|
||||
override fun onRealLayoutInflated(inflatedView: View) {
|
||||
binding = FragmentImageArticleHomeBinding.bind(inflatedView)
|
||||
}
|
||||
|
||||
override fun onFragmentResume() {
|
||||
super.onFragmentResume()
|
||||
NewLogUtils.logRecommendFeedEvent("view_for_you_feed")
|
||||
}
|
||||
|
||||
override fun initRealView() {
|
||||
super.initRealView()
|
||||
isFirstVisible = false
|
||||
binding.rvRecommends.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL).also {
|
||||
it.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_NONE
|
||||
}
|
||||
binding.rvRecommends.adapter = adapter
|
||||
binding.rvRecommends.addItemDecoration(MyItemDecoration())
|
||||
|
||||
binding.srlRefresh.setOnRefreshListener {
|
||||
viewModel.pageLoader.pullToRefresh()
|
||||
}
|
||||
|
||||
binding.reuseNoConnection.connectionReloadTv.setOnClickListener {
|
||||
viewModel.initLoad()
|
||||
}
|
||||
|
||||
val exposureListener = ExposureListener(this, adapter)
|
||||
binding.rvRecommends.addOnScrollListener(exposureListener)
|
||||
binding.rvRecommends.addOnScrollListener(object : OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
val layoutManager = binding.rvRecommends.layoutManager
|
||||
if (layoutManager is StaggeredGridLayoutManager) {
|
||||
val itemPositions = layoutManager.findLastCompletelyVisibleItemPositions(null)
|
||||
val lastCompletePosition = itemPositions.maxOrNull() ?: -1
|
||||
val position = if (lastCompletePosition != -1) {
|
||||
lastCompletePosition
|
||||
} else {
|
||||
val itemVisible = layoutManager.findLastVisibleItemPositions(null)
|
||||
itemVisible.maxOrNull() ?: 0
|
||||
}
|
||||
NewLogUtils.logRecommendFeedSlide(position + 1)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
with(viewModel) {
|
||||
pageLoader.pageState.observe(viewLifecycleOwner) {
|
||||
if (it == PageLoader.PageState.PageInitLoading) {
|
||||
skeletonScreen
|
||||
} else {
|
||||
skeletonScreen.hide()
|
||||
}
|
||||
|
||||
if (it is PageLoader.PageState.PagePullToRefreshLoading) {
|
||||
// 正在下拉刷新,页面保持不变
|
||||
binding.srlRefresh.isRefreshing = true
|
||||
} else {
|
||||
binding.reuseNoneData.root.goneIf(it != PageLoader.PageState.PageNoData)
|
||||
binding.reuseNoConnection.root.goneIf(it != PageLoader.PageState.PageInitFailure)
|
||||
|
||||
binding.srlRefresh.isEnabled = it != PageLoader.PageState.PageInitLoading
|
||||
&& it != PageLoader.PageState.PageInitFailure
|
||||
binding.srlRefresh.isRefreshing = false
|
||||
}
|
||||
|
||||
if (it is PageLoader.PageState.PageLoadMoreReady
|
||||
&& (it.previousState is PageLoader.PageState.PagePullToRefreshLoading
|
||||
|| it.previousState is PageLoader.PageState.PageInitLoading)
|
||||
) {
|
||||
// 加载第一页完成
|
||||
if (it.previousState is PageLoader.PageState.PagePullToRefreshLoading) {
|
||||
// 下拉刷新成功,先清空上一次内容
|
||||
adapter.submitList(null)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
// 延时一下,检查第一页数据是否已铺满第一页,如果未铺满,则直接请求下一页
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
handler.postDelayed({
|
||||
checkIfLoadNextPage(binding.rvRecommends, viewModel::loadMore)
|
||||
}, 16)
|
||||
}
|
||||
adapter.setPageState(it)
|
||||
|
||||
}
|
||||
|
||||
pageLoader.dataList.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(it)
|
||||
}
|
||||
|
||||
imageDetailDestination.observe(viewLifecycleOwner, EventObserver {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, it.id)
|
||||
.appendQueryParameter(EntranceConsts.KEY_SOURCE_ENTRANCE, "社区-推荐信息流")
|
||||
.appendQueryParameter(EntranceConsts.KEY_RECOMMEND_ID, it.recommendId)
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
})
|
||||
|
||||
initLoad()
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
if (isFirstVisible) {
|
||||
return
|
||||
}
|
||||
when (changed) {
|
||||
is EBImageArticleChanged.VoteChanged -> {
|
||||
viewModel.voteChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataChanged -> {
|
||||
viewModel.itemChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataDeleted -> {
|
||||
itemDeleted(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataCreated -> {
|
||||
itemCreated(changed)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun itemCreated(changed: EBImageArticleChanged.DataCreated) {
|
||||
val newData = viewModel.pageLoader.dataList.value?.toMutableList() ?: mutableListOf()
|
||||
if (newData.isEmpty()) {
|
||||
viewModel.initLoad()
|
||||
} else {
|
||||
// 瀑布流布局,在中间添加或者移除item时,会出现错位的现象,这里需要先将原来的数据清空,在重新添加可以避免这个问题
|
||||
adapter.submitList(null)
|
||||
newData.add(0, changed.imageArticle)
|
||||
viewModel.pageLoader.updateData(newData)
|
||||
}
|
||||
}
|
||||
|
||||
private fun itemDeleted(changed: EBImageArticleChanged.DataDeleted) {
|
||||
val oldData = viewModel.pageLoader.dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val hasRemoved = newData.removeAll {
|
||||
it.id == changed.imageArticleId
|
||||
}
|
||||
if (hasRemoved) {
|
||||
if (newData.isEmpty()) {
|
||||
viewModel.initLoad()
|
||||
} else {
|
||||
adapter.submitList(null)
|
||||
viewModel.pageLoader.updateData(newData)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
isFirstVisible = true
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
if (::binding.isInitialized) {
|
||||
binding.rvRecommends.tryToClearRecycler()
|
||||
binding.rvRecommends.recycledViewPool.clear()
|
||||
adapter.onDarkModeChanged()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val KEY_IS_IN_MY_PUBLISH = "key_is_in_my_publish"
|
||||
|
||||
fun newInstance() = ImageArticleHomeFragment()
|
||||
|
||||
fun checkIfLoadNextPage(recyclerView: RecyclerView, loadNext: () -> Unit) {
|
||||
val layoutManager = recyclerView.layoutManager
|
||||
if (layoutManager is StaggeredGridLayoutManager) {
|
||||
val itemPositions = layoutManager.findLastVisibleItemPositions(null)
|
||||
val lastPosition = itemPositions.maxOrNull() ?: 0
|
||||
val itemType = recyclerView.adapter?.getItemViewType(lastPosition) ?: 0
|
||||
if (itemType == ImageArticleFooterWrapperAdapter.ITEM_TYPE_FOOTER) {
|
||||
// 底部加载更多的itemView显示在屏幕内,说明数据未铺满一屏:直接加载下一页
|
||||
loadNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyItemDecoration : RecyclerView.ItemDecoration() {
|
||||
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
val layoutParams = view.layoutParams
|
||||
if (layoutParams is StaggeredGridLayoutManager.LayoutParams) {
|
||||
if (parent.getChildAdapterPosition(view) == state.itemCount - 1) {
|
||||
layoutParams.isFullSpan = true
|
||||
} else {
|
||||
val spanIndex = layoutParams.spanIndex
|
||||
val (left, right) = if (spanIndex % 2 == 0) {
|
||||
8F.dip2px() to 2F.dip2px()
|
||||
} else {
|
||||
2F.dip2px() to 8F.dip2px()
|
||||
}
|
||||
outRect.left = left
|
||||
outRect.right = right
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,216 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.ethanhua.skeleton.Skeleton
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.LazyFragment
|
||||
import com.gh.gamecenter.common.baselist.PageLoader
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.databinding.FragmentImageArticleHomeBinding
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.MyImageArticleAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.fragment.ImageArticleHomeFragment.Companion.checkIfLoadNextPage
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.MyImageArticleListViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class MyImageArticleListFragment : LazyFragment() {
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
private val viewModel by viewModels<MyImageArticleListViewModel>()
|
||||
|
||||
private lateinit var binding: FragmentImageArticleHomeBinding
|
||||
|
||||
private val skeletonScreen by lazy {
|
||||
Skeleton.bind(binding.flSkeleton)
|
||||
.shimmer(true)
|
||||
.angle(Constants.SHIMMER_ANGLE)
|
||||
.color(com.gh.gamecenter.common.R.color.ui_skeleton_highlight)
|
||||
.duration(Constants.SHIMMER_DURATION)
|
||||
.maskWidth(Constants.MASK_WIDTH)
|
||||
.gradientCenterColorWidth(Constants.GRADIENT_CENTER_COLOR_WIDTH)
|
||||
.load(R.layout.fragment_image_article_home_skeleton)
|
||||
.show()
|
||||
}
|
||||
|
||||
private val adapter by lazy {
|
||||
MyImageArticleAdapter(requireContext(), viewModel)
|
||||
}
|
||||
|
||||
override fun getRealLayoutId(): Int = R.layout.fragment_image_article_home
|
||||
|
||||
override fun onRealLayoutInflated(inflatedView: View) {
|
||||
binding = FragmentImageArticleHomeBinding.bind(inflatedView)
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun initRealView() {
|
||||
super.initRealView()
|
||||
binding.rvRecommends.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
|
||||
binding.rvRecommends.adapter = adapter
|
||||
binding.rvRecommends.addItemDecoration(MyItemDecoration())
|
||||
|
||||
binding.srlRefresh.setOnRefreshListener {
|
||||
viewModel.pageLoader.pullToRefresh()
|
||||
}
|
||||
|
||||
binding.reuseNoConnection.connectionReloadTv.setOnClickListener {
|
||||
viewModel.initLoad()
|
||||
}
|
||||
|
||||
with(viewModel) {
|
||||
pageLoader.pageState.observe(viewLifecycleOwner) {
|
||||
if (it == PageLoader.PageState.PageInitLoading) {
|
||||
skeletonScreen
|
||||
} else {
|
||||
skeletonScreen.hide()
|
||||
}
|
||||
|
||||
if (it is PageLoader.PageState.PagePullToRefreshLoading) {
|
||||
// 正在下拉刷新,页面保持不变
|
||||
binding.srlRefresh.isRefreshing = true
|
||||
} else {
|
||||
binding.reuseNoneData.root.goneIf(it != PageLoader.PageState.PageNoData)
|
||||
binding.reuseNoConnection.root.goneIf(it != PageLoader.PageState.PageInitFailure)
|
||||
|
||||
binding.srlRefresh.isEnabled = it != PageLoader.PageState.PageInitLoading
|
||||
&& it != PageLoader.PageState.PageInitFailure
|
||||
binding.srlRefresh.isRefreshing = false
|
||||
}
|
||||
|
||||
if (it is PageLoader.PageState.PageLoadMoreReady
|
||||
&& (it.previousState is PageLoader.PageState.PagePullToRefreshLoading
|
||||
|| it.previousState is PageLoader.PageState.PageInitLoading)
|
||||
) {
|
||||
if (it.previousState is PageLoader.PageState.PagePullToRefreshLoading) {
|
||||
adapter.submitList(null)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
// 延时一下,检查第一页数据是否已铺满第一页,如果未铺满,则直接请求下一页
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
handler.postDelayed({
|
||||
checkIfLoadNextPage(binding.rvRecommends, viewModel::loadMore)
|
||||
}, 16)
|
||||
}
|
||||
adapter.setPageState(it)
|
||||
}
|
||||
|
||||
pageLoader.dataList.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(it)
|
||||
}
|
||||
|
||||
imageArticleDetailDestination.observe(viewLifecycleOwner, EventObserver {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, it)
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
})
|
||||
|
||||
initLoad()
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
when (changed) {
|
||||
is EBImageArticleChanged.VoteChanged -> {
|
||||
viewModel.voteChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataChanged -> {
|
||||
viewModel.itemChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataDeleted -> {
|
||||
itemDeleted(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataCreated -> {
|
||||
itemCreated(changed)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun itemCreated(changed: EBImageArticleChanged.DataCreated) {
|
||||
val newData = viewModel.pageLoader.dataList.value?.toMutableList() ?: mutableListOf()
|
||||
if (newData.isEmpty()) {
|
||||
viewModel.initLoad()
|
||||
} else {
|
||||
adapter.submitList(null)
|
||||
// 请注意:这一行代码不能省
|
||||
adapter.notifyDataSetChanged()
|
||||
newData.add(0, changed.imageArticle.toPersonHistoryEntity())
|
||||
viewModel.pageLoader.updateData(newData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun itemDeleted(changed: EBImageArticleChanged.DataDeleted) {
|
||||
val oldData = viewModel.pageLoader.dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val hasRemoved = newData.removeAll {
|
||||
it.id == changed.imageArticleId
|
||||
}
|
||||
if (hasRemoved) {
|
||||
adapter.submitList(null)
|
||||
adapter.notifyDataSetChanged()
|
||||
if (newData.isEmpty()) {
|
||||
viewModel.initLoad()
|
||||
} else {
|
||||
viewModel.pageLoader.updateData(newData)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance() = MyImageArticleListFragment()
|
||||
}
|
||||
|
||||
private class MyItemDecoration : RecyclerView.ItemDecoration() {
|
||||
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
val layoutParams = view.layoutParams
|
||||
if (layoutParams is StaggeredGridLayoutManager.LayoutParams) {
|
||||
if (parent.getChildAdapterPosition(view) == state.itemCount - 1) {
|
||||
layoutParams.isFullSpan = true
|
||||
} else {
|
||||
val spanIndex = layoutParams.spanIndex
|
||||
val (left, right) = if (spanIndex % 2 == 0) {
|
||||
8F.dip2px() to 2F.dip2px()
|
||||
} else {
|
||||
2F.dip2px() to 8F.dip2px()
|
||||
}
|
||||
outRect.left = left
|
||||
outRect.right = right
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,525 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.Editable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener
|
||||
import android.widget.EditText
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.ACTION_STATE_IDLE
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.ErrorHelper
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.BaseFragment
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.databinding.FragmentPublishImageArticleBinding
|
||||
import com.gh.gamecenter.entity.ForumDetailEntity
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageAndTextAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.PublishImageArticleActivityViewModel
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.PublishImageArticleViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.gh.gamecenter.qa.dialog.ChooseForumActivity
|
||||
import com.gh.gamecenter.qa.dialog.ChooseSectionDialogFragment
|
||||
import com.lightgame.listeners.OnBackPressedListener
|
||||
import com.lightgame.utils.Util_System_Keyboard
|
||||
|
||||
class PublishImageArticleFragment : BaseFragment<Unit>(), OnBackPressedListener {
|
||||
|
||||
private val activityViewModel by activityViewModels<PublishImageArticleActivityViewModel>()
|
||||
private val viewModel by viewModels<PublishImageArticleViewModel>()
|
||||
|
||||
private lateinit var binding: FragmentPublishImageArticleBinding
|
||||
|
||||
private val rootView: View?
|
||||
get() = activity?.findViewById(android.R.id.content)
|
||||
|
||||
private val itemTouchHelper by lazy {
|
||||
ItemTouchHelper(MyItemTouchCallback(activityViewModel))
|
||||
}
|
||||
|
||||
private val adapter by lazy {
|
||||
ImageAndTextAdapter(viewModel) {
|
||||
itemTouchHelper.startDrag(it)
|
||||
}
|
||||
}
|
||||
|
||||
private val savingDraftLoading by lazy {
|
||||
DialogHelper.getProgressDialog(requireContext(), R.string.draft_saving.toResString())
|
||||
}
|
||||
|
||||
private val publishingLoading by lazy {
|
||||
DialogHelper.getProgressDialog(requireContext(), R.string.image_article_publishing.toResString())
|
||||
}
|
||||
|
||||
override fun getInflatedLayout(): View {
|
||||
return View(requireContext())
|
||||
}
|
||||
|
||||
private val onGlobalLayoutListener = OnGlobalLayoutListener {
|
||||
onKeyboardChanged()
|
||||
}
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
private var isKeyBoardShow = false
|
||||
|
||||
private lateinit var chooseForumLauncher: ActivityResultLauncher<String>
|
||||
|
||||
override fun getLayoutId(): Int = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
chooseForumLauncher = registerForActivityResult<String, CommunityEntity?>(object :
|
||||
ActivityResultContract<String, CommunityEntity?>() {
|
||||
|
||||
override fun createIntent(context: Context, input: String): Intent {
|
||||
val intent = Intent(context, ChooseForumActivity::class.java)
|
||||
intent.putExtra(EntranceConsts.KEY_SOURCE_ENTRANCE, input)
|
||||
return intent
|
||||
}
|
||||
|
||||
override fun parseResult(resultCode: Int, intent: Intent?): CommunityEntity? {
|
||||
return intent?.getParcelableExtra(EntranceConsts.KEY_COMMUNITY_DATA)
|
||||
}
|
||||
}
|
||||
) { result -> result?.let(viewModel::changeLinkBbs) }
|
||||
|
||||
activityViewModel.editImageArticle.observe(this, EventObserver {
|
||||
viewModel.setEditImageArticle(it)
|
||||
})
|
||||
|
||||
activityViewModel.community.observe(this, EventObserver {
|
||||
viewModel.changeLinkBbs(it)
|
||||
})
|
||||
}
|
||||
|
||||
override fun initView(view: View?) = Unit
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return FragmentPublishImageArticleBinding.inflate(inflater, container, false)
|
||||
.also {
|
||||
binding = it
|
||||
}.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
view.post {
|
||||
setContentHeight(0)
|
||||
}
|
||||
|
||||
|
||||
binding.rvImages.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
binding.rvImages.addItemDecoration(MyItemDecoration())
|
||||
binding.rvImages.adapter = adapter
|
||||
itemTouchHelper.attachToRecyclerView(binding.rvImages)
|
||||
|
||||
binding.etTitle.addTextChangedListener { text ->
|
||||
if (text != null) {
|
||||
checkMaxLimitReached(binding.etTitle, text, TITLE_MAX_LENGTH, R.string.image_and_text_title_limit)
|
||||
var remainingSize = TITLE_MAX_LENGTH - text.length
|
||||
if (remainingSize < 0) {
|
||||
remainingSize = 0
|
||||
}
|
||||
binding.tvRemainingWords.text = "$remainingSize"
|
||||
}
|
||||
binding.ivClear.visibleIf(!text.isNullOrBlank() && binding.etTitle.hasFocus())
|
||||
}
|
||||
|
||||
binding.etTitle.setOnFocusChangeListener { _, hasFocus ->
|
||||
binding.ivClear.visibleIf(hasFocus && binding.etTitle.text.isNotBlank())
|
||||
binding.tvRemainingWords.visibleIf(hasFocus)
|
||||
}
|
||||
|
||||
binding.tvSelectBbs.setOnClickListener {
|
||||
showSelectBbsDialog()
|
||||
}
|
||||
|
||||
binding.ivClear.setOnClickListener {
|
||||
binding.etTitle.text = null
|
||||
}
|
||||
|
||||
binding.vCloseDragTips.setOnClickListener {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
binding.gDragTips.goneIf(true)
|
||||
}
|
||||
|
||||
binding.etContent.addTextChangedListener { text ->
|
||||
if (text != null) {
|
||||
checkMaxLimitReached(binding.etContent, text, CONTENT_MAX_LENGTH, R.string.image_and_text_content_limit)
|
||||
}
|
||||
}
|
||||
|
||||
binding.tvBbsName.setOnClickListener {
|
||||
showSelectBbsDialog()
|
||||
}
|
||||
|
||||
binding.tvSubSection.setOnClickListener {
|
||||
showSelectSubSectionDialog()
|
||||
}
|
||||
|
||||
binding.vClearBbs.setOnClickListener {
|
||||
if (viewModel.isCreating) {
|
||||
viewModel.changeLinkBbs(null)
|
||||
} else {
|
||||
viewModel.changeLinkSection(null)
|
||||
toast(R.string.cannot_be_modified_after_publishing)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
binding.tvDraftBox.setOnClickListener {
|
||||
activityViewModel.navigateToDraftBox()
|
||||
}
|
||||
|
||||
binding.tvPublish.setOnClickListener {
|
||||
publish()
|
||||
}
|
||||
|
||||
activityViewModel.localImages.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(it)
|
||||
}
|
||||
|
||||
activityViewModel.showDragTipsAction.observe(viewLifecycleOwner, EventObserver {
|
||||
// 倒计时开始,5s 后消失
|
||||
binding.gDragTips.visibleIf(true)
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
handler.postDelayed({
|
||||
binding.gDragTips.goneIf(true)
|
||||
}, DRAG_TIPS_SHOW_DURATION)
|
||||
|
||||
})
|
||||
|
||||
with(viewModel) {
|
||||
|
||||
chooseImageAction.observe(viewLifecycleOwner, EventObserver {
|
||||
activityViewModel.chooseImage()
|
||||
})
|
||||
|
||||
removeImageAction.observe(viewLifecycleOwner, EventObserver {
|
||||
activityViewModel.removeImage(it)
|
||||
})
|
||||
|
||||
linkBbs.observe(viewLifecycleOwner) {
|
||||
updateLinkBbs(it)
|
||||
}
|
||||
|
||||
draftCreated.observe(viewLifecycleOwner, EventObserver {
|
||||
if (savingDraftLoading.isShowing) {
|
||||
savingDraftLoading.dismiss()
|
||||
}
|
||||
val toastText = if (it) {
|
||||
R.string.save_draft_successfully.toResString()
|
||||
} else {
|
||||
R.string.save_draft_failure.toResString()
|
||||
}
|
||||
ToastUtils.showToast(toastText)
|
||||
if (it) {
|
||||
activity?.finish()
|
||||
}
|
||||
})
|
||||
|
||||
imageTextPublished.observe(viewLifecycleOwner, EventObserver { (success, errorString) ->
|
||||
if (publishingLoading.isShowing) {
|
||||
publishingLoading.dismiss()
|
||||
}
|
||||
|
||||
if (success) {
|
||||
ToastUtils.showToast(R.string.publish_image_article_successfully.toResString())
|
||||
activity?.setResult(Activity.RESULT_OK)
|
||||
activity?.finish()
|
||||
} else {
|
||||
ErrorHelper.handleError(requireContext(), errorString, false, "发布图文", "社区实名", "图文") {
|
||||
publish()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
editImageArticle.observe(viewLifecycleOwner, EventObserver {
|
||||
fillUiByDraft(it)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun fillUiByDraft(imageArticle: ImageArticleEntity) {
|
||||
binding.etTitle.setText(imageArticle.title)
|
||||
binding.etContent.setText(imageArticle.content)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内容输入框的高度
|
||||
*/
|
||||
private fun setContentHeight(keyboardHeight: Int) {
|
||||
val rootHeight = binding.root.height
|
||||
val remainHeight =
|
||||
if (keyboardHeight > 0) {
|
||||
rootHeight - 116F.dip2px() - 50F.dip2px() - 50F.dip2px() - keyboardHeight
|
||||
} else {
|
||||
rootHeight - 116F.dip2px() - 50F.dip2px() - 60F.dip2px() - 50F.dip2px()
|
||||
}
|
||||
|
||||
val contentHeight = if (remainHeight > 360F.dip2px()) {
|
||||
360F.dip2px()
|
||||
} else {
|
||||
remainHeight
|
||||
}
|
||||
binding.etContent.updateLayoutParams {
|
||||
height = contentHeight
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDraft() {
|
||||
if (!savingDraftLoading.isShowing) {
|
||||
savingDraftLoading.show()
|
||||
}
|
||||
val title = binding.etTitle.text?.toString() ?: ""
|
||||
val content = binding.etContent.text?.toString() ?: ""
|
||||
val images = activityViewModel.localImages.value ?: emptyList()
|
||||
viewModel.createOrEditDraft(title, content, images)
|
||||
}
|
||||
|
||||
private fun publish() {
|
||||
if (!publishingLoading.isShowing) {
|
||||
publishingLoading.show()
|
||||
}
|
||||
val title = binding.etTitle.text?.toString() ?: ""
|
||||
val content = binding.etContent.text?.toString() ?: ""
|
||||
val images = activityViewModel.localImages.value ?: emptyList()
|
||||
viewModel.publishImageText(title, content, images)
|
||||
}
|
||||
|
||||
private fun updateLinkBbs(linkBbs: PublishImageArticleViewModel.LinkBbs) {
|
||||
if (linkBbs.communityEntity == null) {
|
||||
// 还没有关联论坛
|
||||
binding.tvSelectBbs.visibleIf(true)
|
||||
binding.gBbsSelected.visibleIf(false)
|
||||
} else {
|
||||
// 已关联论坛
|
||||
binding.tvSelectBbs.visibleIf(false)
|
||||
binding.gBbsSelected.visibleIf(true)
|
||||
binding.ivBbsIcon.displayGameIcon(linkBbs.communityEntity.icon, null, null)
|
||||
binding.tvBbsName.text = linkBbs.communityEntity.name
|
||||
if (linkBbs.selectedSection == null) {
|
||||
// 还没有选择子模块
|
||||
|
||||
if (linkBbs.hasSection) {
|
||||
// 有子模块
|
||||
binding.tvSubSection.visibleIf(true)
|
||||
binding.ivBbsArrRight.visibleIf(true)
|
||||
binding.tvSubSection.text = ""
|
||||
} else {
|
||||
// 没有子模块
|
||||
binding.tvSubSection.visibleIf(false)
|
||||
binding.ivBbsArrRight.visibleIf(false)
|
||||
}
|
||||
} else {
|
||||
binding.tvSubSection.text = linkBbs.selectedSection.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkMaxLimitReached(editText: EditText, text: Editable, maxLength: Int, toastResId: Int) {
|
||||
if (text.length > maxLength) {
|
||||
editText.setText(text.subSequence(0, maxLength))
|
||||
editText.setSelection(maxLength) // 将光标移动到文本末尾
|
||||
ToastUtils.showToast(toastResId.toResString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun onKeyboardChanged() {
|
||||
val rect = Rect()
|
||||
rootView?.let {
|
||||
it.getWindowVisibleDisplayFrame(rect)
|
||||
val screenHeight = it.height
|
||||
val keyboardHeight = screenHeight - rect.bottom
|
||||
if (keyboardHeight > screenHeight * 0.15) {
|
||||
// 键盘弹起
|
||||
if (!isKeyBoardShow) {
|
||||
isKeyBoardShow = true
|
||||
|
||||
// 当软键盘弹起时,必须要保证EditText的光标和内容不被挡住
|
||||
setContentHeight(keyboardHeight)
|
||||
}
|
||||
|
||||
} else {
|
||||
// 键盘隐藏
|
||||
if (isKeyBoardShow) {
|
||||
isKeyBoardShow = false
|
||||
setContentHeight(0)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun showSelectBbsDialog() {
|
||||
if (viewModel.isCreating) {
|
||||
val delayTime = if (isKeyBoardShow) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(requireActivity())
|
||||
200L
|
||||
} else 0L
|
||||
AppExecutor.uiExecutor.executeWithDelay({
|
||||
chooseForumLauncher.launch("社区")
|
||||
NewLogUtils.logChooseForumPanelEnter("发图文")
|
||||
}, delayTime)
|
||||
} else {
|
||||
toast(R.string.cannot_be_modified_after_publishing)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSelectSubSectionDialog() {
|
||||
val delayTime = if (isKeyBoardShow) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(requireActivity())
|
||||
200L
|
||||
} else 0L
|
||||
AppExecutor.uiExecutor.executeWithDelay({
|
||||
ChooseSectionDialogFragment.show(
|
||||
requireActivity() as AppCompatActivity,
|
||||
viewModel.linkBbs.value?.communityEntity?.id ?: "",
|
||||
viewModel.linkBbs.value?.selectedSection?.id ?: "",
|
||||
viewModel.isModerator,
|
||||
tag ?: ""
|
||||
)
|
||||
}, delayTime)
|
||||
}
|
||||
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
requireActivity().findViewById<View>(android.R.id.content)?.viewTreeObserver?.addOnGlobalLayoutListener(
|
||||
onGlobalLayoutListener
|
||||
)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
requireActivity().findViewById<View>(android.R.id.content)?.viewTreeObserver?.removeOnGlobalLayoutListener(
|
||||
onGlobalLayoutListener
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
override fun onHandleBackPressed(): Boolean {
|
||||
showSaveDraftDialog()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun showSaveDraftDialog() {
|
||||
SensorsBridge.trackEvent("ArticleCancelDialogShow")
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
com.gh.gamecenter.common.R.string.miui_optimization_warning_dialog_title.toResString(),
|
||||
R.string.save_to_draft_box_and_exit.toResString(),
|
||||
confirmText = R.string.save_and_exit.toResString(),
|
||||
cancelText = R.string.do_not_save.toResString(),
|
||||
confirmClickCallback = {
|
||||
SensorsBridge.trackEvent("ArticleCancelDialogClick", "button_name", "保存并退出")
|
||||
createDraft()
|
||||
},
|
||||
cancelClickCallback = {
|
||||
SensorsBridge.trackEvent("ArticleCancelDialogClick", "button_name", "不保存")
|
||||
activity?.finish()
|
||||
},
|
||||
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == ChooseSectionDialogFragment.REQUEST_CODE) {
|
||||
val section = data?.getParcelableExtra<ForumDetailEntity.Section>(EntranceConsts.KEY_DATA)
|
||||
if (section != null) {
|
||||
viewModel.changeLinkSection(section)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val TITLE_MAX_LENGTH = 20
|
||||
private const val CONTENT_MAX_LENGTH = 1000
|
||||
private const val DRAG_TIPS_SHOW_DURATION = 5000L
|
||||
|
||||
fun newInstance() = PublishImageArticleFragment()
|
||||
}
|
||||
|
||||
private class MyItemTouchCallback(
|
||||
private val viewModel: PublishImageArticleActivityViewModel
|
||||
) : ItemTouchHelper.Callback() {
|
||||
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
|
||||
return makeMovementFlags(ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT, 1)
|
||||
}
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
val adapter = recyclerView.adapter as? ImageAndTextAdapter
|
||||
if (adapter != null) {
|
||||
val position = viewHolder.bindingAdapterPosition
|
||||
val targetPosition = target.bindingAdapterPosition
|
||||
val targetItem = adapter.getItem(targetPosition)
|
||||
if (targetItem.id != ImageAndTextAdapter.INVALID_ID) {
|
||||
viewModel.swap(position, targetPosition)
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun isLongPressDragEnabled(): Boolean = true
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit
|
||||
|
||||
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
||||
super.onSelectedChanged(viewHolder, actionState)
|
||||
if (actionState == ACTION_STATE_IDLE) {
|
||||
// 拖拽完毕,刷新数据:将第一位的图片设为封面
|
||||
viewModel.refreshImages()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyItemDecoration : RecyclerView.ItemDecoration() {
|
||||
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
outRect.left = if (parent.getChildAdapterPosition(view) == 0) {
|
||||
0
|
||||
} else {
|
||||
4F.dip2px()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,118 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.baselist.LoadType
|
||||
import com.gh.gamecenter.common.baselist.PageLoader
|
||||
import com.gh.gamecenter.common.utils.toArrayList
|
||||
import com.gh.gamecenter.common.utils.toJson
|
||||
import com.gh.gamecenter.core.utils.GsonUtils
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.feature.entity.MeEntity
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleRepository
|
||||
import com.gh.gamecenter.qa.article.detail.CommentItemData
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
||||
class ImageArticleCommentViewModel(
|
||||
application: Application,
|
||||
imageArticleId: String,
|
||||
topCommentId: String
|
||||
) :
|
||||
BaseCommentViewModel(application, "", "", "", "", "", imageArticleId, topCommentId = topCommentId) {
|
||||
|
||||
private val repository = ImageArticleRepository.newInstance()
|
||||
|
||||
override fun provideDataObservable(page: Int): Observable<MutableList<CommentEntity>> {
|
||||
val map = hashMapOf<String, Any>()
|
||||
if (!isHandleTopComment && topCommentId.isNotEmpty()) {
|
||||
map["top_comment_id"] = topCommentId
|
||||
}
|
||||
return RetrofitManager.getInstance().api.getImageArticleComments(
|
||||
imageArticleId,
|
||||
currentSortType.value,
|
||||
page,
|
||||
map
|
||||
).map {
|
||||
mTotal = it.headers().get("total")?.toInt() ?: 0
|
||||
val type = object : TypeToken<List<CommentEntity>>() {}.type
|
||||
GsonUtils.gson.fromJson(it.body()?.toJson() ?: "", type)
|
||||
}
|
||||
}
|
||||
|
||||
override fun mergeResultLiveData() {
|
||||
mResultLiveData.addSource(mListLiveData) {
|
||||
mergeListData(mListLiveData.value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun mergeListData(commentList: List<CommentEntity>?, hasFilter: Boolean) {
|
||||
val mergedList = arrayListOf<CommentItemData>().apply {
|
||||
if (commentList.isNullOrEmpty() && mLoadStatusLiveData.value == LoadStatus.INIT_EMPTY) {
|
||||
add(CommentItemData(errorEmpty = true))
|
||||
} else if (commentList.isNullOrEmpty() && mLoadStatusLiveData.value == LoadStatus.INIT_FAILED) {
|
||||
add(CommentItemData(errorConnection = true))
|
||||
} else {
|
||||
commentList?.forEachIndexed { index, entity ->
|
||||
// 没有 me 会导致不能跨页面更新点赞
|
||||
if (entity.me == null) {
|
||||
entity.me = MeEntity()
|
||||
}
|
||||
handleTopComment(index, entity)
|
||||
add(CommentItemData(commentNormal = entity))
|
||||
}
|
||||
add(CommentItemData(footer = true))
|
||||
}
|
||||
}
|
||||
mResultLiveData.postValue(mergedList)
|
||||
}
|
||||
|
||||
fun insertNewestComment(newComment: CommentEntity) {
|
||||
val data = (mResultLiveData.value ?: emptyList()).toArrayList()
|
||||
val count = data.count { it.commentNormal != null }
|
||||
if (count == 0) {
|
||||
load(LoadType.REFRESH)
|
||||
return
|
||||
}
|
||||
when (currentSortType) {
|
||||
SortType.LATEST -> {
|
||||
val index = data.indexOfFirst { it.commentNormal != null }
|
||||
if (index >= 0) {
|
||||
mTotal++
|
||||
data.add(index, CommentItemData(commentNormal = newComment))
|
||||
mResultLiveData.postValue(data)
|
||||
} else {
|
||||
load(LoadType.REFRESH)
|
||||
}
|
||||
}
|
||||
|
||||
SortType.OLDEST -> {
|
||||
//根据total判断是否插入到最后
|
||||
if (count >= mTotal) {
|
||||
mTotal++
|
||||
val index = data.indexOfLast { it.commentNormal != null }
|
||||
data.add(index + 1, CommentItemData(commentNormal = newComment))
|
||||
mResultLiveData.postValue(data)
|
||||
} else {
|
||||
load(LoadType.REFRESH)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Factory(
|
||||
private val application: Application,
|
||||
private val imageArticleId: String,
|
||||
private val topCommentId: String
|
||||
) : ViewModelProvider.NewInstanceFactory() {
|
||||
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return ImageArticleCommentViewModel(application, imageArticleId, topCommentId) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,334 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.viewmodel
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Transformations
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.entity.ErrorEntity
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.observableToMain
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.common.utils.toObject
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.feature.entity.Permissions
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleRepository
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleUseCase
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel.SortType
|
||||
import io.reactivex.CompletableObserver
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.HttpException
|
||||
|
||||
class ImageArticleDetailViewModel : ViewModel() {
|
||||
|
||||
private val repository = ImageArticleRepository.newInstance()
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
var imageArticleId: String = ""
|
||||
|
||||
private val useCase = ImageArticleUseCase(repository, compositeDisposable)
|
||||
|
||||
private val _imageArticleDetailEntity = MutableLiveData<ImageArticleEntity>()
|
||||
val imageArticleDetailEntity: LiveData<ImageArticleEntity> = _imageArticleDetailEntity
|
||||
|
||||
val isUserFollowed: LiveData<Boolean> =
|
||||
Transformations.distinctUntilChanged(Transformations.map(imageArticleDetailEntity) {
|
||||
it.me.isFollower
|
||||
})
|
||||
|
||||
fun followUser() {
|
||||
val isFollowed = isUserFollowed.value ?: false
|
||||
val userId = imageArticleDetailEntity.value?.user?.id ?: ""
|
||||
SensorsBridge.trackUserFollowClick(
|
||||
userId = userId,
|
||||
userName = imageArticleDetailEntity.value?.user?.name ?: "",
|
||||
buttonName = if (isFollowed) "已关注" else "关注"
|
||||
)
|
||||
repository.followUser(!isFollowed, userId)
|
||||
.compose(observableToMain())
|
||||
.subscribe(object : Response<ResponseBody>() {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
compositeDisposable.add(d)
|
||||
}
|
||||
|
||||
override fun onResponse(response: ResponseBody?) {
|
||||
updateImageArticle {
|
||||
it.me.isFollower = !isFollowed
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
val commentCount: LiveData<Int> =
|
||||
Transformations.distinctUntilChanged(Transformations.map(imageArticleDetailEntity) {
|
||||
it.count.comment
|
||||
})
|
||||
|
||||
fun updateComment(commentId: String, commentCount: Int) {
|
||||
updateImageArticle {
|
||||
it.count.comment = commentCount
|
||||
}
|
||||
ImageArticleUseCase.notifyCommentChanged(imageArticleId, commentCount)
|
||||
if (commentId.isNotEmpty()) {
|
||||
insertNewestComment(commentId)
|
||||
}
|
||||
}
|
||||
|
||||
private val _insertNewestCommentAction = MutableLiveData<Event<CommentEntity>>()
|
||||
val insertNewestCommentAction: LiveData<Event<CommentEntity>> = _insertNewestCommentAction
|
||||
private fun insertNewestComment(commentId: String) {
|
||||
// 将刚刚评论的内容插入到评论列表中
|
||||
repository.getSingleCommentById(commentId)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<CommentEntity>() {
|
||||
override fun onSuccess(data: CommentEntity) {
|
||||
_insertNewestCommentAction.value = Event(data)
|
||||
}
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
val vote: LiveData<Pair<Boolean, Int>> =
|
||||
Transformations.distinctUntilChanged(Transformations.map(imageArticleDetailEntity) {
|
||||
it.me.isCommunityArticleVote to it.count.vote
|
||||
})
|
||||
|
||||
fun vote() {
|
||||
val isVoted = vote.value?.first ?: false
|
||||
useCase.voteImageArticle(imageArticleId, !isVoted)
|
||||
|
||||
val imageArticle = imageArticleDetailEntity.value ?: return
|
||||
SensorsBridge.trackArticleLikeClick(
|
||||
customerType = imageArticle.user.auth?.text ?: "",
|
||||
articleId = imageArticle.id,
|
||||
bbsId = imageArticle.community?.id ?: "",
|
||||
bbsType = imageArticle.community?.typeChinese ?: "综合论坛",
|
||||
activityTag = "",
|
||||
gameForumType = imageArticle.community?.game?.categoryChinese ?: "",
|
||||
articleType = "图文",
|
||||
buttonName = if (isVoted) "取消点赞" else "赞同"
|
||||
)
|
||||
}
|
||||
|
||||
private val _pageStatus = MutableLiveData<LoadStatus>()
|
||||
val pageStatus: LiveData<LoadStatus> = _pageStatus
|
||||
|
||||
fun loadImageArticleDetail(imageArticleId: String, recommendId: String) {
|
||||
_pageStatus.value = LoadStatus.INIT_LOADING
|
||||
this.imageArticleId = imageArticleId
|
||||
repository.loadImageArticleDetail(imageArticleId)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ImageArticleEntity>() {
|
||||
override fun onSuccess(data: ImageArticleEntity) {
|
||||
_pageStatus.value = LoadStatus.INIT_LOADED
|
||||
setImageArticle(data)
|
||||
NewLogUtils.logForumContentBrowser(imageArticleId, "bbs_article", recommendId)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
val error =
|
||||
(exception as? HttpException)?.response()?.errorBody()?.string()?.toObject<ErrorEntity>()
|
||||
if (error != null && error.code == 404001) {
|
||||
_pageStatus.value = LoadStatus.INIT_EMPTY
|
||||
} else {
|
||||
_pageStatus.value = LoadStatus.INIT_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
private val _sortType = MutableLiveData<Event<SortType>>()
|
||||
val sortType: LiveData<Event<SortType>> = _sortType
|
||||
fun changeSort(newSort: SortType) {
|
||||
_sortType.value = Event(newSort)
|
||||
}
|
||||
|
||||
val isBbsFollowed: LiveData<Boolean> =
|
||||
Transformations.distinctUntilChanged(Transformations.map(imageArticleDetailEntity) {
|
||||
it.community?.isFollowed ?: false
|
||||
})
|
||||
|
||||
fun followBbs(communityId: String) {
|
||||
val isFollowed = isBbsFollowed.value ?: false
|
||||
repository.followBbs(communityId, !isFollowed)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
updateImageArticle {
|
||||
it.community?.isFollowed = !isFollowed
|
||||
}
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
val isFavorite: LiveData<Boolean> =
|
||||
Transformations.distinctUntilChanged(Transformations.map(imageArticleDetailEntity) {
|
||||
it.me.isFavorite
|
||||
})
|
||||
|
||||
fun collect() {
|
||||
val imageArticleId = imageArticleId
|
||||
val isCollected = isFavorite.value ?: false
|
||||
repository.collect(imageArticleId, !isCollected)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : CompletableObserver {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
compositeDisposable.add(d)
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
updateImageArticle {
|
||||
it.me.isFavorite = !isCollected
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) = Unit
|
||||
|
||||
})
|
||||
|
||||
val imageArticle = imageArticleDetailEntity.value ?: return
|
||||
SensorsBridge.trackArticleCollectionClick(
|
||||
customerType = imageArticle.user.auth?.text ?: "",
|
||||
articleId = imageArticle.id,
|
||||
bbsId = imageArticle.community?.id ?: "",
|
||||
bbsType = imageArticle.community?.typeChinese ?: "综合论坛",
|
||||
activityTag = "",
|
||||
gameForumType = imageArticle.community?.game?.categoryChinese ?: "",
|
||||
articleType = "图文",
|
||||
buttonName = if (isCollected) "已收藏" else "收藏"
|
||||
)
|
||||
}
|
||||
|
||||
fun setImageArticle(newData: ImageArticleEntity) {
|
||||
_imageArticleDetailEntity.value = newData
|
||||
}
|
||||
|
||||
fun updateImageArticle(block: (ImageArticleEntity) -> Unit) {
|
||||
val data = imageArticleDetailEntity.value ?: return
|
||||
block(data)
|
||||
_imageArticleDetailEntity.value = data
|
||||
}
|
||||
|
||||
private val _applyHighlightAction = MutableLiveData<Event<Boolean>>()
|
||||
val applyHighlightAction: LiveData<Event<Boolean>> = _applyHighlightAction
|
||||
fun applyHighlightForImageArticle() {
|
||||
repository.applyHighlightForImageArticle(imageArticleId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : CompletableObserver {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
compositeDisposable.add(d)
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
imageArticleDetailEntity.value?.choicenessStatus = "apply"
|
||||
_applyHighlightAction.value = Event(true)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
_applyHighlightAction.value = Event(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private val _addHighlightAction = MutableLiveData<Event<Int>>()
|
||||
val addHighlightAction: LiveData<Event<Int>> = _addHighlightAction
|
||||
fun addHighlight(isAdd: Boolean) {
|
||||
repository.addHighlight(isAdd, imageArticleId)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
val imageArticle = imageArticleDetailEntity.value ?: return
|
||||
if (isAdd) {
|
||||
if (imageArticle.me.moderatorPermissions.choicenessImageArticle == Permissions.REPORTER) {
|
||||
_addHighlightAction.value = Event(R.string.apply_successfully)
|
||||
updateImageArticle {
|
||||
it.choicenessStatus = "apply"
|
||||
}
|
||||
} else {
|
||||
_addHighlightAction.value = Event(R.string.operation_successful)
|
||||
updateImageArticle {
|
||||
it.choicenessStatus = "pass"
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
if (imageArticle.me.moderatorPermissions.cancelChoicenessImageArticle == Permissions.REPORTER) {
|
||||
_addHighlightAction.value = Event(R.string.apply_successfully)
|
||||
} else {
|
||||
_addHighlightAction.value = Event(R.string.operation_successful)
|
||||
updateImageArticle {
|
||||
it.choicenessStatus = "cancel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
_addHighlightAction.value = Event(R.string.permission_error)
|
||||
}
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
private val _deleteOrHideImageArticleSuccessfully = MutableLiveData<Event<Pair<Boolean, Int>>>()
|
||||
val deleteOrHideImageArticleSuccessfully: LiveData<Event<Pair<Boolean, Int>>> =
|
||||
_deleteOrHideImageArticleSuccessfully
|
||||
|
||||
fun deleteOrHideImageArticle() {
|
||||
repository.deleteOrHideImageArticle(imageArticleId)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
val imageArticle = imageArticleDetailEntity.value ?: return
|
||||
val toastResId = if (imageArticle.me.isModerator) {
|
||||
if (imageArticle.me.moderatorPermissions.hideImageArticle == Permissions.REPORTER) {
|
||||
R.string.apply_successfully
|
||||
} else {
|
||||
R.string.hidden
|
||||
}
|
||||
} else {
|
||||
R.string.deleted
|
||||
}
|
||||
ImageArticleUseCase.notifyDataDeleted(imageArticleId)
|
||||
_deleteOrHideImageArticleSuccessfully.value = Event(true to toastResId)
|
||||
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
super.onFailure(exception)
|
||||
_deleteOrHideImageArticleSuccessfully.value = Event(false to R.string.permission_error_and_retry)
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
fun imageArticleChanged(changed: EBImageArticleChanged) {
|
||||
when {
|
||||
changed is EBImageArticleChanged.VoteChanged -> {
|
||||
updateImageArticle {
|
||||
it.me.isCommunityArticleVote = changed.isVoted
|
||||
it.count.vote = changed.count
|
||||
}
|
||||
}
|
||||
|
||||
changed is EBImageArticleChanged.DataChanged -> {
|
||||
setImageArticle(changed.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,101 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.viewmodel
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.gh.gamecenter.common.baselist.PageLoader
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleRepository
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import io.reactivex.CompletableObserver
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
class ImageArticleDraftViewModel : ViewModel() {
|
||||
|
||||
private val repository = ImageArticleRepository.newInstance()
|
||||
|
||||
private val composeDisposable = CompositeDisposable()
|
||||
|
||||
private val _pageState = MutableLiveData<PageLoader.PageState>()
|
||||
val pageState: LiveData<PageLoader.PageState> = _pageState
|
||||
|
||||
private val _drafts = MutableLiveData<List<ImageArticleEntity>>()
|
||||
val drafts: LiveData<List<ImageArticleEntity>> = _drafts
|
||||
|
||||
fun loadDraft(isPullToRefresh: Boolean) {
|
||||
_pageState.value = if (isPullToRefresh) {
|
||||
PageLoader.PageState.PagePullToRefreshLoading
|
||||
} else {
|
||||
PageLoader.PageState.PageInitLoading
|
||||
}
|
||||
|
||||
repository.loadDraft()
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<List<ImageArticleEntity>>() {
|
||||
override fun onSuccess(data: List<ImageArticleEntity>) {
|
||||
_pageState.value = if (data.isEmpty()) {
|
||||
PageLoader.PageState.PageNoData
|
||||
} else {
|
||||
PageLoader.PageState.PageLoadCompleted
|
||||
}
|
||||
_drafts.value = data
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
super.onFailure(exception)
|
||||
_pageState.value = if (isPullToRefresh) {
|
||||
PageLoader.PageState.PagePullToRefreshFailure
|
||||
} else {
|
||||
PageLoader.PageState.PageInitFailure
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}).let(composeDisposable::add)
|
||||
}
|
||||
|
||||
private val _showDeleteDraftDialogAction = MutableLiveData<Event<String>>()
|
||||
val showDeleteDraftDialogAction: LiveData<Event<String>> = _showDeleteDraftDialogAction
|
||||
fun showDeleteDraftDialog(draftId: String) {
|
||||
_showDeleteDraftDialogAction.value = Event(draftId)
|
||||
}
|
||||
|
||||
fun deleteDraft(draftId: String) {
|
||||
repository.deleteDraft(draftId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : CompletableObserver {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
composeDisposable.add(d)
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
val oldData = drafts.value ?: emptyList()
|
||||
val newList = oldData.toMutableList()
|
||||
newList.removeAll { it.id == draftId }
|
||||
if (newList.isEmpty()) {
|
||||
_pageState.value = PageLoader.PageState.PageNoData
|
||||
} else {
|
||||
_drafts.value = newList
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) = Unit
|
||||
})
|
||||
}
|
||||
|
||||
private val _publishImageArticleDestination = MutableLiveData<Event<ImageArticleEntity>>()
|
||||
val publishImageArticleDestination: LiveData<Event<ImageArticleEntity>> = _publishImageArticleDestination
|
||||
fun editDraft(draftEntity: ImageArticleEntity) {
|
||||
_publishImageArticleDestination.value = Event(draftEntity)
|
||||
}
|
||||
|
||||
fun updateDrafts(draftList: MutableList<ImageArticleEntity>) {
|
||||
_drafts.value = draftList
|
||||
}
|
||||
}
|
||||
@ -1,77 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.viewmodel
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.gh.gamecenter.common.baselist.PageLoader
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleRepository
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleUseCase
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
||||
class ImageArticleHomeViewModel : ViewModel() {
|
||||
|
||||
private val repository = ImageArticleRepository.newInstance()
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
val useCase = ImageArticleUseCase(repository, compositeDisposable)
|
||||
|
||||
val pageLoader = PageLoader(compositeDisposable = compositeDisposable) { pageNo, _ ->
|
||||
repository.loadRecommends(pageNo)
|
||||
}
|
||||
|
||||
fun initLoad() {
|
||||
pageLoader.loadInit()
|
||||
}
|
||||
|
||||
private val _imageDetailDestination = MutableLiveData<Event<ImageArticleEntity>>()
|
||||
val imageDetailDestination: LiveData<Event<ImageArticleEntity>> = _imageDetailDestination
|
||||
fun navigateToImageArticleDetailPage(imageArticleEntity: ImageArticleEntity) {
|
||||
_imageDetailDestination.value = Event(imageArticleEntity)
|
||||
}
|
||||
|
||||
fun loadMore() {
|
||||
pageLoader.loadMore()
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
fun voteChanged(changed: EBImageArticleChanged.VoteChanged) {
|
||||
val oldData = pageLoader.dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val position = newData.indexOfFirst { it.id == changed.id }
|
||||
if (position != -1) {
|
||||
val oldItem = newData[position]
|
||||
val oldCount = oldItem.count.vote
|
||||
val newCount = if (changed.isVoted) {
|
||||
oldCount + 1
|
||||
} else {
|
||||
oldCount - 1
|
||||
}
|
||||
val newItem = oldItem.copy(
|
||||
_me = oldItem.me.copy(isCommunityArticleVote = changed.isVoted),
|
||||
_count = oldItem.count.copy(vote = newCount)
|
||||
)
|
||||
newData[position] = newItem
|
||||
pageLoader.updateData(newData)
|
||||
}
|
||||
}
|
||||
|
||||
fun itemChanged(changed: EBImageArticleChanged.DataChanged) {
|
||||
val oldData = pageLoader.dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val position = newData.indexOfFirst { it.id == changed.data.id }
|
||||
if (position != -1) {
|
||||
newData[position] = changed.data
|
||||
pageLoader.updateData(newData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,81 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.viewmodel
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.gh.gamecenter.common.baselist.PageLoader
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity.Count
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleRepository
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleUseCase
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
||||
class MyImageArticleListViewModel : ViewModel() {
|
||||
|
||||
private val repository = ImageArticleRepository.newInstance()
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
val useCase = ImageArticleUseCase(repository, compositeDisposable)
|
||||
|
||||
val pageLoader = PageLoader(compositeDisposable = compositeDisposable) { pageSize, _ ->
|
||||
repository.loadMyImageArticleList(pageSize)
|
||||
.singleOrError()
|
||||
}
|
||||
|
||||
fun initLoad() {
|
||||
pageLoader.loadInit()
|
||||
}
|
||||
|
||||
private val _imageArticleDetailDestination = MutableLiveData<Event<String>>()
|
||||
val imageArticleDetailDestination: LiveData<Event<String>> = _imageArticleDetailDestination
|
||||
fun navigateToImageArticleDetailPage(imageArticleId: String) {
|
||||
_imageArticleDetailDestination.value = Event(imageArticleId)
|
||||
}
|
||||
|
||||
fun loadMore() {
|
||||
pageLoader.loadMore()
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
fun voteChanged(changed: EBImageArticleChanged.VoteChanged) {
|
||||
val oldData = pageLoader.dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val position = newData.indexOfFirst { it.id == changed.id }
|
||||
if (position != -1) {
|
||||
val oldItem = newData[position]
|
||||
val oldCount = oldItem.count.vote
|
||||
val newCount = if (changed.isVoted) {
|
||||
oldCount + 1
|
||||
} else {
|
||||
oldCount - 1
|
||||
}
|
||||
val newItem = oldItem.copy(
|
||||
_me = oldItem.me.copy(isCommunityArticleVote = changed.isVoted),
|
||||
_count = Count(
|
||||
comment = oldItem.count.comment,
|
||||
vote = newCount,
|
||||
reply = oldItem.count.reply,
|
||||
)
|
||||
)
|
||||
|
||||
newData[position] = newItem
|
||||
pageLoader.updateData(newData)
|
||||
}
|
||||
}
|
||||
|
||||
fun itemChanged(changed: EBImageArticleChanged.DataChanged) {
|
||||
val oldData = pageLoader.dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val position = newData.indexOfFirst { it.id == changed.data.id }
|
||||
if (position != -1) {
|
||||
newData[position] = changed.data.toPersonHistoryEntity()
|
||||
pageLoader.updateData(newData)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,129 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.viewmodel
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleRepository
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageAndTextAdapter
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import java.util.*
|
||||
|
||||
class PublishImageArticleActivityViewModel : ViewModel() {
|
||||
|
||||
private val repository = ImageArticleRepository.newInstance()
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
private var imageId: Int = 0
|
||||
|
||||
private val _showDragTipsAction = MutableLiveData<Event<Unit>>()
|
||||
val showDragTipsAction: LiveData<Event<Unit>> = _showDragTipsAction
|
||||
|
||||
private val _localImages = MutableLiveData<List<ImageAndTextAdapter.LocalImage>>()
|
||||
val localImages: LiveData<List<ImageAndTextAdapter.LocalImage>> = _localImages
|
||||
|
||||
fun addImages(uris: List<Uri>) {
|
||||
val oldData = localImages.value?.toMutableList() ?: mutableListOf()
|
||||
|
||||
val newData = (oldData + uris.map {
|
||||
ImageAndTextAdapter.LocalImage(id = imageId++, isCover = false, showClose = true, uri = it)
|
||||
}).toMutableList()
|
||||
|
||||
resetFirstItem(newData)
|
||||
|
||||
repository.isShowDragTips()
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<Boolean>() {
|
||||
override fun onSuccess(data: Boolean) {
|
||||
if (data && newData.size > 1) {
|
||||
repository.saveHasShowDragTips()
|
||||
_showDragTipsAction.value = Event(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
private val _chooseImageAction = MutableLiveData<Event<Int>>()
|
||||
val chooseImageAction: LiveData<Event<Int>> = _chooseImageAction
|
||||
fun chooseImage() {
|
||||
val currentImageSize = localImages.value?.size ?: 0
|
||||
val remainingSize = 9 - currentImageSize
|
||||
_chooseImageAction.value = Event(remainingSize)
|
||||
}
|
||||
|
||||
fun removeImage(position: Int) {
|
||||
val images = localImages.value?.toMutableList() ?: mutableListOf()
|
||||
images.removeAt(position)
|
||||
resetFirstItem(images)
|
||||
}
|
||||
|
||||
private fun resetFirstItem(data: MutableList<ImageAndTextAdapter.LocalImage>) {
|
||||
if (data.isEmpty()) {
|
||||
_localImages.value = mutableListOf()
|
||||
} else {
|
||||
// 给第一个设置为封面
|
||||
val firstItem = data[0].copy(isCover = true)
|
||||
data[0] = firstItem
|
||||
_localImages.value = data
|
||||
}
|
||||
}
|
||||
|
||||
fun swap(dataPosition: Int, targetDataPosition: Int) {
|
||||
val oldList = localImages.value ?: arrayListOf()
|
||||
val newList = oldList.toMutableList()
|
||||
Collections.swap(newList, dataPosition, targetDataPosition)
|
||||
_localImages.value = newList
|
||||
|
||||
}
|
||||
|
||||
fun refreshImages() {
|
||||
val oldList = localImages.value ?: arrayListOf()
|
||||
val newList = oldList.toMutableList()
|
||||
for (index in newList.indices) {
|
||||
val item = newList[index]
|
||||
if (index == 0 && !item.isCover) {
|
||||
newList[0] = item.copy(isCover = true)
|
||||
}
|
||||
|
||||
if (index != 0 && item.isCover) {
|
||||
newList[index] = item.copy(isCover = false)
|
||||
}
|
||||
}
|
||||
_localImages.value = newList
|
||||
}
|
||||
|
||||
private val _draftBoxDestination = MutableLiveData<Event<Unit>>()
|
||||
val draftBoxDestination: LiveData<Event<Unit>> = _draftBoxDestination
|
||||
fun navigateToDraftBox() {
|
||||
_draftBoxDestination.value = Event(Unit)
|
||||
}
|
||||
|
||||
private val _editImageArticle = MutableLiveData<Event<ImageArticleEntity>>()
|
||||
val editImageArticle: LiveData<Event<ImageArticleEntity>> = _editImageArticle
|
||||
fun setEditImageArticle(imageArticleEntity: ImageArticleEntity?) {
|
||||
imageArticleEntity ?: return
|
||||
addImagesFromEdit(imageArticleEntity.images)
|
||||
_editImageArticle.value = Event(imageArticleEntity)
|
||||
}
|
||||
|
||||
private fun addImagesFromEdit(urls: List<String>) {
|
||||
val newImages = urls.map {
|
||||
ImageAndTextAdapter.LocalImage(id = imageId++, isCover = false, showClose = true, url = it)
|
||||
}.toMutableList()
|
||||
|
||||
resetFirstItem(newImages)
|
||||
}
|
||||
|
||||
private val _community = MutableLiveData<Event<CommunityEntity>>()
|
||||
val community: LiveData<Event<CommunityEntity>> = _community
|
||||
fun setCommunity(communityEntity: CommunityEntity) {
|
||||
_community.value = Event(communityEntity)
|
||||
}
|
||||
}
|
||||
@ -1,234 +0,0 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.viewmodel
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.observableToMain
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.common.utils.toRequestBody
|
||||
import com.gh.gamecenter.entity.ForumDetailEntity
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.PublishImageTextRequest
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleRepository
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleUseCase
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageAndTextAdapter
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.HttpException
|
||||
|
||||
class PublishImageArticleViewModel : ViewModel() {
|
||||
|
||||
private val repository = ImageArticleRepository.newInstance()
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
var isModerator: Boolean = false
|
||||
|
||||
private var imageArticle: ImageArticleEntity? = null
|
||||
|
||||
val isCreating: Boolean
|
||||
get() = imageArticle == null || imageArticle!!.isDraft
|
||||
|
||||
private val _chooseImageAction = MutableLiveData<Event<Unit>>()
|
||||
val chooseImageAction: LiveData<Event<Unit>> = _chooseImageAction
|
||||
fun chooseImage() {
|
||||
_chooseImageAction.value = Event(Unit)
|
||||
}
|
||||
|
||||
private val _removeImageAction = MutableLiveData<Event<Int>>()
|
||||
val removeImageAction: LiveData<Event<Int>> = _removeImageAction
|
||||
fun removeImage(position: Int) {
|
||||
_removeImageAction.value = Event(position)
|
||||
}
|
||||
|
||||
private val _linkBbs = MutableLiveData<LinkBbs>()
|
||||
val linkBbs: LiveData<LinkBbs> = _linkBbs
|
||||
fun changeLinkBbs(newCommunity: CommunityEntity?) {
|
||||
if (newCommunity == null) {
|
||||
_linkBbs.value = LinkBbs(null, false, null)
|
||||
return
|
||||
}
|
||||
val oldCommunity = linkBbs.value?.communityEntity
|
||||
if (newCommunity != oldCommunity) {
|
||||
// 用户重新选择了关联论坛
|
||||
_linkBbs.value = LinkBbs(newCommunity, false, null)
|
||||
getForumSections(newCommunity)
|
||||
getModeratorsInfo(newCommunity.id)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getForumSections(newCommunity: CommunityEntity) {
|
||||
repository.checkHasSections(newCommunity.id)
|
||||
.compose(observableToMain())
|
||||
.subscribe(object : Response<Boolean>() {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
compositeDisposable.add(d)
|
||||
}
|
||||
|
||||
override fun onResponse(response: Boolean?) {
|
||||
if (response == true) {
|
||||
// 此论坛有子板块,更新关联论坛ui状态
|
||||
_linkBbs.value = LinkBbs(newCommunity, true, null)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
private fun getModeratorsInfo(bbsId: String) {
|
||||
repository.getModeratorsInfo(bbsId)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<Boolean>() {
|
||||
override fun onSuccess(data: Boolean) {
|
||||
isModerator = data
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
fun changeLinkSection(section: ForumDetailEntity.Section?) {
|
||||
val oldLink = linkBbs.value
|
||||
if (oldLink != null) {
|
||||
_linkBbs.value = oldLink.copy(selectedSection = section)
|
||||
}
|
||||
}
|
||||
|
||||
private val _draftCreated = MutableLiveData<Event<Boolean>>()
|
||||
val draftCreated: LiveData<Event<Boolean>> = _draftCreated
|
||||
fun createOrEditDraft(title: String, content: String, localImages: List<ImageAndTextAdapter.LocalImage>) {
|
||||
val request = createPublishRequest(title, content)
|
||||
repository.createOrEditDraft(request, localImages)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
_draftCreated.value = Event(true)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
_draftCreated.value = Event(false)
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
private val _imageTextPublished = MutableLiveData<Event<Pair<Boolean, String>>>()
|
||||
val imageTextPublished: LiveData<Event<Pair<Boolean, String>>> = _imageTextPublished
|
||||
fun publishImageText(title: String, content: String, images: List<ImageAndTextAdapter.LocalImage>) {
|
||||
val request = createPublishRequest(title, content)
|
||||
SensorsBridge.trackEvent(
|
||||
"ArticlePostClick",
|
||||
"bbs_id",
|
||||
request.communityId,
|
||||
"bbs_type",
|
||||
request.communityType,
|
||||
"activity_tag",
|
||||
"",
|
||||
"article_type",
|
||||
"图文"
|
||||
)
|
||||
if (isCreating) {
|
||||
repository.publishImageText(request, images)
|
||||
} else {
|
||||
repository.editImageArticle(imageArticle!!.id, request, images)
|
||||
}
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ImageArticleEntity>() {
|
||||
override fun onSuccess(data: ImageArticleEntity) {
|
||||
if (isCreating) {
|
||||
ImageArticleUseCase.notifyDataCreated(data, request.draftId)
|
||||
} else {
|
||||
ImageArticleUseCase.notifyDataEdited(data)
|
||||
}
|
||||
_imageTextPublished.value = Event(true to "")
|
||||
|
||||
val community = data.community
|
||||
SensorsBridge.trackArticlePostResult(
|
||||
postResult = "成功",
|
||||
bbsId = community?.id ?: "",
|
||||
bbsType = if (community != null) {
|
||||
if (data.community.type == "official_bbs") "综合论坛" else "游戏论坛"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
activityTag = "",
|
||||
articleType = "图文",
|
||||
customerType = UserManager.getInstance().userInfoEntity?.auth?.text ?: "",
|
||||
gameForumType = community?.game?.categoryChinese ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
val errorString = try {
|
||||
(exception as? HttpException)?.response()?.errorBody()?.string() ?: ""
|
||||
} catch (e1: Exception) {
|
||||
e1.printStackTrace()
|
||||
""
|
||||
}
|
||||
_imageTextPublished.value = Event(false to errorString)
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
private fun createPublishRequest(title: String, content: String): PublishImageTextRequest {
|
||||
val draftId = if (imageArticle?.isDraft == true) {
|
||||
// 发布或者编辑草稿
|
||||
imageArticle?.id ?: ""
|
||||
} else {
|
||||
""
|
||||
}
|
||||
val selectedBbs = linkBbs.value
|
||||
val communityId = selectedBbs?.communityEntity?.id ?: ""
|
||||
val communityType = selectedBbs?.communityEntity?.type ?: ""
|
||||
val sectionId = selectedBbs?.selectedSection?.id ?: ""
|
||||
val sectionIds = if (sectionId.isNotEmpty()) listOf(sectionId) else listOf()
|
||||
return PublishImageTextRequest(title, content, communityType, communityId, sectionIds, emptyList(), draftId)
|
||||
}
|
||||
|
||||
private val _editImageArticle = MutableLiveData<Event<ImageArticleEntity>>()
|
||||
val editImageArticle: LiveData<Event<ImageArticleEntity>> = _editImageArticle
|
||||
fun setEditImageArticle(imageArticleEntity: ImageArticleEntity?) {
|
||||
imageArticleEntity ?: return
|
||||
imageArticle = imageArticleEntity
|
||||
val community = imageArticleEntity.community?.toCommunityEntity()
|
||||
val section = imageArticleEntity.sections.firstOrNull()
|
||||
val game = imageArticleEntity.community?.game
|
||||
val icon = if (game == null) {
|
||||
community?.icon ?: ""
|
||||
} else {
|
||||
game.rawIcon ?: game.icon
|
||||
}
|
||||
community?.icon = icon
|
||||
when {
|
||||
community != null && section != null -> { // 绑定了论坛和子板块
|
||||
val formSection = ForumDetailEntity.Section(section.id, name = section.name)
|
||||
_linkBbs.value = LinkBbs(community, hasSection = true, formSection)
|
||||
}
|
||||
|
||||
community != null -> { // 只绑定了论坛未绑定子板块
|
||||
changeLinkBbs(community)
|
||||
}
|
||||
|
||||
else -> { // 未绑定论坛
|
||||
changeLinkBbs(null)
|
||||
}
|
||||
}
|
||||
|
||||
changeLinkBbs(community)
|
||||
_editImageArticle.value = Event(imageArticleEntity)
|
||||
}
|
||||
|
||||
|
||||
data class LinkBbs(
|
||||
val communityEntity: CommunityEntity?,
|
||||
val hasSection: Boolean,
|
||||
val selectedSection: ForumDetailEntity.Section? = null
|
||||
)
|
||||
}
|
||||
@ -611,7 +611,7 @@ class GameFragmentAdapter(
|
||||
val subjectData = gameEntity.subjectData
|
||||
DataCollectionUtils.uploadClick(mContext, subjectData?.name + "-列表", "游戏-专题", gameEntity.name)
|
||||
if (gameEntity.isMiniGame()) {
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity)
|
||||
} else {
|
||||
GameDetailActivity.startGameDetailActivity(
|
||||
mContext, gameEntity,
|
||||
@ -1322,7 +1322,7 @@ class GameFragmentAdapter(
|
||||
DataCollectionUtils.uploadClick(mContext, subjectData.name + "-列表", "游戏-专题", gameEntity.name)
|
||||
|
||||
if (gameEntity.isMiniGame()) {
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity)
|
||||
} else if (gameEntity.isPluggable) {
|
||||
GameDetailActivity.startGameDetailActivity(
|
||||
mContext,
|
||||
|
||||
@ -135,7 +135,7 @@ class GameGallerySlideViewHolder(val binding: GameGallerySlideItemBinding) : Bas
|
||||
binding.iconIv.displayGameIcon(gameEntity)
|
||||
binding.iconIv.setOnClickListener {
|
||||
if (gameEntity.isMiniGame()) {
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity)
|
||||
} else {
|
||||
GameDetailActivity.startGameDetailActivity(
|
||||
binding.root.context,
|
||||
|
||||
@ -55,7 +55,7 @@ class GameGalleryViewHolder(val cell: GameGalleryItemCell) :
|
||||
|
||||
if (subjectEntity.isMiniGame) {
|
||||
gameIcon.setOnClickListener {
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity)
|
||||
}
|
||||
} else {
|
||||
gameIcon.setOnClickListener(null)
|
||||
|
||||
@ -140,7 +140,7 @@ class GameHorizontalAdapter(
|
||||
}
|
||||
|
||||
if (gameEntity.isMiniGame()) {
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity)
|
||||
} else {
|
||||
GameDetailActivity.startGameDetailActivity(
|
||||
mContext,
|
||||
|
||||
@ -68,7 +68,7 @@ class GameHorizontalSlideAdapter(
|
||||
holder.bindGameHorizontalItem(gameEntity, mSubjectEntity)
|
||||
holder.itemView.setOnClickListener {
|
||||
if (gameEntity.isMiniGame()) {
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity)
|
||||
} else {
|
||||
val exposureEvent = exposureEventList?.safelyGetInRelease(position)
|
||||
if (exposureEvent != null) {
|
||||
|
||||
@ -45,7 +45,9 @@ import com.zhihu.matisse.Matisse
|
||||
import com.zhihu.matisse.internal.utils.PathUtils
|
||||
import io.reactivex.disposables.Disposable
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.io.File
|
||||
import kotlin.collections.component1
|
||||
import kotlin.collections.component2
|
||||
@ -420,10 +422,8 @@ class GameUploadFragment : ToolbarFragment() {
|
||||
requestMap["type"] = mGameType
|
||||
}
|
||||
|
||||
val body = RequestBody.create(
|
||||
MediaType.parse("application/json"),
|
||||
GsonUtils.toJson(requestMap)
|
||||
)
|
||||
val body = GsonUtils.toJson(requestMap)
|
||||
.toRequestBody("application/json".toMediaTypeOrNull())
|
||||
mViewModel.uploadGames(body)
|
||||
}
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ open class GameCollectionDetailViewModel(
|
||||
gameCollectionId: String,
|
||||
topCommentId: String = ""
|
||||
) :
|
||||
BaseCommentViewModel(application, "", "", "", "", gameCollectionId, topCommentId = topCommentId) {
|
||||
BaseCommentViewModel(application, "", "", "", "", gameCollectionId, topCommentId) {
|
||||
|
||||
var firstItemInitOverLiveData = MutableLiveData<Boolean>()
|
||||
var followLiveData = MutableLiveData<Boolean>()
|
||||
|
||||
@ -7,6 +7,9 @@ import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.view.animation.AccelerateDecelerateInterpolator
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.gh.common.util.DirectUtils
|
||||
@ -21,6 +24,17 @@ class GameCollectionAmwayViewHolder(var binding: GameCollectionSquareAmwayItemBi
|
||||
private val mAdapter = GameCollectionAmwayAdapter(binding.root.context)
|
||||
private val mLooperHandle = LooperHandle(this)
|
||||
private val mSlideLooperKey = 333
|
||||
private val mLifecycleObserver = object : DefaultLifecycleObserver {
|
||||
override fun onResume(owner: LifecycleOwner) {
|
||||
super.onResume(owner)
|
||||
startAutoPlay()
|
||||
}
|
||||
|
||||
override fun onPause(owner: LifecycleOwner) {
|
||||
super.onPause(owner)
|
||||
stopAutoPlay()
|
||||
}
|
||||
}
|
||||
|
||||
fun bindAmway(amwayList: List<AmwayCommentEntity>, viewModel: GameCollectionSquareViewModel) {
|
||||
mAdapter.setAmwayList(amwayList)
|
||||
@ -54,6 +68,14 @@ class GameCollectionAmwayViewHolder(var binding: GameCollectionSquareAmwayItemBi
|
||||
mLooperHandle.removeMessages(mSlideLooperKey)
|
||||
}
|
||||
|
||||
fun onViewAttach(lifecycle: Lifecycle) {
|
||||
lifecycle.addObserver(mLifecycleObserver)
|
||||
}
|
||||
|
||||
fun onViewDetach(lifecycle: Lifecycle) {
|
||||
lifecycle.removeObserver(mLifecycleObserver)
|
||||
}
|
||||
|
||||
fun ViewPager2.setCurrentItem(
|
||||
item: Int,
|
||||
duration: Long,
|
||||
|
||||
@ -2,6 +2,7 @@ package com.gh.gamecenter.gamecollection.square
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.exposure.ExposureManager
|
||||
import com.gh.common.util.DirectUtils
|
||||
@ -23,6 +24,7 @@ import com.lightgame.adapter.BaseRecyclerAdapter
|
||||
|
||||
class GameCollectionBannerAdapter(
|
||||
context: Context,
|
||||
private val mLifecycleOwner: LifecycleOwner,
|
||||
private val mViewModel: GameCollectionSquareViewModel,
|
||||
var mBannerList: List<CarouselEntity> = emptyList(),
|
||||
private var mAmwayListItem: List<AmwayCommentEntity>? = null,
|
||||
@ -78,6 +80,20 @@ class GameCollectionBannerAdapter(
|
||||
return index
|
||||
}
|
||||
|
||||
override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
|
||||
super.onViewAttachedToWindow(holder)
|
||||
if (holder is GameCollectionAmwayViewHolder) {
|
||||
holder.onViewAttach(mLifecycleOwner.lifecycle)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
|
||||
super.onViewDetachedFromWindow(holder)
|
||||
if (holder is GameCollectionAmwayViewHolder) {
|
||||
holder.onViewDetach(mLifecycleOwner.lifecycle)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ITEM_AMWAY = 100
|
||||
const val ITEM_BANNER = 101
|
||||
|
||||
@ -12,6 +12,9 @@ import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.PagerSnapHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@ -47,6 +50,7 @@ import java.lang.ref.WeakReference
|
||||
|
||||
class GameCollectionSquareAdapter(
|
||||
context: Context,
|
||||
private val mLifecycleOwner: LifecycleOwner,
|
||||
private val mIsHome: Boolean = false,
|
||||
private val mFragment: GameCollectionSquareFragment,
|
||||
private val mViewModel: GameCollectionSquareViewModel,
|
||||
@ -157,7 +161,7 @@ class GameCollectionSquareAdapter(
|
||||
when (holder) {
|
||||
is GameCollectionHeaderItemViewHolder -> {
|
||||
val itemData = mEntityList[position]
|
||||
holder.bindHeader(itemData, mBasicExposureSource, mViewModel)
|
||||
holder.bindHeader(mLifecycleOwner, itemData, mBasicExposureSource, mViewModel)
|
||||
}
|
||||
|
||||
is GameCollectionFilterItemViewHolder -> holder.bindFilter(mFragment, mViewModel, mRefreshCallback)
|
||||
@ -211,6 +215,20 @@ class GameCollectionSquareAdapter(
|
||||
override fun getItemCount() =
|
||||
if (mEntityList.isNullOrEmpty()) 0 else if (mIsHome && mEntityList.size == 2) mEntityList.size else mEntityList.size + 1
|
||||
|
||||
override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
|
||||
super.onViewAttachedToWindow(holder)
|
||||
if (holder is GameCollectionHeaderItemViewHolder) {
|
||||
holder.onViewAttach(mLifecycleOwner.lifecycle)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
|
||||
super.onViewDetachedFromWindow(holder)
|
||||
if (holder is GameCollectionHeaderItemViewHolder) {
|
||||
holder.onViewDetach(mLifecycleOwner.lifecycle)
|
||||
}
|
||||
}
|
||||
|
||||
class GameCollectionHeaderItemViewHolder(val binding: ItemGameCollectionHeaderBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
private lateinit var mBannerAdapter: GameCollectionBannerAdapter
|
||||
@ -218,8 +236,20 @@ class GameCollectionSquareAdapter(
|
||||
private lateinit var mBannerLayoutManager: LinearLayoutManager
|
||||
private val mLooperHandle = LooperHandle(this)
|
||||
private val mSlideLooperKey = 111
|
||||
private val mLifecycleObserver = object : DefaultLifecycleObserver {
|
||||
override fun onResume(owner: LifecycleOwner) {
|
||||
super.onResume(owner)
|
||||
startAutoPlay()
|
||||
}
|
||||
|
||||
override fun onPause(owner: LifecycleOwner) {
|
||||
super.onPause(owner)
|
||||
stopAutoPlay()
|
||||
}
|
||||
}
|
||||
|
||||
fun bindHeader(
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
itemData: GameCollectionListItemData,
|
||||
mBasicExposureSource: List<ExposureSource>,
|
||||
viewModel: GameCollectionSquareViewModel
|
||||
@ -249,6 +279,7 @@ class GameCollectionSquareAdapter(
|
||||
mBannerLayoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
mBannerAdapter = GameCollectionBannerAdapter(
|
||||
context,
|
||||
lifecycleOwner,
|
||||
viewModel,
|
||||
bannerList,
|
||||
amwayListItem,
|
||||
@ -345,6 +376,14 @@ class GameCollectionSquareAdapter(
|
||||
mLooperHandle.removeMessages(mSlideLooperKey)
|
||||
}
|
||||
|
||||
fun onViewAttach(lifecycle: Lifecycle) {
|
||||
lifecycle.addObserver(mLifecycleObserver)
|
||||
}
|
||||
|
||||
fun onViewDetach(lifecycle: Lifecycle) {
|
||||
lifecycle.removeObserver(mLifecycleObserver)
|
||||
}
|
||||
|
||||
class LooperHandle(viewHolder: GameCollectionHeaderItemViewHolder) : Handler(Looper.getMainLooper()) {
|
||||
private val mWeakReference: WeakReference<GameCollectionHeaderItemViewHolder> = WeakReference(viewHolder)
|
||||
|
||||
|
||||
@ -138,6 +138,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
|
||||
mGuideContainer?.visibility = View.GONE
|
||||
} else {
|
||||
if (mExposureEventList.isNotEmpty()) ExposureManager.log(mExposureEventList)
|
||||
stopAutoPlay()
|
||||
}
|
||||
val stayTime = (System.currentTimeMillis() - startPageTime) / 1000
|
||||
NewFlatLogUtils.logGameCollectSquareStayTime(stayTime, if (mUseAlternativeLayout) "首页tab栏" else "游戏单广场")
|
||||
@ -175,6 +176,8 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
startAutoPlay()
|
||||
}
|
||||
mElapsedHelper.resetCounting()
|
||||
mElapsedHelper.resumeCounting()
|
||||
@ -270,6 +273,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
|
||||
mAdapter =
|
||||
GameCollectionSquareAdapter(
|
||||
requireContext(),
|
||||
viewLifecycleOwner,
|
||||
mUseAlternativeLayout,
|
||||
this,
|
||||
mViewModel,
|
||||
@ -382,6 +386,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
|
||||
|
||||
val bannerAdapter = GameCollectionBannerAdapter(
|
||||
requireContext(),
|
||||
viewLifecycleOwner,
|
||||
mViewModel,
|
||||
mEntrance = "游戏单广场",
|
||||
mBasicExposureSource = mBasicExposureSourceList
|
||||
@ -515,7 +520,8 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
|
||||
}
|
||||
|
||||
private fun startAutoPlay() {
|
||||
if ((mDefaultBinding.headerContainer.bannerRv.adapter as GameCollectionBannerAdapter).getActualSize() <= 1) return
|
||||
val bannerAdapter = mDefaultBinding.headerContainer.bannerRv.adapter as? GameCollectionBannerAdapter
|
||||
if (bannerAdapter == null || bannerAdapter.getActualSize() <= 1) return
|
||||
stopAutoPlay()
|
||||
mLooperHandle.sendEmptyMessageDelayed(mSlideLooperKey, BANNER_LOOP_TIME)
|
||||
}
|
||||
|
||||
@ -45,7 +45,9 @@ import com.gh.gamecenter.login.user.UserManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.json.JSONObject
|
||||
import retrofit2.HttpException
|
||||
|
||||
@ -541,7 +543,7 @@ class RatingEditActivity : ToolBarActivity(), KeyboardHeightObserver {
|
||||
jsonObject.put("rom", MetaUtil.getRom().name + " " + MetaUtil.getRom().versionName)
|
||||
jsonObject.put("again", again)
|
||||
|
||||
val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
|
||||
val body = jsonObject.toString().toRequestBody("application/json".toMediaTypeOrNull())
|
||||
|
||||
CheckLoginUtils.checkLogin(this, mEntrance) {
|
||||
mViewModel.postGameComment(mComment?.id ?: "", body)
|
||||
|
||||
@ -97,7 +97,7 @@ class HomeGameItemViewHolder(val binding: HomeGameItemBinding) : BaseRecyclerVie
|
||||
}
|
||||
holder.itemView.setOnClickListener {
|
||||
if (game.isMiniGame()) {
|
||||
MiniGameItemHelper.launchMiniGame(game.miniGameAppId, game.miniGameType)
|
||||
MiniGameItemHelper.launchMiniGame(game)
|
||||
} else {
|
||||
GameDetailActivity.startGameDetailActivity(
|
||||
binding.root.context,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user