feat:社区推荐信息流改版&新增图文内容类型—客户端 https://jira.shanqu.cc/browse/GHZSCY-6136
This commit is contained in:
@ -14,6 +14,7 @@ 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
|
||||
@ -24,15 +25,17 @@ 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(contentId: String) {
|
||||
fun showReportDialog(report: CommunityReporter) {
|
||||
val sp = PreferenceManager.getDefaultSharedPreferences(HaloApp.getInstance())
|
||||
val suggestion: SettingsEntity.Suggestion? =
|
||||
sp.getString(CommonConsts.SUGGESTION_HINT_TYPE, null)?.toObject()
|
||||
@ -52,7 +55,7 @@ object BbsReportHelper {
|
||||
binding.normalReasonContainer.visibility = View.GONE
|
||||
binding.otherReasonContainer.visibility = View.VISIBLE
|
||||
} else {
|
||||
postReport(contentId, json {
|
||||
report.postReport(json {
|
||||
"reason" to reason
|
||||
})
|
||||
dialog.cancel()
|
||||
@ -82,7 +85,7 @@ object BbsReportHelper {
|
||||
) {
|
||||
ToastUtils.showToast("请填写举报原因")
|
||||
} else {
|
||||
postReport(contentId, json {
|
||||
report.postReport(json {
|
||||
"reason" to "其它"
|
||||
"description" to binding.otherReasonEt.text.toString()
|
||||
})
|
||||
@ -105,28 +108,45 @@ object BbsReportHelper {
|
||||
}
|
||||
}
|
||||
|
||||
@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("举报成功")
|
||||
}
|
||||
interface CommunityReporter {
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
super.onFailure(exception)
|
||||
if (exception is HttpException) {
|
||||
ErrorHelper.handleError(
|
||||
HaloApp.getInstance().application,
|
||||
exception.response().errorBody()?.string()
|
||||
)
|
||||
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()
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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,6 +119,23 @@ 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,
|
||||
@ -129,6 +146,7 @@ object CommentHelper {
|
||||
questionId: String? = null,
|
||||
videoId: String? = null,
|
||||
gameCollectionId: String? = null,
|
||||
imageArticleId: String? = null,
|
||||
isShowTopOrAccept: Boolean = false,
|
||||
ignoreModerator: Boolean = false,
|
||||
isVideoAuthor: Boolean = false,
|
||||
@ -137,8 +155,7 @@ object CommentHelper {
|
||||
val context = view.context
|
||||
val dialogOptions = ArrayList<String>()
|
||||
val isContentAuthor = commentEntity.me?.isContentAuthor == true
|
||||
|
||||
if (isShowTopOrAccept && (articleId != null || questionId != null || videoId != null) && isContentAuthor) {
|
||||
if (isShowTopOrAccept && (articleId != null || questionId != null || videoId != null || imageArticleId != null) && isContentAuthor) {
|
||||
dialogOptions.add(if (commentEntity.isTop) "取消置顶" else "置顶")
|
||||
}
|
||||
if (isShowTopOrAccept && questionId != null && isContentAuthor) {
|
||||
@ -229,6 +246,7 @@ object CommentHelper {
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
|
||||
articleId != null -> {
|
||||
PostCommentUtils.reportCommunityArticleComment(
|
||||
commentEntity.id,
|
||||
@ -236,6 +254,7 @@ object CommentHelper {
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
|
||||
questionId != null -> {
|
||||
PostCommentUtils.reportQuestionComment(
|
||||
questionId,
|
||||
@ -244,6 +263,7 @@ object CommentHelper {
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
|
||||
gameCollectionId != null -> {
|
||||
PostCommentUtils.reportGameCollectionComment(
|
||||
gameCollectionId,
|
||||
@ -252,6 +272,15 @@ object CommentHelper {
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
|
||||
imageArticleId != null -> {
|
||||
PostCommentUtils.reportImageArticleComment(
|
||||
commentEntity.id,
|
||||
reportType,
|
||||
commentListener
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
PostCommentUtils.reportVideoComment(
|
||||
videoId,
|
||||
@ -287,6 +316,17 @@ object CommentHelper {
|
||||
null
|
||||
)
|
||||
)
|
||||
} else if (imageArticleId != null) {
|
||||
context.startActivity(
|
||||
CommentDetailActivity
|
||||
.getImageArticleCommentIntent(
|
||||
context,
|
||||
imageArticleId,
|
||||
commentEntity.id,
|
||||
communityId,
|
||||
null
|
||||
)
|
||||
)
|
||||
} else {
|
||||
context.startActivity(
|
||||
CommentDetailActivity
|
||||
|
||||
@ -305,6 +305,7 @@ public class CommentUtils {
|
||||
String articleCommunityId,
|
||||
String videoId,
|
||||
String questionId,
|
||||
String imageArticleId,
|
||||
final CommentEntity commentEntity,
|
||||
final TextView commentLikeCountTv,
|
||||
final ImageView commentLikeIv,
|
||||
@ -328,7 +329,7 @@ public class CommentUtils {
|
||||
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
|
||||
commentLikeCountTv.setVisibility(View.VISIBLE);
|
||||
|
||||
PostCommentUtils.likeComment(answerId, articleId, videoId, questionId, commentEntity.getId(),
|
||||
PostCommentUtils.likeComment(answerId, articleId, videoId, questionId, imageArticleId, commentEntity.getId(),
|
||||
new PostCommentUtils.PostCommentListener() {
|
||||
@Override
|
||||
public void postSuccess(JSONObject response) {
|
||||
@ -374,6 +375,7 @@ public class CommentUtils {
|
||||
String articleId,
|
||||
String articleCommunityId,
|
||||
String videoId,
|
||||
String imageArticleId,
|
||||
final CommentEntity commentEntity,
|
||||
final TextView commentLikeCountTv,
|
||||
final ImageView commentLikeIv,
|
||||
@ -382,7 +384,7 @@ public class CommentUtils {
|
||||
String entrance = "视频流-评论-点赞";
|
||||
CheckLoginUtils.checkLogin(context, entrance, () -> {
|
||||
|
||||
PostCommentUtils.likeComment(answerId, articleId, videoId, "", commentEntity.getId(),
|
||||
PostCommentUtils.likeComment(answerId, articleId, videoId, "", imageArticleId, commentEntity.getId(),
|
||||
new PostCommentUtils.PostCommentListener() {
|
||||
@Override
|
||||
public void postSuccess(JSONObject response) {
|
||||
|
||||
@ -568,6 +568,10 @@ object DirectUtils {
|
||||
}
|
||||
}
|
||||
|
||||
"image_article" -> ARouter.getInstance().build(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.withString(KEY_IMAGE_ARTICLE_ID, linkEntity.link)
|
||||
.navigation()
|
||||
|
||||
"" -> {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@ -77,6 +77,7 @@ public class PostCommentUtils {
|
||||
String articleId,
|
||||
String videoId,
|
||||
String questionId,
|
||||
final String imageArticleId,
|
||||
final String commentId,
|
||||
final PostCommentListener listener) {
|
||||
|
||||
@ -88,6 +89,8 @@ 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);
|
||||
}
|
||||
@ -116,6 +119,7 @@ public class PostCommentUtils {
|
||||
String articleCommunityId,
|
||||
String videoId,
|
||||
String questionId,
|
||||
String imageArticleId,
|
||||
final String commentId,
|
||||
final PostCommentListener listener) {
|
||||
Observable<ResponseBody> observable;
|
||||
@ -124,6 +128,8 @@ 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);
|
||||
}
|
||||
@ -300,6 +306,25 @@ 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);
|
||||
|
||||
|
||||
@ -0,0 +1,268 @@
|
||||
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 = R.color.text_instance.toColor(context)
|
||||
private var selectedColor = 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 (animationState == AnimationState.RightPlaying) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
107
app/src/main/java/com/gh/common/view/VoteStateView.kt
Normal file
107
app/src/main/java/com/gh/common/view/VoteStateView.kt
Normal file
@ -0,0 +1,107 @@
|
||||
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) {
|
||||
R.color.text_theme
|
||||
} else {
|
||||
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(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"
|
||||
}
|
||||
}
|
||||
@ -76,6 +76,19 @@ 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,
|
||||
|
||||
224
app/src/main/java/com/gh/gamecenter/entity/ImageArticleEntity.kt
Normal file
224
app/src/main/java/com/gh/gamecenter/entity/ImageArticleEntity.kt
Normal file
@ -0,0 +1,224 @@
|
||||
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(未精选)
|
||||
/**
|
||||
* 临时变量,区分是编辑发布还是编辑草稿
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
||||
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" -> "游戏论坛"
|
||||
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,12 +36,13 @@ data class PersonalHistoryEntity(
|
||||
var length: Long = 0,
|
||||
@SerializedName("count")
|
||||
private var _count: Count = Count(),
|
||||
val time: Long = 0,
|
||||
var time: Long = 0,
|
||||
@SerializedName("title")
|
||||
|
||||
private var _title: String = "",
|
||||
var description: String = "",
|
||||
@SerializedName("community")
|
||||
private var _community: CommunityEntity = CommunityEntity(),
|
||||
private var _community: CommunityEntity? = null,
|
||||
var videos: List<CommunityVideoEntity> = ArrayList(),
|
||||
@SerializedName("user")
|
||||
private var _user: UserEntity? = null,
|
||||
@ -63,8 +64,17 @@ 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) {
|
||||
@ -104,7 +114,7 @@ data class PersonalHistoryEntity(
|
||||
}
|
||||
|
||||
override var community: CommunityEntity
|
||||
get() = _community
|
||||
get() = _community ?: CommunityEntity()
|
||||
set(value) {
|
||||
_community = value
|
||||
}
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
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 = ""
|
||||
)
|
||||
@ -2,8 +2,15 @@ package com.gh.gamecenter.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class VoteEntity(
|
||||
var vote: Int? = 0,
|
||||
data class VoteEntity(
|
||||
@SerializedName("vote")
|
||||
private val _vote: Int? = null,
|
||||
@SerializedName("is_guide_follow")
|
||||
var isGuideFollow: Boolean = false
|
||||
)
|
||||
private var _isGuideFollow: Boolean? = null
|
||||
) {
|
||||
val vote: Int
|
||||
get() = _vote ?: 0
|
||||
|
||||
val isGuideFollow: Boolean
|
||||
get() = _isGuideFollow ?: false
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
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()
|
||||
}
|
||||
@ -6,6 +6,7 @@ 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
|
||||
@ -14,6 +15,8 @@ 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
|
||||
@ -21,6 +24,7 @@ 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
|
||||
@ -47,7 +51,7 @@ class ForumArticleAskListAdapter(
|
||||
}
|
||||
|
||||
override fun areItemsTheSame(oldItem: AnswerEntity?, newItem: AnswerEntity?): Boolean {
|
||||
return oldItem?.id == newItem?.id
|
||||
return oldItem?.id == newItem?.id && oldItem?.type == newItem?.type
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
@ -55,9 +59,11 @@ class ForumArticleAskListAdapter(
|
||||
ItemViewType.ITEM_HEADER -> {
|
||||
ForumArticleHeadViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
ItemViewType.ITEM_FOOTER -> {
|
||||
FooterViewHolder(mLayoutInflater.inflate(com.gh.gamecenter.common.R.layout.refresh_footerview, parent, false))
|
||||
}
|
||||
|
||||
else -> {
|
||||
ForumArticleAskItemViewHolder(
|
||||
CommunityAnswerItemBinding.bind(
|
||||
@ -95,7 +101,8 @@ 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"
|
||||
|
||||
@ -148,6 +155,7 @@ class ForumArticleAskListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"video" -> {
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
"click_forum_detail_content",
|
||||
@ -166,6 +174,7 @@ class ForumArticleAskListAdapter(
|
||||
)
|
||||
mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, answer.id, bbsId, "论坛详情-信息流"))
|
||||
}
|
||||
|
||||
"question" -> {
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
"click_forum_detail_content",
|
||||
@ -188,6 +197,7 @@ class ForumArticleAskListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"answer" -> {
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
"click_forum_detail_content",
|
||||
@ -215,9 +225,16 @@ class ForumArticleAskListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
ARouter.getInstance().build(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.withString(EntranceConsts.KEY_IMAGE_ARTICLE_ID, answer.id)
|
||||
.navigation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ItemViewType.ITEM_FOOTER -> {
|
||||
val footerViewHolder = holder as FooterViewHolder
|
||||
footerViewHolder.initItemPadding()
|
||||
@ -225,6 +242,7 @@ class ForumArticleAskListAdapter(
|
||||
footerViewHolder.hint.textSize = 12f
|
||||
footerViewHolder.hint.setTextColor(ContextCompat.getColor(mContext, com.gh.gamecenter.common.R.color.aaaaaa))
|
||||
}
|
||||
|
||||
ItemViewType.ITEM_HEADER -> {
|
||||
if (holder is ForumArticleHeadViewHolder) {
|
||||
val articleListHead = if (path == "全部") {
|
||||
|
||||
@ -10,6 +10,7 @@ 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
|
||||
@ -18,10 +19,13 @@ 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
|
||||
@ -132,6 +136,73 @@ 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 -> {
|
||||
println("kayn -->DataCreated:${changed.imageArticle}")
|
||||
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,11 +4,13 @@ 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
|
||||
@ -58,9 +60,11 @@ class ForumArticleAskListViewModel(application: Application, val bbsId: String =
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
"精华" -> {
|
||||
RetrofitManager.getInstance().api.getEssenceForumList(bbsId, page)
|
||||
}
|
||||
|
||||
"问答" -> {
|
||||
RetrofitManager.getInstance().api.getAskForumList(
|
||||
bbsId,
|
||||
@ -68,6 +72,7 @@ class ForumArticleAskListViewModel(application: Application, val bbsId: String =
|
||||
page
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
RetrofitManager.getInstance().api.getVideoForumList(
|
||||
bbsId,
|
||||
@ -94,6 +99,28 @@ 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
|
||||
|
||||
@ -35,6 +35,7 @@ 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
|
||||
@ -56,6 +57,7 @@ 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
|
||||
@ -79,6 +81,7 @@ 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
|
||||
@ -265,12 +268,14 @@ 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)
|
||||
@ -881,7 +886,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(
|
||||
@ -1089,6 +1094,23 @@ 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 = {
|
||||
ARouter.getInstance().build(RouteConsts.activity.publishImageArticleActivity)
|
||||
.withParcelable(
|
||||
EntranceConsts.KEY_COMMUNITY_DATA,
|
||||
CommunityEntity(mBbsId, name = mForumDetail?.name ?: "", icon = icon)
|
||||
)
|
||||
.navigation()
|
||||
dialog.dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
contentView.findViewById<View>(R.id.community_edit_article_container).setOnClickListener {
|
||||
context?.ifLogin("论坛详情-发布-发帖子", action = {
|
||||
checkStoragePermissionBeforeAction {
|
||||
|
||||
@ -17,11 +17,13 @@ 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
|
||||
@ -36,6 +38,7 @@ 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
|
||||
@ -52,6 +55,8 @@ 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
|
||||
@ -127,6 +132,7 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
override fun getRealLayoutId(): Int {
|
||||
return R.layout.fragment_community_home
|
||||
}
|
||||
@ -135,7 +141,6 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
mBinding = FragmentCommunityHomeBinding.bind(inflatedView)
|
||||
}
|
||||
|
||||
|
||||
override fun onFragmentFirstVisible() {
|
||||
ArticleDetailWebCacheManager.init(requireContext().applicationContext)
|
||||
|
||||
@ -306,14 +311,14 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
?: FollowHomeFragment()
|
||||
mFragmentList.add(followFragment)
|
||||
|
||||
val forumArticleListFragment = childFragmentManager.findFragmentByTag("$tag$TAB_RECOMMEND_INDEX")
|
||||
?: ForumArticleListFragment().with(
|
||||
val recommendFragment = childFragmentManager.findFragmentByTag("$tag$TAB_RECOMMEND_INDEX")
|
||||
?: ImageArticleHomeFragment.newInstance().with(
|
||||
bundleOf(
|
||||
EntranceConsts.KEY_ENTRANCE to "社区",
|
||||
EntranceConsts.KEY_PATH to "推荐"
|
||||
)
|
||||
)
|
||||
mFragmentList.add(forumArticleListFragment)
|
||||
mFragmentList.add(recommendFragment)
|
||||
|
||||
val forumFragment = childFragmentManager.findFragmentByTag("${tag}$TAB_FORUM_INDEX")
|
||||
?: ForumFragment().with(bundleOf(EntranceConsts.KEY_ENTRANCE to "社区"))
|
||||
@ -587,6 +592,16 @@ 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.getInstance().build(RouteConsts.activity.publishImageArticleActivity).navigation()
|
||||
}
|
||||
dialog.dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
contentView.findViewById<View>(R.id.community_edit_article_container).setOnClickListener {
|
||||
context?.ifLogin("论坛首页-发布-发帖子", action = {
|
||||
showRegulationTestDialogIfNeeded {
|
||||
@ -637,6 +652,7 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun resetFollowTab() {
|
||||
mBinding?.tabLayout?.run {
|
||||
if (selectedTabPosition == TAB_FOLLOW_INDEX) {
|
||||
@ -675,13 +691,13 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
|
||||
private fun insertDataToRecommendTab(entity: ArticleEntity) {
|
||||
(mFragmentList[TAB_RECOMMEND_INDEX] as? ForumArticleListFragment)?.insertDataToFirstIndex(entity)
|
||||
// 废弃 后续会逐渐将 activityForResult迁移到 launcher
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
mBinding?.viewPager?.run {
|
||||
if (currentItem == 1) {
|
||||
return (mFragmentList[1] as ForumArticleListFragment).onBackPressed()
|
||||
return (mFragmentList[1] as ImageArticleHomeFragment).onBackPressed()
|
||||
}
|
||||
}
|
||||
return super.onBackPressed()
|
||||
|
||||
@ -8,6 +8,7 @@ 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
|
||||
|
||||
@ -6,6 +6,7 @@ import android.graphics.Color
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
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
|
||||
@ -17,6 +18,8 @@ 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.*
|
||||
@ -24,6 +27,7 @@ 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
|
||||
@ -528,6 +532,12 @@ class ForumArticleAskItemViewHolder(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
ARouter.getInstance().build(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.withString(EntranceConsts.KEY_IMAGE_ARTICLE_ID, entity.id)
|
||||
.navigation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
package com.gh.gamecenter.forum.home.recommend
|
||||
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
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() {
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return R.layout.activity_image_article_detail
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,154 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,241 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package com.gh.gamecenter.forum.home.recommend
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.VoteEntity
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
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))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,178 @@
|
||||
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.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.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
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.gh.gamecenter.qa.editor.LocalMediaActivity
|
||||
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)
|
||||
var imageArticleEntity: ImageArticleEntity? = null
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_COMMUNITY_DATA)
|
||||
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?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ARouter.getInstance().inject(this)
|
||||
|
||||
DisplayUtils.setLightStatusBar(this, true)
|
||||
setStatusBarColor(Color.TRANSPARENT)
|
||||
|
||||
tvTitle = findViewById(R.id.tv_title)
|
||||
val ivBack = findViewById<ImageView>(R.id.iv_back)
|
||||
ivBack.setOnClickListener {
|
||||
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,
|
||||
LocalMediaActivity.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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
with(viewModel) {
|
||||
val lifecycleOwner = this@PublishImageArticleActivity
|
||||
chooseImageAction.observe(lifecycleOwner, EventObserver {
|
||||
isFirstEnter = false
|
||||
PermissionHelper.checkStoragePermissionBeforeActionForResult(this@PublishImageArticleActivity) { grant ->
|
||||
if (grant) {
|
||||
this@PublishImageArticleActivity.chooseImage(it)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
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)
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
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)
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
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) {
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
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)
|
||||
}
|
||||
@ -0,0 +1,187 @@
|
||||
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.dip2px
|
||||
import com.gh.gamecenter.common.utils.display
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
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(id: String) {
|
||||
viewModel.navigateToImageArticleDetailPage(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)
|
||||
|
||||
}
|
||||
|
||||
override fun onBindDataViewHolder(holder: MyImageArticleViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||
val item = getItem(position)
|
||||
holder.bind(item, 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, payloads: List<Any?>? = null) {
|
||||
println("kayn -->bind:$payloads")
|
||||
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.id)
|
||||
}
|
||||
|
||||
setVote()
|
||||
voteState.setOnClickListener {
|
||||
val vote = !item.me.isCommunityArticleVote
|
||||
listener.voteImageArticle(item.id, vote)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnMyArticleImageListener {
|
||||
|
||||
fun navigateToImageArticleDetailPage(id: String)
|
||||
|
||||
fun voteImageArticle(id: String, vote: Boolean)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,196 @@
|
||||
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.ViewHolder
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.display
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.databinding.RecyclerRecommendHomeBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
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()
|
||||
) {
|
||||
|
||||
override fun onCreateDataViewHolder(parent: ViewGroup): RecommendHomeViewHolder {
|
||||
return RecommendHomeViewHolder(parent.toBinding(), object : OnImageArticleListener {
|
||||
override fun navigateToImageArticleDetailPage(id: String) {
|
||||
viewModel.navigateToImageArticleDetailPage(id)
|
||||
}
|
||||
|
||||
override fun voteImageArticle(id: String, vote: Boolean) {
|
||||
viewModel.useCase.voteImageArticle(id, vote)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
override fun onBindDataViewHolder(holder: RecommendHomeViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
listener.navigateToImageArticleDetailPage(item.id)
|
||||
|
||||
}
|
||||
voteState.setOnClickListener {
|
||||
val vote = !item.me.isCommunityArticleVote
|
||||
listener.voteImageArticle(item.id, vote)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnImageArticleListener {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
fun navigateToImageArticleDetailPage(id: String)
|
||||
|
||||
fun voteImageArticle(id: String, vote: Boolean)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,136 @@
|
||||
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.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.Constants
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse
|
||||
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
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class ImageArticleCommentFragment : ListFragment<CommentItemData, ImageArticleCommentViewModel>() {
|
||||
|
||||
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,
|
||||
arguments?.getString(KEY_IMAGE_ARTICLE_ID) ?: ""
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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?) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_IMAGE_ARTICLE_ID = "key_image_article_id"
|
||||
|
||||
fun newInstance(imageArticleId: String): Fragment =
|
||||
ImageArticleCommentFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putString(KEY_IMAGE_ARTICLE_ID, imageArticleId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,790 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.Path
|
||||
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.content.ContextCompat
|
||||
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.facade.annotation.Autowired
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
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.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.PublishImageArticleActivity
|
||||
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>()
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_IMAGE_ARTICLE_ID)
|
||||
var imageArticleId = ""
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_TOP_COMMENT_ID)
|
||||
var topCommentId: String? = null
|
||||
|
||||
private var showIndicator = false
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getInflatedLayout() = binding.root
|
||||
|
||||
override fun getLayoutId() = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ARouter.getInstance().inject(this)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val tag = ImageArticleDetailFragment::class.java.name
|
||||
val fragment =
|
||||
childFragmentManager.findFragmentByTag(tag) ?: ImageArticleCommentFragment.newInstance(imageArticleId)
|
||||
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.layoutLoading.root.goneIf(it != LoadStatus.INIT_LOADING)
|
||||
}
|
||||
|
||||
imageArticleDetailEntity.observe(viewLifecycleOwner) {
|
||||
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 R.color.text_theme
|
||||
} else {
|
||||
R.drawable.ic_article_detail_like_bottom_bar to 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 R.color.text_theme
|
||||
} else {
|
||||
R.drawable.ic_article_detail_star_bottom_bar to 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
|
||||
}
|
||||
toast(toastResId)
|
||||
})
|
||||
|
||||
addHighlightAction.observe(viewLifecycleOwner, EventObserver {
|
||||
toast(it)
|
||||
})
|
||||
|
||||
deleteOrHideImageArticleSuccessfully.observe(viewLifecycleOwner, EventObserver {
|
||||
val (isSuccess, toastResId) = it
|
||||
toast(toastResId)
|
||||
if (isSuccess) {
|
||||
EventBus.getDefault().post(EBImageArticleChanged.DataDeleted(imageArticleId))
|
||||
requireActivity().finish()
|
||||
}
|
||||
})
|
||||
|
||||
loadImageArticleDetail(this@ImageArticleDetailFragment.imageArticleId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun initView(view: View?) {
|
||||
super.initView(view)
|
||||
binding.vpBanner.adapter = adapter
|
||||
|
||||
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(R.color.ui_container_2, 19F)
|
||||
binding.inputContainer.replyTv.setDebouncedClickListener {
|
||||
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)
|
||||
}
|
||||
binding.inputContainer.bottomCommentTv.setOnClickListener { binding.inputContainer.bottomCommentIv.performClick() }
|
||||
|
||||
binding.inputContainer.bottomStarIv.setOnClickListener {
|
||||
requireContext().ifLogin(entrance = "帖子详情-收藏") {
|
||||
clickToastByStatus(viewModel.imageArticleDetailEntity.value?.status ?: "") {
|
||||
viewModel.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
binding.vBack.setOnClickListener {
|
||||
activity?.finish()
|
||||
}
|
||||
binding.ivAvatar.setOnClickListener {
|
||||
DirectUtils.directToHomeActivity(
|
||||
requireContext(),
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id,
|
||||
1,
|
||||
mEntrance,
|
||||
"图文详情"
|
||||
)
|
||||
}
|
||||
|
||||
binding.vpBanner.registerOnPageChangeCallback(object : OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
showNumberIndicator(position)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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, R.style.TextHeadline)
|
||||
} else {
|
||||
binding.tvAuth.goneIf(false)
|
||||
binding.tvAuth.text = imageArticle.user.auth?.text
|
||||
TextViewCompat.setTextAppearance(binding.tvName, 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, "帖子详情")
|
||||
}
|
||||
binding.ctvFollowBbs.setOnClickListener {
|
||||
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
|
||||
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) && imageArticle != null) {
|
||||
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.cancelHighlightCommunityArticle) > Permissions.GUEST
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_unselect_title),
|
||||
R.drawable.icon_more_panel_essence_cancel
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if ((moderatorPermissions.highlightCommunityArticle) > 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.hideCommunityArticle > 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
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 置顶/取消置顶
|
||||
if (imageArticle.me.isModerator
|
||||
&& !imageArticle.me.isCommunityTop
|
||||
&& moderatorPermissions.topCommunityArticle > Permissions.GUEST
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_top_title),
|
||||
R.drawable.icon_more_panel_top
|
||||
)
|
||||
)
|
||||
} else if (imageArticle.me.isModerator
|
||||
&& imageArticle.me.isCommunityTop
|
||||
&& moderatorPermissions.cancelTopCommunityArticle > Permissions.GUEST
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_cancel_top_title),
|
||||
R.drawable.icon_more_panel_top_cancel
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
}
|
||||
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) -> {
|
||||
ARouter.getInstance().build(RouteConsts.activity.publishImageArticleActivity)
|
||||
.withParcelable(
|
||||
EntranceConsts.KEY_IMAGE_ARTICLE_ENTITY,
|
||||
viewModel.imageArticleDetailEntity.value
|
||||
)
|
||||
.navigation()
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_complaint_title) -> {
|
||||
ifLogin("图文详情") {
|
||||
BbsReportHelper.showReportDialog(BbsReportHelper.ImageArticleReporter(imageArticleId))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_apply_select_title) -> {
|
||||
if (viewModel.imageArticleDetailEntity.value?.getSimplifyChoicenessStatus() == "apply") {
|
||||
ToastUtils.showToast("申请加精审核中")
|
||||
} else {
|
||||
viewModel.applyHighlightForImageArticle()
|
||||
}
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_select_title) -> {
|
||||
if (viewModel.imageArticleDetailEntity.value?.getSimplifyChoicenessStatus() == "apply") {
|
||||
ToastUtils.showToast("加精审核中")
|
||||
} else {
|
||||
showHighlightDialog(true)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
)
|
||||
}
|
||||
|
||||
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.highlightCommunityArticle > Permissions.GUEST) ||
|
||||
(!isHighlight && permissions.cancelHighlightCommunityArticle > Permissions.GUEST)
|
||||
) {
|
||||
highlightDialogHintContent =
|
||||
if ((isHighlight && permissions.highlightCommunityArticle == Permissions.REPORTER) ||
|
||||
(!isHighlight && permissions.cancelHighlightCommunityArticle == 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
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,161 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.graphics.Rect
|
||||
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(),
|
||||
R.string.confirm.toResString(),
|
||||
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 {
|
||||
// 否则,直接打开新的发布页
|
||||
ARouter.getInstance().build(RouteConsts.activity.publishImageArticleActivity)
|
||||
.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,233 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
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.common.utils.toJson
|
||||
import com.gh.gamecenter.databinding.FragmentImageArticleHomeBinding
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.forum.home.CommunityHomeViewModel
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleDetailActivity
|
||||
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 val skeletonScreen by lazy {
|
||||
Skeleton.bind(binding.flSkeleton)
|
||||
.shimmer(true)
|
||||
.angle(Constants.SHIMMER_ANGLE)
|
||||
.color(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 initRealView() {
|
||||
super.initRealView()
|
||||
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()
|
||||
}
|
||||
|
||||
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 {
|
||||
ARouter.getInstance().build(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.withString(EntranceConsts.KEY_IMAGE_ARTICLE_ID, it)
|
||||
.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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
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.findLastCompletelyVisibleItemPositions(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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,213 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Rect
|
||||
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(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 {
|
||||
ARouter.getInstance().build(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.withString(EntranceConsts.KEY_IMAGE_ARTICLE_ID, it)
|
||||
.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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,519 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
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.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 {
|
||||
if (publishingLoading.isShowing) {
|
||||
publishingLoading.dismiss()
|
||||
}
|
||||
val toastText = if (it) {
|
||||
// 发布成功
|
||||
R.string.publish_image_article_successfully.toResString()
|
||||
} else {
|
||||
// 发布失败
|
||||
R.string.publish_image_article_failure.toResString()
|
||||
}
|
||||
ToastUtils.showToast(toastText)
|
||||
if (it) {
|
||||
activity?.finish()
|
||||
}
|
||||
})
|
||||
|
||||
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, TITLE_MAX_LENGTH))
|
||||
editText.setSelection(TITLE_MAX_LENGTH) // 将光标移动到文本末尾
|
||||
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("社区")
|
||||
}, 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() {
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
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 = {
|
||||
createDraft()
|
||||
},
|
||||
cancelClickCallback = {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,116 @@
|
||||
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
|
||||
) :
|
||||
BaseCommentViewModel(application, "", "", "", "", "", "", imageArticleId) {
|
||||
|
||||
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
|
||||
) : ViewModelProvider.NewInstanceFactory() {
|
||||
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return ImageArticleCommentViewModel(application, imageArticleId) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,293 @@
|
||||
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.gamecenter.R
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.observableToMain
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
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
|
||||
|
||||
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 ?: ""
|
||||
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)
|
||||
}
|
||||
|
||||
private val _pageStatus = MutableLiveData<LoadStatus>()
|
||||
val pageStatus: LiveData<LoadStatus> = _pageStatus
|
||||
|
||||
fun loadImageArticleDetail(imageArticleId: 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)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
_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
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
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<String>>()
|
||||
val imageDetailDestination: LiveData<Event<String>> = _imageDetailDestination
|
||||
fun navigateToImageArticleDetailPage(imageArticleId: String) {
|
||||
_imageDetailDestination.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 = 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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,129 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,198 @@
|
||||
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.observableToMain
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
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 io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import okhttp3.ResponseBody
|
||||
|
||||
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<Boolean>>()
|
||||
val imageTextPublished: LiveData<Event<Boolean>> = _imageTextPublished
|
||||
fun publishImageText(title: String, content: String, images: List<ImageAndTextAdapter.LocalImage>) {
|
||||
val request = createPublishRequest(title, content)
|
||||
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)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
_imageTextPublished.value = Event(false)
|
||||
}
|
||||
|
||||
}).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
|
||||
)
|
||||
}
|
||||
@ -9,6 +9,9 @@ import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.BaseFragment_TabLayout
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toResString
|
||||
import com.gh.gamecenter.forum.home.recommend.fragment.ImageArticleHomeFragment
|
||||
import com.gh.gamecenter.forum.home.recommend.fragment.MyImageArticleListFragment
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.personalhome.home.UserHistoryViewModel
|
||||
import com.gh.gamecenter.personalhome.home.game.UserCommentHistoryFragment
|
||||
@ -25,6 +28,7 @@ class MyPostWrapperFragment : BaseFragment_TabLayout() {
|
||||
|
||||
override fun initTabTitleList(tabTitleList: MutableList<String>) {
|
||||
tabTitleList.add("评价")
|
||||
tabTitleList.add(R.string.image_article.toResString())
|
||||
tabTitleList.add(getString(R.string.collection_article))
|
||||
tabTitleList.add(getString(R.string.ask_search_questions))
|
||||
tabTitleList.add(getString(R.string.video))
|
||||
@ -50,10 +54,11 @@ class MyPostWrapperFragment : BaseFragment_TabLayout() {
|
||||
menuItem?.run {
|
||||
if (itemId == R.id.menu_draft && mLastPosition != 0) {
|
||||
val tabName = when (mLastPosition) {
|
||||
1 -> getString(R.string.collection_article)
|
||||
2 -> getString(R.string.ask_search_questions)
|
||||
3 -> getString(R.string.video)
|
||||
4 -> getString(R.string.answer)
|
||||
1 -> getString(R.string.image_article)
|
||||
2 -> getString(R.string.collection_article)
|
||||
3 -> getString(R.string.ask_search_questions)
|
||||
4 -> getString(R.string.video)
|
||||
5 -> getString(R.string.answer)
|
||||
else -> ""
|
||||
}
|
||||
NewFlatLogUtils.logHaloSelfPublishContent(tabName, "草稿箱")
|
||||
@ -64,6 +69,7 @@ class MyPostWrapperFragment : BaseFragment_TabLayout() {
|
||||
|
||||
override fun initFragmentList(fragments: MutableList<Fragment>) {
|
||||
fragments.add(UserCommentHistoryFragment.getInstance("我的发布", UserManager.getInstance().userId))
|
||||
fragments.add(MyImageArticleListFragment.newInstance())
|
||||
fragments.add(MyPostFragment.getInstance(UserHistoryViewModel.TYPE.COMMUNITY_ARTICLE))
|
||||
fragments.add(MyPostFragment.getInstance(UserHistoryViewModel.TYPE.QUESTION))
|
||||
fragments.add(MyPostFragment.getInstance(UserHistoryViewModel.TYPE.VIDEO))
|
||||
@ -75,10 +81,11 @@ class MyPostWrapperFragment : BaseFragment_TabLayout() {
|
||||
NewFlatLogUtils.logHaloSelfPublishTab(
|
||||
when (position) {
|
||||
0 -> "评价"
|
||||
1 -> getString(R.string.collection_article)
|
||||
2 -> getString(R.string.ask_search_questions)
|
||||
3 -> getString(R.string.video)
|
||||
4 -> getString(R.string.answer)
|
||||
1 -> "图文"
|
||||
2 -> getString(R.string.collection_article)
|
||||
3 -> getString(R.string.ask_search_questions)
|
||||
4 -> getString(R.string.video)
|
||||
5 -> getString(R.string.answer)
|
||||
else -> ""
|
||||
}
|
||||
)
|
||||
|
||||
@ -36,7 +36,18 @@ class PersonalItemViewHolder(
|
||||
) :
|
||||
BaseAnswerOrArticleItemViewHolder(binding.root) {
|
||||
|
||||
fun bindPersonalItem(historyEntity: PersonalHistoryEntity, entrance: String, position: Int) {
|
||||
fun bindPersonalItem(
|
||||
historyEntity: PersonalHistoryEntity,
|
||||
entrance: String,
|
||||
position: Int,
|
||||
payloads: List<Any?>? = null
|
||||
) {
|
||||
if(!payloads.isNullOrEmpty()){
|
||||
// 局部更新
|
||||
commentCount.isClickable = true
|
||||
bindCommendAndVote(historyEntity, entrance)
|
||||
return
|
||||
}
|
||||
commentCount.isClickable = true
|
||||
bindCommendAndVote(historyEntity, entrance)
|
||||
|
||||
|
||||
@ -1,42 +1,34 @@
|
||||
package com.gh.gamecenter.personalhome.home
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.util.SparseBooleanArray
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.NewsUtils
|
||||
import com.gh.common.view.ImageContainerView
|
||||
import com.gh.common.view.ImageContainerView.Companion.toImageContainerData
|
||||
import com.gh.gamecenter.ImageViewerActivity
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.adapter.viewholder.PersonalHomeRatingViewHolder
|
||||
import com.gh.gamecenter.common.baselist.ListAdapter
|
||||
import com.gh.gamecenter.common.callback.ConfirmListener
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.ItemViewType
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.databinding.RefreshFooterviewBinding
|
||||
import com.gh.gamecenter.common.utils.TextHelper
|
||||
import com.gh.gamecenter.common.utils.ifLogin
|
||||
import com.gh.gamecenter.common.utils.setTextWithHighlightedTextWrappedInsideWrapper
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.viewholder.FooterViewHolder
|
||||
import com.gh.gamecenter.core.utils.NumberUtils
|
||||
import com.gh.gamecenter.core.utils.SpanBuilder
|
||||
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
|
||||
import com.gh.gamecenter.databinding.PersonalHomeRatingBinding
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity
|
||||
import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
import com.gh.gamecenter.feature.entity.ForumVideoEntity
|
||||
import com.gh.gamecenter.forum.home.AnswerArticleVideoViewEventHelper
|
||||
import com.gh.gamecenter.forum.home.ArticleItemVideoView
|
||||
import com.gh.gamecenter.forum.home.ArticleItemVideoView.Companion.toArticleVideoData
|
||||
import com.gh.gamecenter.forum.home.follow.viewholder.FollowFooterViewHolder
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleDetailActivity
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.MyImageArticleAdapter.MyImageArticleViewHolder
|
||||
import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity
|
||||
import com.gh.gamecenter.personalhome.PersonalItemViewHolder
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
|
||||
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
|
||||
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
|
||||
import com.shuyu.gsyvideoplayer.utils.OrientationUtils
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class UserHistoryAdapter(
|
||||
@ -48,10 +40,15 @@ class UserHistoryAdapter(
|
||||
|
||||
private var mExpandSparseBooleanArray = SparseBooleanArray()
|
||||
|
||||
override fun setListData(updateData: MutableList<PersonalHistoryEntity>?) {
|
||||
super.setListData(updateData)
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return when {
|
||||
position == itemCount - 1 -> ItemViewType.ITEM_FOOTER
|
||||
mEntityList[position].type == "game_comment" -> ItemViewType.RATING_ITEM
|
||||
mListViewModel.type == UserHistoryViewModel.TYPE.IMAGE_ARTICLE -> ITEM_TYPE_IMAGE_ARTICLE
|
||||
else -> ItemViewType.ITEM_BODY
|
||||
}
|
||||
}
|
||||
@ -61,6 +58,11 @@ class UserHistoryAdapter(
|
||||
return when (viewType) {
|
||||
ItemViewType.ITEM_FOOTER -> {
|
||||
view = mLayoutInflater.inflate(com.gh.gamecenter.common.R.layout.refresh_footerview, parent, false)
|
||||
val layoutParams = view.layoutParams
|
||||
if (layoutParams is StaggeredGridLayoutManager.LayoutParams) {
|
||||
layoutParams.isFullSpan = true
|
||||
view.layoutParams = layoutParams
|
||||
}
|
||||
FooterViewHolder(view)
|
||||
}
|
||||
|
||||
@ -69,6 +71,22 @@ class UserHistoryAdapter(
|
||||
PersonalHomeRatingViewHolder(PersonalHomeRatingBinding.bind(view))
|
||||
}
|
||||
|
||||
ITEM_TYPE_IMAGE_ARTICLE -> {
|
||||
MyImageArticleViewHolder(parent.toBinding(),
|
||||
object : MyImageArticleViewHolder.OnMyArticleImageListener {
|
||||
override fun navigateToImageArticleDetailPage(id: String) {
|
||||
ARouter.getInstance().build(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.withString(EntranceConsts.KEY_IMAGE_ARTICLE_ID, id)
|
||||
.navigation()
|
||||
}
|
||||
|
||||
override fun voteImageArticle(id: String, vote: Boolean) {
|
||||
mListViewModel.useCase.voteImageArticle(id, vote)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
else -> {
|
||||
view = mLayoutInflater.inflate(R.layout.community_answer_item, parent, false)
|
||||
PersonalItemViewHolder(mContext, CommunityAnswerItemBinding.bind(view), itemClickCallback)
|
||||
@ -76,8 +94,26 @@ class UserHistoryAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: List<Any?>) {
|
||||
if (payloads.isNotEmpty()) {
|
||||
when (holder) {
|
||||
is PersonalItemViewHolder -> {
|
||||
bindNormalItem(holder, position, payloads)
|
||||
}
|
||||
|
||||
is MyImageArticleViewHolder -> {
|
||||
bindImageArticle(holder, position, payloads)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
super.onBindViewHolder(holder, position, payloads)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is MyImageArticleViewHolder -> bindImageArticle(holder, position)
|
||||
is PersonalItemViewHolder -> bindNormalItem(holder, position)
|
||||
is PersonalHomeRatingViewHolder -> bindRatingItem(holder, position)
|
||||
is FooterViewHolder -> {
|
||||
@ -87,10 +123,18 @@ class UserHistoryAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindNormalItem(holder: PersonalItemViewHolder, position: Int) {
|
||||
val historyEntity = mEntityList[holder.adapterPosition]
|
||||
private fun bindImageArticle(
|
||||
holder: MyImageArticleViewHolder,
|
||||
position: Int,
|
||||
payloads: List<Any?>? = null
|
||||
) {
|
||||
val historyEntity = mEntityList[position]
|
||||
holder.bind(historyEntity, payloads)
|
||||
}
|
||||
|
||||
holder.bindPersonalItem(historyEntity, mEntrance, position)
|
||||
private fun bindNormalItem(holder: PersonalItemViewHolder, position: Int, payloads: List<Any?>? = null) {
|
||||
val historyEntity = mEntityList[holder.adapterPosition]
|
||||
holder.bindPersonalItem(historyEntity, mEntrance, position, payloads)
|
||||
}
|
||||
|
||||
private fun bindRatingItem(holder: PersonalHomeRatingViewHolder, position: Int) {
|
||||
@ -159,4 +203,9 @@ class UserHistoryAdapter(
|
||||
override fun getItemCount(): Int {
|
||||
return if (mEntityList == null || mEntityList.isEmpty()) 0 else mEntityList.size + 1
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val USER_HISTORY_PAYLOADS_VOTE_CHANGED = "user_history_payloads_vote_changed"
|
||||
private const val ITEM_TYPE_IMAGE_ARTICLE = 110
|
||||
}
|
||||
}
|
||||
@ -7,21 +7,32 @@ import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
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.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.view.FixLinearLayoutManager
|
||||
import com.gh.gamecenter.core.utils.MD5Utils
|
||||
import com.gh.gamecenter.databinding.FragmentUserPublishBinding
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.feature.entity.ForumVideoEntity
|
||||
import com.gh.gamecenter.feature.entity.PersonalEntity
|
||||
import com.gh.gamecenter.forum.home.ForumScrollCalculatorHelper
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleDetailActivity
|
||||
import com.gh.gamecenter.forum.home.recommend.fragment.ImageArticleHomeFragment
|
||||
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
|
||||
import com.gh.gamecenter.personalhome.home.UserHistoryAdapter.Companion.USER_HISTORY_PAYLOADS_VOTE_CHANGED
|
||||
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
|
||||
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
|
||||
import com.gh.gamecenter.qa.entity.QuestionsDetailEntity
|
||||
@ -30,6 +41,8 @@ import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
|
||||
import com.gh.gamecenter.video.detail.CustomManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewModel>() {
|
||||
|
||||
@ -79,6 +92,68 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
})
|
||||
}
|
||||
|
||||
@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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateImageArticleItem(
|
||||
id: String,
|
||||
hasPayload: Boolean,
|
||||
block: (PersonalHistoryEntity) -> 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 onResume() {
|
||||
resumeVideo()
|
||||
super.onResume()
|
||||
@ -148,12 +223,14 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
mBinding?.run {
|
||||
allType.text = "全部 ${mCount.getTotalCount()}"
|
||||
videoType.text = "视频 ${mCount.video}"
|
||||
imageArticleType.text = getString(R.string.image_article_with_count, "${mCount.imageArticle}")
|
||||
articleType.text = "帖子 ${mCount.communityArticle}"
|
||||
questionType.text = "提问 ${mCount.question}"
|
||||
answerType.text = "回答 ${mCount.answer}"
|
||||
|
||||
val typePairList = arrayListOf(
|
||||
Pair(UserHistoryViewModel.TYPE.ALL, allType),
|
||||
Pair(UserHistoryViewModel.TYPE.IMAGE_ARTICLE, imageArticleType),
|
||||
Pair(UserHistoryViewModel.TYPE.VIDEO, videoType),
|
||||
Pair(UserHistoryViewModel.TYPE.COMMUNITY_ARTICLE, articleType),
|
||||
Pair(UserHistoryViewModel.TYPE.QUESTION, questionType),
|
||||
@ -208,18 +285,26 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
UserHistoryViewModel.TYPE.ALL -> {
|
||||
allType.text = "全部 $count"
|
||||
}
|
||||
|
||||
UserHistoryViewModel.TYPE.IMAGE_ARTICLE -> {
|
||||
imageArticleType.text = getString(R.string.image_article_with_count, "$count")
|
||||
}
|
||||
|
||||
UserHistoryViewModel.TYPE.VIDEO -> {
|
||||
mCount.video = count
|
||||
videoType.text = "视频 $count"
|
||||
}
|
||||
|
||||
UserHistoryViewModel.TYPE.COMMUNITY_ARTICLE -> {
|
||||
mCount.communityArticle = count
|
||||
articleType.text = "帖子 $count"
|
||||
}
|
||||
|
||||
UserHistoryViewModel.TYPE.QUESTION -> {
|
||||
mCount.question = count
|
||||
questionType.text = "提问 $count"
|
||||
}
|
||||
|
||||
UserHistoryViewModel.TYPE.ANSWER -> {
|
||||
mCount.answer = count
|
||||
answerType.text = "回答 $count"
|
||||
@ -288,6 +373,10 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
104,
|
||||
position
|
||||
)
|
||||
} else if (historyEntity.type == "image_article") {
|
||||
ARouter.getInstance().build(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.withString(EntranceConsts.KEY_IMAGE_ARTICLE_ID, historyEntity.id)
|
||||
.navigation()
|
||||
} else if (!historyEntity.type.contains("question")) {
|
||||
val intent = NewQuestionDetailActivity.getSpecifiedCommentIntent(
|
||||
requireContext(),
|
||||
@ -329,9 +418,35 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
return mAdapter!!
|
||||
}
|
||||
|
||||
|
||||
override fun onChanged(ts: MutableList<PersonalHistoryEntity>?) {
|
||||
if (ts != null) {
|
||||
val layoutManager = mListRv.layoutManager ?: return
|
||||
if (mViewModel?.type == UserHistoryViewModel.TYPE.IMAGE_ARTICLE) {
|
||||
if (layoutManager !is StaggeredGridLayoutManager) {
|
||||
mListRv.layoutManager = StaggeredGridLayoutManager(2, RecyclerView.VERTICAL)
|
||||
if (mListRv.itemDecorationCount == 0) {
|
||||
itemDecoration?.let(mListRv::addItemDecoration)
|
||||
}
|
||||
mListRv.adapter = mAdapter
|
||||
}
|
||||
} else {
|
||||
if (layoutManager is StaggeredGridLayoutManager) {
|
||||
mListRv.layoutManager = FixLinearLayoutManager(requireContext())
|
||||
if (mListRv.itemDecorationCount > 0) {
|
||||
mItemDecoration?.let(mListRv::removeItemDecoration)
|
||||
}
|
||||
mListRv.adapter = mAdapter
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onChanged(ts)
|
||||
}
|
||||
|
||||
private fun getCurrentTabName(): String {
|
||||
return when (mCurrentType) {
|
||||
UserHistoryViewModel.TYPE.ALL -> "全部"
|
||||
UserHistoryViewModel.TYPE.IMAGE_ARTICLE -> "图文"
|
||||
UserHistoryViewModel.TYPE.VIDEO -> "视频"
|
||||
UserHistoryViewModel.TYPE.COMMUNITY_ARTICLE -> "帖子"
|
||||
UserHistoryViewModel.TYPE.QUESTION -> "提问"
|
||||
@ -339,7 +454,14 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemDecoration() = null
|
||||
override fun getItemDecoration(): ItemDecoration? {
|
||||
mItemDecoration = if (mCurrentType == UserHistoryViewModel.TYPE.IMAGE_ARTICLE) {
|
||||
ImageArticleHomeFragment.MyItemDecoration()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return mItemDecoration
|
||||
}
|
||||
|
||||
override fun onRefresh() {
|
||||
mScrollCalculatorHelper?.currentPlayer?.release()
|
||||
@ -398,6 +520,7 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
me.isVoted = resultData?.me?.isVoted ?: false
|
||||
}
|
||||
}
|
||||
|
||||
101 -> {
|
||||
val resultData =
|
||||
data.getParcelableExtra<ArticleDetailEntity>(ArticleDetailEntity::class.java.simpleName)
|
||||
@ -411,6 +534,7 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
me.isCommunityArticleVote = resultData?.me?.isCommunityArticleVote ?: false
|
||||
}
|
||||
}
|
||||
|
||||
102 -> {
|
||||
val resultData =
|
||||
data.getParcelableExtra<CommentEntity>(CommentEntity::class.java.simpleName)
|
||||
@ -421,6 +545,8 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
me.isAnswerVoted = resultData?.me?.isCommentVoted ?: false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
103 -> {
|
||||
val resultData =
|
||||
data.getParcelableExtra<QuestionsDetailEntity>(QuestionsDetailEntity::class.java.simpleName)
|
||||
@ -431,6 +557,7 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
104 -> {
|
||||
val resultData =
|
||||
data.getParcelableExtra<ForumVideoEntity>(ForumVideoEntity::class.java.simpleName)
|
||||
@ -468,6 +595,7 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
const val DEFAULT_TYPE = "default_type"
|
||||
const val PATH_USER_COMMENT = "个人主页-评论"
|
||||
const val PATH_USER_QUESTION_ANSWER = "个人主页-问答"
|
||||
|
||||
fun getInstance(
|
||||
userId: String,
|
||||
scene: UserHistoryViewModel.SCENE,
|
||||
|
||||
@ -16,11 +16,16 @@ import com.gh.gamecenter.common.entity.ErrorEntity
|
||||
import com.gh.gamecenter.feature.entity.ForumVideoEntity
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
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.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.HttpException
|
||||
@ -36,6 +41,10 @@ class UserHistoryViewModel(
|
||||
var videoList = arrayListOf<ForumVideoEntity>()
|
||||
var count = MutableLiveData<Int>()
|
||||
|
||||
private val imageArticleRepository = ImageArticleRepository.newInstance()
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
val useCase = ImageArticleUseCase(imageArticleRepository, compositeDisposable)
|
||||
|
||||
init {
|
||||
setOverLimitSize(1)
|
||||
}
|
||||
@ -50,7 +59,6 @@ class UserHistoryViewModel(
|
||||
|
||||
override fun mergeResultLiveData() {
|
||||
mResultLiveData.addSource(mListLiveData) { list ->
|
||||
|
||||
videoList = ArrayList(list.map { it.transformForumVideoEntity() })
|
||||
|
||||
mResultLiveData.postValue(list)
|
||||
@ -132,6 +140,16 @@ class UserHistoryViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
enum class SCENE(val value: String) {
|
||||
COMMENT("comment"),
|
||||
QUESTION_ANSWER("question_answer")
|
||||
@ -139,6 +157,7 @@ class UserHistoryViewModel(
|
||||
|
||||
enum class TYPE(val value: String) {
|
||||
ALL("all"),
|
||||
IMAGE_ARTICLE("image_article"),
|
||||
VIDEO("video"),
|
||||
COMMUNITY_ARTICLE("community_article"),
|
||||
ANSWER("answer"),
|
||||
|
||||
@ -4,17 +4,21 @@ import android.annotation.SuppressLint
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import com.airbnb.lottie.LottieAnimationView
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.LogUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.feature.view.GameIconView
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
|
||||
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.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.*
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity
|
||||
import com.gh.gamecenter.entity.VoteEntity
|
||||
import com.gh.gamecenter.forum.detail.ForumDetailActivity
|
||||
@ -24,6 +28,7 @@ import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
import com.gh.gamecenter.feature.entity.CommunityItemData
|
||||
import com.gh.gamecenter.feature.entity.ArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.Count
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleDetailActivity
|
||||
import com.gh.gamecenter.qa.entity.QuestionsDetailEntity
|
||||
import com.gh.gamecenter.qa.questions.invite.QuestionsInviteActivity
|
||||
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
|
||||
@ -267,6 +272,12 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
|
||||
)
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
ARouter.getInstance().build(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.withString(EntranceConsts.KEY_IMAGE_ARTICLE_ID, entity.id)
|
||||
.navigation()
|
||||
}
|
||||
|
||||
else -> {
|
||||
val communityId = entity.community.id
|
||||
val intent = ArticleDetailActivity.getCommentIntent(
|
||||
@ -398,19 +409,27 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
|
||||
}
|
||||
})
|
||||
} else {
|
||||
val voteObservable = if (entity.type == "community_article") {
|
||||
RetrofitManager.getInstance().api.postCommunityArticleVote(entity.id)
|
||||
} else {
|
||||
RetrofitManager.getInstance().api
|
||||
.postVoteQuestionComment(entity.questions.id, entity.id)
|
||||
.map { GsonUtils.fromJson(it.string(), VoteEntity::class.java) }
|
||||
when (entity.type) {
|
||||
"community_article" -> {
|
||||
RetrofitManager.getInstance().api.postCommunityArticleVote(entity.id)
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
RetrofitManager.getInstance().api.voteArticleImage(entity.id)
|
||||
.toObservable()
|
||||
}
|
||||
|
||||
else -> {
|
||||
RetrofitManager.getInstance().api
|
||||
.postVoteQuestionComment(entity.questions.id, entity.id)
|
||||
.map { GsonUtils.fromJson(it.string(), VoteEntity::class.java) }
|
||||
}
|
||||
}
|
||||
voteObservable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Response<VoteEntity>() {
|
||||
override fun onResponse(response: VoteEntity?) {
|
||||
if (entity.type == "community_article") {
|
||||
if (entity.type == "community_article" || entity.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE) {
|
||||
entity.me.isCommunityArticleVote = true
|
||||
} else {
|
||||
entity.me.isAnswerVoted = true
|
||||
@ -484,18 +503,26 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
|
||||
}
|
||||
})
|
||||
} else {
|
||||
val unVoteObservable = if (entity.type == "community_article") {
|
||||
RetrofitManager.getInstance().api.postCommunityArticleUnVote(entity.id)
|
||||
} else {
|
||||
RetrofitManager.getInstance().api
|
||||
.postAnswerUnvote(entity.id)
|
||||
when (entity.type) {
|
||||
"community_article" -> {
|
||||
RetrofitManager.getInstance().api.postCommunityArticleUnVote(entity.id)
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
RetrofitManager.getInstance().api.unVoteArticleImage(entity.id)
|
||||
.toObservable()
|
||||
}
|
||||
|
||||
else -> {
|
||||
RetrofitManager.getInstance().api
|
||||
.postAnswerUnvote(entity.id)
|
||||
}
|
||||
}
|
||||
unVoteObservable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Response<VoteEntity>() {
|
||||
override fun onResponse(response: VoteEntity?) {
|
||||
if (entity.type == "community_article") {
|
||||
if (entity.type == "community_article" || entity.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE) {
|
||||
entity.me.isCommunityArticleVote = false
|
||||
} else {
|
||||
entity.me.isAnswerVoted = false
|
||||
|
||||
@ -13,7 +13,6 @@ import com.gh.gamecenter.common.utils.viewModelProvider
|
||||
import com.gh.gamecenter.common.view.CustomDividerItemDecoration
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentAdapter
|
||||
import com.halo.assistant.HaloApp
|
||||
import splitties.views.backgroundColor
|
||||
|
||||
class ArticleDetailCommentListFragment : ListFragment<CommentItemData, ArticleDetailCommentListViewModel>() {
|
||||
|
||||
|
||||
@ -793,7 +793,8 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
|
||||
|
||||
getString(R.string.article_detail_more_complaint_title) -> {
|
||||
ifLogin("帖子详情") {
|
||||
BbsReportHelper.showReportDialog(mViewModel.detailEntity?.id ?: "")
|
||||
|
||||
BbsReportHelper.showReportDialog(BbsReportHelper.PostsReporter(mViewModel.detailEntity?.id ?: ""))
|
||||
}
|
||||
NewLogUtils.logSharePanelClick(
|
||||
"click_report",
|
||||
@ -991,7 +992,6 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
|
||||
mBinding.inputContainer.bottomCommentTv.text = mViewModel.getCommentText(
|
||||
mViewModel.detailEntity?.count?.comment ?: 0, "评论"
|
||||
)
|
||||
|
||||
ImageUtils.display(mBinding.userAvatar, articleDetail.user.icon)
|
||||
|
||||
if (!mEntrance.contains("论坛详情")) {
|
||||
|
||||
@ -49,6 +49,7 @@ class CommentActivity : BaseActivity() {
|
||||
val commentId = intent.getStringExtra(KEY_COMMENT_ID) ?: ""
|
||||
val gameCollectionId = intent.getStringExtra(GAME_COLLECTION_ID) ?: ""
|
||||
val gameCollectionTitle = intent.getStringExtra(GAME_COLLECTION_TITLE) ?: ""
|
||||
val imageArticleId = intent.getStringExtra(IMAGE_ARTICLE_ID) ?: ""
|
||||
|
||||
val isVideoAuthor = intent.getBooleanExtra(IS_VIDEO_AUTHOR, false)
|
||||
val isStairsComment = intent.getBooleanExtra(IS_STAIRS_COMMENT, false)
|
||||
@ -82,9 +83,11 @@ class CommentActivity : BaseActivity() {
|
||||
isCommentConversation && gameCollectionId.isNotEmpty() && commentId.isNotEmpty() -> {
|
||||
GameCollectionCommentConversationFragment().with(intent.extras)
|
||||
}
|
||||
|
||||
isCommentConversation && commentId.isNotEmpty() -> {
|
||||
CommentConversationFragment().with(intent.extras)
|
||||
}
|
||||
|
||||
answerId.isNotEmpty() -> {
|
||||
NewCommentFragment.getAnswerCommentInstance(
|
||||
answerId,
|
||||
@ -94,6 +97,7 @@ class CommentActivity : BaseActivity() {
|
||||
commentCallback
|
||||
)
|
||||
}
|
||||
|
||||
articleId.isNotEmpty() -> {
|
||||
NewCommentFragment.getCommunityArticleCommentInstance(
|
||||
articleId,
|
||||
@ -106,6 +110,7 @@ class CommentActivity : BaseActivity() {
|
||||
commentCallback
|
||||
)
|
||||
}
|
||||
|
||||
questionId.isNotEmpty() -> {
|
||||
NewCommentFragment.getCommunityQuestionCommentInstance(
|
||||
questionId,
|
||||
@ -118,6 +123,7 @@ class CommentActivity : BaseActivity() {
|
||||
commentCallback
|
||||
)
|
||||
}
|
||||
|
||||
gameCollectionId.isNotEmpty() -> {
|
||||
NewCommentFragment.getGameCollectionCommentInstance(
|
||||
gameCollectionId,
|
||||
@ -131,6 +137,18 @@ class CommentActivity : BaseActivity() {
|
||||
commentCallback
|
||||
)
|
||||
}
|
||||
|
||||
imageArticleId.isNotEmpty() -> {
|
||||
NewCommentFragment.getImageArticleCommentInstance(
|
||||
imageArticleId,
|
||||
showKeyboard,
|
||||
commentCount,
|
||||
mShowInputOnly,
|
||||
commentEntity,
|
||||
commentCallback
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
NewCommentFragment.getVideoCommentInstance(
|
||||
videoId,
|
||||
@ -197,6 +215,8 @@ class CommentActivity : BaseActivity() {
|
||||
|
||||
const val REQUEST_CODE = 8123
|
||||
|
||||
const val IMAGE_ARTICLE_ID = "image_article_id"
|
||||
|
||||
@JvmStatic
|
||||
fun getAnswerCommentIntent(
|
||||
context: Context,
|
||||
@ -280,6 +300,7 @@ class CommentActivity : BaseActivity() {
|
||||
articleId: String,
|
||||
videoId: String,
|
||||
questionId: String,
|
||||
imageArticleId: String,
|
||||
showKeyboard: Boolean = false,
|
||||
position: Int = -1,
|
||||
entrance: String,
|
||||
@ -290,6 +311,7 @@ class CommentActivity : BaseActivity() {
|
||||
intent.putExtra(EntranceConsts.KEY_COMMUNITY_ARTICLE_ID, articleId)
|
||||
intent.putExtra(VIDEO_ID, videoId)
|
||||
intent.putExtra(QUESTION_ID, questionId)
|
||||
intent.putExtra(IMAGE_ARTICLE_ID, imageArticleId)
|
||||
intent.putExtra(EntranceConsts.KEY_COMMUNITY_ID, communityId)
|
||||
intent.putExtra(EntranceConsts.KEY_POSITION, position)
|
||||
intent.putExtra(KEY_COMMENT_ID, commentId)
|
||||
@ -446,6 +468,30 @@ class CommentActivity : BaseActivity() {
|
||||
return intent
|
||||
}
|
||||
|
||||
/**
|
||||
* 回复图文评论
|
||||
*/
|
||||
fun getImageArticleCommentReplyIntent(
|
||||
context: Context,
|
||||
imageArticleId: String,
|
||||
commentId: String,
|
||||
commentCount: Int? = 0,
|
||||
commentEntity: CommentEntity? = null
|
||||
): Intent {
|
||||
val intent = Intent(context, CommentActivity::class.java)
|
||||
intent.putExtra(KEY_COMMENT_ID, commentId)
|
||||
intent.putExtra(COMMENT_COUNT, commentCount)
|
||||
intent.putExtra(SHOW_KEYBOARD, true)
|
||||
intent.putExtra(SHOW_INPUT_ONLY, true)
|
||||
intent.putExtra(COMMENT_ENTITY, commentEntity)
|
||||
intent.putExtra(IMAGE_ARTICLE_ID, imageArticleId)
|
||||
intent.putExtra(USE_REPLY_API, true)
|
||||
if (context is Activity) {
|
||||
context.overridePendingTransition(0, 0)
|
||||
}
|
||||
return intent
|
||||
}
|
||||
|
||||
/**
|
||||
* 游戏单评论对话
|
||||
*/
|
||||
@ -467,6 +513,28 @@ class CommentActivity : BaseActivity() {
|
||||
intent.putExtra(EntranceConsts.KEY_IS_COMMENT_CONVERSATION, true)
|
||||
return intent
|
||||
}
|
||||
|
||||
/**
|
||||
* 评论图文
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getImageArticleCommentIntent(
|
||||
context: Context,
|
||||
imageArticleId: String,
|
||||
communityId: String,
|
||||
commentCount: Int? = 0,
|
||||
): Intent {
|
||||
val intent = Intent(context, CommentActivity::class.java)
|
||||
intent.putExtra(IMAGE_ARTICLE_ID, imageArticleId)
|
||||
intent.putExtra(COMMENT_COUNT, commentCount)
|
||||
intent.putExtra(SHOW_KEYBOARD, true)
|
||||
intent.putExtra(COMMUNITY_ID, communityId)
|
||||
intent.putExtra(SHOW_INPUT_ONLY, true)
|
||||
if (context is Activity) {
|
||||
context.overridePendingTransition(0, 0)
|
||||
}
|
||||
return intent
|
||||
}
|
||||
}
|
||||
|
||||
interface CommentListener {
|
||||
|
||||
@ -172,6 +172,7 @@ class NewCommentAdapter(
|
||||
mViewModel.communityId,
|
||||
mViewModel.videoId,
|
||||
mViewModel.questionId,
|
||||
mViewModel.imageArticleId,
|
||||
commentEntity,
|
||||
holder.commentLikeCountTv,
|
||||
holder.commentLikeIv,
|
||||
@ -251,6 +252,8 @@ class NewCommentAdapter(
|
||||
|
||||
CommentType.GAME_COLLECTION,
|
||||
CommentType.GAME_COLLECTION_CONVERSATION -> "游戏单详情-评论管理"
|
||||
|
||||
CommentType.IMAGE_ARTICLE -> "图文详情-评论管理"
|
||||
}
|
||||
|
||||
val userHomePageTabPosition = if (mViewModel.commentType.isVideo()) 2 else 1
|
||||
|
||||
@ -44,9 +44,12 @@ class NewCommentConversationFragment : NewCommentFragment() {
|
||||
mVideoId = arguments?.getString(CommentActivity.VIDEO_ID) ?: ""
|
||||
mIsVideoAuthor = arguments?.getBoolean(CommentActivity.IS_VIDEO_AUTHOR, false) ?: false
|
||||
|
||||
mImageArticleId = arguments?.getString(CommentActivity.IMAGE_ARTICLE_ID) ?: ""
|
||||
|
||||
mCommentType = when {
|
||||
mAnswerId.isNotEmpty() -> CommentType.ANSWER_CONVERSATION
|
||||
mArticleId.isNotEmpty() -> CommentType.COMMUNITY_ARTICLE_CONVERSATION
|
||||
mImageArticleId.isNotEmpty() -> CommentType.IMAGE_ARTICLE
|
||||
else -> CommentType.VIDEO_CONVERSATION
|
||||
}
|
||||
|
||||
|
||||
@ -42,6 +42,7 @@ import com.gh.gamecenter.feature.eventbus.EBDeleteComment
|
||||
import com.gh.gamecenter.feature.selector.ChooseType
|
||||
import com.gh.gamecenter.qa.comment.CommentActivity.Companion.GAME_COLLECTION_ID
|
||||
import com.gh.gamecenter.qa.comment.CommentActivity.Companion.GAME_COLLECTION_TITLE
|
||||
import com.gh.gamecenter.qa.comment.CommentActivity.Companion.IMAGE_ARTICLE_ID
|
||||
import com.gh.gamecenter.qa.comment.CommentActivity.Companion.QUESTION_ID
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Util_System_Keyboard
|
||||
@ -82,6 +83,7 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
protected var mGameCollectionTitle: String = ""
|
||||
protected var mCommentId: String = ""
|
||||
protected var mRootCommentId: String = ""
|
||||
protected var mImageArticleId: String = ""
|
||||
protected var mShowInputOnly: Boolean = false // 是否只显示输入框,不显示列表
|
||||
protected var mIsVideoAuthor: Boolean = false//是否是视频作者
|
||||
protected var mCommentType = CommentType.ANSWER
|
||||
@ -130,6 +132,7 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
mShowInputOnly = getBoolean(SHOW_INPUT_ONLY, false)
|
||||
mCommentEntity = getParcelable(COMMENT_ENTITY)
|
||||
mIsVideoAuthor = getBoolean(IS_VIDEO_AUTHOR, false)
|
||||
mImageArticleId = getString(IMAGE_ARTICLE_ID) ?: ""
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -229,6 +232,8 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
CommentType.GAME_COLLECTION,
|
||||
CommentType.GAME_COLLECTION_CONVERSATION -> "游戏单评论及回复"
|
||||
|
||||
CommentType.IMAGE_ARTICLE -> "图文的评论和回复"
|
||||
|
||||
else -> ""
|
||||
}
|
||||
ErrorHelper.handleError(
|
||||
@ -412,7 +417,8 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
gameCollectionId = mGameCollectionId,
|
||||
rootCommentId = mRootCommentId,
|
||||
commentType = mCommentType,
|
||||
isVideoAuthor = mIsVideoAuthor
|
||||
isVideoAuthor = mIsVideoAuthor,
|
||||
imageArticleId = mImageArticleId
|
||||
)
|
||||
)
|
||||
return mViewModel
|
||||
@ -435,6 +441,8 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
|
||||
CommentType.GAME_COLLECTION,
|
||||
CommentType.GAME_COLLECTION_CONVERSATION -> "(游戏单详情-评论列表)"
|
||||
|
||||
CommentType.IMAGE_ARTICLE -> "图文详情-评论列表"
|
||||
}
|
||||
mAdapter = NewCommentAdapter(requireContext(), mViewModel, true, this, this, entrance)
|
||||
}
|
||||
@ -598,6 +606,10 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
"游戏单详情-评论-回复"
|
||||
}
|
||||
}
|
||||
|
||||
CommentType.IMAGE_ARTICLE -> {
|
||||
"图文详情-评论-写评论"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -945,5 +957,28 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun getImageArticleCommentInstance(
|
||||
imageArticleId: String,
|
||||
showSoftKeyboardOnStartUp: Boolean,
|
||||
commentCount: Int,
|
||||
showInputOnly: Boolean,
|
||||
commentEntity: CommentEntity?,
|
||||
listener: CommentActivity.CommentListener
|
||||
): NewCommentFragment {
|
||||
return NewCommentFragment().apply {
|
||||
mCommentListener = listener
|
||||
with(
|
||||
bundleOf(
|
||||
SHOW_SOFT_KEY_BOARD_ON_STARTUP to showSoftKeyboardOnStartUp,
|
||||
IMAGE_ARTICLE_ID to imageArticleId,
|
||||
COMMENT_COUNT to commentCount,
|
||||
COMMENT_TYPE to CommentType.IMAGE_ARTICLE,
|
||||
SHOW_INPUT_ONLY to showInputOnly,
|
||||
COMMENT_ENTITY to commentEntity
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,7 +29,6 @@ import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import retrofit2.HttpException
|
||||
|
||||
@ -44,7 +43,8 @@ open class NewCommentViewModel(
|
||||
var gameCollectionId: String = "",
|
||||
var rootCommentId: String = "",
|
||||
var commentType: CommentType = CommentType.ANSWER,
|
||||
var isVideoAuthor: Boolean = false
|
||||
var isVideoAuthor: Boolean = false,
|
||||
var imageArticleId: String = ""
|
||||
) : ListViewModel<CommentEntity, CommentEntity>(application) {
|
||||
|
||||
private val mPostCommentLiveData = MutableLiveData<ApiResponse<JSONObject>>()
|
||||
@ -138,6 +138,7 @@ open class NewCommentViewModel(
|
||||
this.articleDetail = it
|
||||
}, {})
|
||||
}
|
||||
|
||||
CommentType.VIDEO,
|
||||
CommentType.VIDEO_CONVERSATION -> {
|
||||
api.getBbsVideoDetail(videoId)
|
||||
@ -147,6 +148,7 @@ open class NewCommentViewModel(
|
||||
this.videoDetail = it
|
||||
}, {})
|
||||
}
|
||||
|
||||
CommentType.COMMUNITY_QUESTION,
|
||||
CommentType.COMMUNITY_QUESTION_CONVERSATION -> {
|
||||
api.getQuestionsById(questionId)
|
||||
@ -156,6 +158,7 @@ open class NewCommentViewModel(
|
||||
this.questionDetail = it
|
||||
}, {})
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@ -165,8 +168,7 @@ open class NewCommentViewModel(
|
||||
CommentType.COMMUNITY_QUESTION,
|
||||
CommentType.COMMUNITY_QUESTION_CONVERSATION -> {
|
||||
questionDetail?.let {
|
||||
if (reply)
|
||||
{
|
||||
if (reply) {
|
||||
SensorsBridge.trackArticleReply(
|
||||
customerType = it.user.auth?.text ?: "",
|
||||
articleId = it.id ?: "",
|
||||
@ -439,6 +441,15 @@ open class NewCommentViewModel(
|
||||
api.postReplyToGameCollectionComment(gameCollectionId, commentEntity.id, body)
|
||||
}
|
||||
}
|
||||
|
||||
CommentType.IMAGE_ARTICLE -> {
|
||||
if (commentEntity == null) {
|
||||
api.postImageArticleComment(imageArticleId, body)
|
||||
} else {
|
||||
api.postReplyToImageArticleComment(commentEntity.id, body)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Remove this apiResponse crap.
|
||||
@ -632,7 +643,8 @@ open class NewCommentViewModel(
|
||||
private val gameCollectionId: String = "",
|
||||
private val rootCommentId: String = "",
|
||||
private val isVideoAuthor: Boolean = false,
|
||||
private val commentType: CommentType
|
||||
private val commentType: CommentType,
|
||||
private val imageArticleId: String = ""
|
||||
) : ViewModelProvider.NewInstanceFactory() {
|
||||
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
@ -647,7 +659,8 @@ open class NewCommentViewModel(
|
||||
commentId = commentId,
|
||||
rootCommentId = rootCommentId,
|
||||
commentType = commentType,
|
||||
isVideoAuthor = isVideoAuthor
|
||||
isVideoAuthor = isVideoAuthor,
|
||||
imageArticleId = imageArticleId
|
||||
) as T
|
||||
}
|
||||
}
|
||||
@ -667,7 +680,9 @@ enum class CommentType {
|
||||
VIDEO_CONVERSATION,
|
||||
|
||||
GAME_COLLECTION,
|
||||
GAME_COLLECTION_CONVERSATION;
|
||||
GAME_COLLECTION_CONVERSATION,
|
||||
IMAGE_ARTICLE;
|
||||
|
||||
|
||||
fun isVideo(): Boolean {
|
||||
return (this == VIDEO || this == VIDEO_CONVERSATION)
|
||||
|
||||
@ -39,6 +39,8 @@ class StairsCommentFragment : NewCommentFragment() {
|
||||
|
||||
CommentType.GAME_COLLECTION,
|
||||
CommentType.GAME_COLLECTION_CONVERSATION -> "(游戏单详情-评论列表)"
|
||||
|
||||
CommentType.IMAGE_ARTICLE -> "(图文详情-评论列表)"
|
||||
}
|
||||
mAdapter = StairsCommentAdapter(requireContext(), mViewModel, true, this, this, entrance)
|
||||
}
|
||||
|
||||
@ -261,6 +261,7 @@ class StairsCommentViewHolder(
|
||||
mViewModel.articleId,
|
||||
mViewModel.communityId,
|
||||
mViewModel.videoId,
|
||||
mViewModel.imageArticleId,
|
||||
commentEntity,
|
||||
holder.binding.commentLikeCount,
|
||||
holder.binding.commentLike,
|
||||
@ -314,6 +315,8 @@ class StairsCommentViewHolder(
|
||||
|
||||
CommentType.GAME_COLLECTION,
|
||||
CommentType.GAME_COLLECTION_CONVERSATION -> "游戏单详情-评论管理"
|
||||
|
||||
CommentType.IMAGE_ARTICLE ->"图文详情-评论管理"
|
||||
}
|
||||
holder.binding.commentUserIcon.setOnClickListener {
|
||||
DirectUtils.directToHomeActivity(
|
||||
|
||||
@ -32,6 +32,7 @@ import com.gh.gamecenter.core.utils.SpanBuilder
|
||||
import com.gh.gamecenter.databinding.*
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.feature.entity.Permissions
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleUseCase
|
||||
import com.gh.gamecenter.qa.article.detail.*
|
||||
import com.gh.gamecenter.qa.comment.CommentActivity
|
||||
import com.gh.gamecenter.qa.comment.CommentPictureAdapter
|
||||
@ -178,6 +179,7 @@ abstract class BaseCommentAdapter(
|
||||
|
||||
//刷新 ITEM_FILTER
|
||||
mViewModel.commentCount -= 1
|
||||
mViewModel.updateCommentCount(mViewModel.commentCount)
|
||||
notifyItemChanged(1)
|
||||
|
||||
val isArticleDetail = this is ArticleDetailAdapter
|
||||
@ -241,14 +243,17 @@ abstract class BaseCommentAdapter(
|
||||
binding.progressBar.visibility = View.GONE
|
||||
binding.footerTv.setText(com.gh.gamecenter.common.R.string.loading_failed_retry)
|
||||
}
|
||||
|
||||
isOver -> {
|
||||
binding.progressBar.visibility = View.GONE
|
||||
binding.footerTv.setText(loadOverHint)
|
||||
}
|
||||
|
||||
isLoading -> {
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
binding.footerTv.setText(com.gh.gamecenter.common.R.string.loading)
|
||||
}
|
||||
|
||||
else -> {
|
||||
binding.progressBar.visibility = View.GONE
|
||||
}
|
||||
@ -285,18 +290,23 @@ abstract class BaseCommentAdapter(
|
||||
article != null -> {
|
||||
"全部评论"
|
||||
}
|
||||
|
||||
questions != null -> {
|
||||
"全部回答"
|
||||
}
|
||||
|
||||
comment != null -> {
|
||||
"全部回复"
|
||||
}
|
||||
|
||||
gameCollection != null -> {
|
||||
"玩家评论"
|
||||
}
|
||||
|
||||
commentDetail != null -> {
|
||||
"全部讨论"
|
||||
}
|
||||
|
||||
else -> {
|
||||
""
|
||||
}
|
||||
@ -325,6 +335,7 @@ abstract class BaseCommentAdapter(
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
1 -> {
|
||||
mViewModel.changeSort(BaseCommentViewModel.SortType.LATEST)
|
||||
|
||||
@ -380,6 +391,7 @@ abstract class BaseCommentAdapter(
|
||||
}
|
||||
MtaHelper.onEvent("帖子详情", "全部评论", "评论正文")
|
||||
}
|
||||
|
||||
viewModel.videoId.isNotEmpty() -> {
|
||||
CommentActivity.getVideoCommentReplyIntent(
|
||||
binding.root.context,
|
||||
@ -396,6 +408,7 @@ abstract class BaseCommentAdapter(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.questionId.isNotEmpty() -> {
|
||||
CommentActivity.getQuestionCommentReplyIntent(
|
||||
binding.root.context,
|
||||
@ -426,11 +439,13 @@ abstract class BaseCommentAdapter(
|
||||
viewModel.articleId,
|
||||
viewModel.videoId,
|
||||
viewModel.questionId,
|
||||
viewModel.imageArticleId,
|
||||
false,
|
||||
comment.floor,
|
||||
entrance,
|
||||
PATH_ARTICLE_DETAIL
|
||||
).apply {
|
||||
PATH_ARTICLE_DETAIL,
|
||||
|
||||
).apply {
|
||||
binding.root.context.startActivity(this)
|
||||
}
|
||||
MtaHelper.onEvent("帖子详情", "全部评论", "回复")
|
||||
@ -527,9 +542,11 @@ abstract class BaseCommentAdapter(
|
||||
viewModel.articleId.isNotEmpty() -> {
|
||||
viewModel.topItemData?.articleDetail?.user?.id ?: ""
|
||||
}
|
||||
|
||||
viewModel.questionId.isNotEmpty() -> {
|
||||
viewModel.topItemData?.questionDetail?.user?.id ?: ""
|
||||
}
|
||||
|
||||
else -> {
|
||||
""
|
||||
}
|
||||
@ -577,6 +594,7 @@ abstract class BaseCommentAdapter(
|
||||
viewModel.articleId,
|
||||
viewModel.videoId,
|
||||
viewModel.questionId,
|
||||
viewModel.imageArticleId,
|
||||
false,
|
||||
comment.floor,
|
||||
entrance,
|
||||
@ -665,12 +683,19 @@ abstract class BaseCommentAdapter(
|
||||
viewModel.articleId.isNotEmpty() -> {
|
||||
if (viewModel is CommentConversationViewModel) PATH_ARTICLE_DETAIL_COMMENT else PATH_ARTICLE_DETAIL
|
||||
}
|
||||
|
||||
viewModel.questionId.isNotEmpty() -> {
|
||||
if (viewModel is CommentConversationViewModel) PATH_QUESTION_DETAIL_COMMENT else PATH_QUESTION_DETAIL
|
||||
}
|
||||
|
||||
viewModel.videoId.isNotEmpty() -> {
|
||||
if (viewModel is CommentConversationViewModel) PATH_VIDEO_DETAIL_COMMENT else PATH_VIDEO_DETAIL
|
||||
}
|
||||
|
||||
viewModel.imageArticleId.isNotEmpty() -> {
|
||||
if (viewModel is CommentConversationViewModel) PATH_IMAGE_ARTICLE_DETAIL_COMMENT else PATH_IMAGE_ARTICLE_DETAIL
|
||||
}
|
||||
|
||||
else -> ""
|
||||
}
|
||||
val mtaKey = if (viewModel is ArticleDetailViewModel) "全部评论" else "评论详情-全部回复"
|
||||
@ -843,6 +868,7 @@ abstract class BaseCommentAdapter(
|
||||
deleteCallBack
|
||||
)
|
||||
}
|
||||
|
||||
viewModel.videoId.isNotEmpty() -> {
|
||||
showVideoCommentOptions(
|
||||
view,
|
||||
@ -852,6 +878,7 @@ abstract class BaseCommentAdapter(
|
||||
deleteCallBack
|
||||
)
|
||||
}
|
||||
|
||||
viewModel.questionId.isNotEmpty() -> {
|
||||
showQuestionCommentOption(
|
||||
view,
|
||||
@ -861,6 +888,16 @@ abstract class BaseCommentAdapter(
|
||||
deleteCallBack
|
||||
)
|
||||
}
|
||||
|
||||
viewModel.imageArticleId.isNotEmpty() -> {
|
||||
showImageArticleOption(
|
||||
view,
|
||||
comment,
|
||||
viewModel,
|
||||
path,
|
||||
deleteCallBack
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -872,10 +909,12 @@ abstract class BaseCommentAdapter(
|
||||
bbsId = viewModel.topItemData?.articleDetail?.community?.id ?: ""
|
||||
type = viewModel.topItemData?.articleDetail?.type ?: ""
|
||||
}
|
||||
|
||||
viewModel.questionId.isNotEmpty() -> {
|
||||
bbsId = viewModel.topItemData?.questionDetail?.community?.id ?: ""
|
||||
type = viewModel.topItemData?.questionDetail?.type ?: ""
|
||||
}
|
||||
|
||||
else -> {
|
||||
bbsId = (viewModel as? VideoCommentViewModel)?.videoDetail?.bbs?.id ?: ""
|
||||
type = (viewModel as? VideoCommentViewModel)?.videoDetail?.type ?: ""
|
||||
@ -916,6 +955,7 @@ abstract class BaseCommentAdapter(
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
"采纳" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -929,6 +969,7 @@ abstract class BaseCommentAdapter(
|
||||
extraConfig = DialogHelper.Config(centerContent = true, centerTitle = true)
|
||||
)
|
||||
}
|
||||
|
||||
"取消采纳" -> {
|
||||
viewModel.acceptQuestionComment(
|
||||
viewModel.questionId,
|
||||
@ -936,12 +977,15 @@ abstract class BaseCommentAdapter(
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
"加精选" -> {
|
||||
showHighlightQuestionCommentDialog(comment, view.context, viewModel, true)
|
||||
}
|
||||
|
||||
"取消精选" -> {
|
||||
showHighlightQuestionCommentDialog(comment, view.context, viewModel, false)
|
||||
}
|
||||
|
||||
"置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -955,6 +999,7 @@ abstract class BaseCommentAdapter(
|
||||
extraConfig = DialogHelper.Config(centerContent = true, centerTitle = true)
|
||||
)
|
||||
}
|
||||
|
||||
"取消置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -1048,6 +1093,7 @@ abstract class BaseCommentAdapter(
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
"置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -1061,6 +1107,7 @@ abstract class BaseCommentAdapter(
|
||||
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
"取消置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -1119,6 +1166,7 @@ abstract class BaseCommentAdapter(
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
"置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -1132,6 +1180,7 @@ abstract class BaseCommentAdapter(
|
||||
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
"取消置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -1166,6 +1215,78 @@ abstract class BaseCommentAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
private fun showImageArticleOption(
|
||||
view: View,
|
||||
comment: CommentEntity,
|
||||
viewModel: BaseCommentViewModel,
|
||||
path: String,
|
||||
deleteCallBack: ((comment: CommentEntity) -> Unit)?
|
||||
) {
|
||||
CommentHelper.showImageArticleCommentOptions(
|
||||
view,
|
||||
comment,
|
||||
viewModel.imageArticleId,
|
||||
isShowTop = path == PATH_IMAGE_ARTICLE_DETAIL,
|
||||
listener = object : OnCommentOptionClickListener {
|
||||
override fun onCommentOptionClick(entity: CommentEntity, option: String) {
|
||||
when (option) {
|
||||
"删除评论" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
"提示",
|
||||
"删除评论后,评论下所有的回复都将被删除",
|
||||
"删除",
|
||||
"取消",
|
||||
{
|
||||
viewModel.deleteComment(comment) {
|
||||
deleteCallBack?.invoke(comment)
|
||||
}
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
"置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
"提示",
|
||||
"是否将此条评论置顶?",
|
||||
"确认",
|
||||
"取消",
|
||||
confirmClickCallback = {
|
||||
commentTop(view.context, viewModel, comment, false)
|
||||
},
|
||||
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
"取消置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
"提示",
|
||||
"是否将此条评论取消置顶?",
|
||||
"确认",
|
||||
"取消",
|
||||
confirmClickCallback = {
|
||||
viewModel.updateCommentTop(
|
||||
comment.id ?: "",
|
||||
top = false,
|
||||
isAgain = false
|
||||
) { isSuccess, _ ->
|
||||
if (isSuccess) {
|
||||
viewModel.onUpdateCommentTopSuccess()
|
||||
}
|
||||
}
|
||||
},
|
||||
extraConfig = DialogHelper.Config(centerContent = true, centerTitle = true)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
private fun commentTop(
|
||||
context: Context,
|
||||
viewModel: BaseCommentViewModel,
|
||||
@ -1212,6 +1333,9 @@ abstract class BaseCommentAdapter(
|
||||
|
||||
const val PATH_VIDEO_DETAIL = "视频详情"
|
||||
const val PATH_VIDEO_DETAIL_COMMENT = "视频评论详情"
|
||||
|
||||
const val PATH_IMAGE_ARTICLE_DETAIL = "帖子详情"
|
||||
const val PATH_IMAGE_ARTICLE_DETAIL_COMMENT = "帖子评论详情"
|
||||
}
|
||||
|
||||
enum class AdapterType {
|
||||
|
||||
@ -2,10 +2,12 @@ package com.gh.gamecenter.qa.comment.base
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.common.util.ErrorHelper
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.common.util.PostCommentUtils
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.common.baselist.ListViewModel
|
||||
import com.gh.gamecenter.common.baselist.LoadParams
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
@ -24,10 +26,12 @@ import com.gh.gamecenter.entity.CommentDraft
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.feature.entity.MeEntity
|
||||
import com.gh.gamecenter.feature.entity.Permissions
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import com.gh.gamecenter.qa.article.detail.CommentItemData
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.retrofit.service.ApiService
|
||||
import com.gh.gamecenter.room.AppDatabase
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
@ -42,7 +46,8 @@ abstract class BaseCommentViewModel(
|
||||
var questionId: String,
|
||||
var communityId: String,
|
||||
var gameCollectionId: String,
|
||||
var topCommentId: String = ""
|
||||
var topCommentId: String = "",
|
||||
val imageArticleId: String = "",
|
||||
) : ListViewModel<CommentEntity, CommentItemData>(application) {
|
||||
protected val mApi: ApiService = RetrofitManager.getInstance().api
|
||||
protected var mTotal: Int = 0
|
||||
@ -56,20 +61,29 @@ abstract class BaseCommentViewModel(
|
||||
|
||||
var isHandleTopComment = false
|
||||
|
||||
private val _updateCommentCountAction = MutableLiveData<Event<Int>>()
|
||||
val updateCommentCountAction: LiveData<Event<Int>> = _updateCommentCountAction
|
||||
fun updateCommentCount(count: Int) {
|
||||
_updateCommentCountAction.value = Event(count)
|
||||
}
|
||||
|
||||
override fun loadStatusControl(size: Int) {
|
||||
if (mCurLoadParams.loadOffset == LoadParams.DEFAULT_OFFSET) { // 初始化列表
|
||||
when {
|
||||
size == 0 -> {
|
||||
mLoadStatusLiveData.setValue(LoadStatus.INIT_EMPTY)
|
||||
}
|
||||
|
||||
size == REQUEST_FAILURE_SIZE -> {
|
||||
// TODO 处理列表加载失败问题
|
||||
mLoadStatusLiveData.setValue(LoadStatus.INIT_LOADED)
|
||||
}
|
||||
|
||||
size < mOverLimitSize -> {
|
||||
// 避免一个屏幕出现两次分页
|
||||
mLoadStatusLiveData.setValue(LoadStatus.INIT_OVER)
|
||||
}
|
||||
|
||||
else -> mLoadStatusLiveData.setValue(LoadStatus.INIT_LOADED)
|
||||
}
|
||||
} else {
|
||||
@ -146,15 +160,28 @@ abstract class BaseCommentViewModel(
|
||||
articleId.isNotEmpty() -> {
|
||||
mApi.getCommunityArticleComment(commentId)
|
||||
}
|
||||
|
||||
videoId.isNotEmpty() -> {
|
||||
mApi.getCommunityVideoComment(commentId)
|
||||
}
|
||||
|
||||
questionId.isNotEmpty() -> {
|
||||
mApi.getCommunityQuestionComment(questionId, commentId)
|
||||
}
|
||||
|
||||
gameCollectionId.isNotEmpty() -> {
|
||||
mApi.getGameCollectionComment(gameCollectionId, commentId)
|
||||
}
|
||||
|
||||
imageArticleId.isNotEmpty() -> {
|
||||
mApi.getImageArticleCommentDetail(
|
||||
commentId,
|
||||
BuildConfig.VERSION_NAME,
|
||||
HaloApp.getInstance().channel,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
}
|
||||
|
||||
else -> null
|
||||
} ?: return
|
||||
single.compose(singleToMain())
|
||||
@ -172,6 +199,7 @@ abstract class BaseCommentViewModel(
|
||||
load(LoadType.REFRESH)
|
||||
}
|
||||
}
|
||||
|
||||
SortType.OLDEST -> {
|
||||
//根据total判断是否插入到最后
|
||||
if (count >= mTotal) {
|
||||
@ -185,6 +213,7 @@ abstract class BaseCommentViewModel(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
super.onFailure(exception)
|
||||
load(LoadType.REFRESH)
|
||||
@ -221,6 +250,7 @@ abstract class BaseCommentViewModel(
|
||||
articleId,
|
||||
videoId,
|
||||
questionId,
|
||||
imageArticleId,
|
||||
comment.id,
|
||||
object : PostCommentUtils.PostCommentListener {
|
||||
override fun postSuccess(response: JSONObject?) {
|
||||
@ -273,7 +303,7 @@ abstract class BaseCommentViewModel(
|
||||
}
|
||||
|
||||
fun unLike(comment: CommentEntity) {
|
||||
PostCommentUtils.unLikeComment(articleId, communityId, videoId, questionId, comment.id,
|
||||
PostCommentUtils.unLikeComment(articleId, communityId, videoId, questionId, imageArticleId, comment.id,
|
||||
object : PostCommentUtils.PostCommentListener {
|
||||
override fun postSuccess(response: JSONObject?) {
|
||||
val cloneComment = comment.clone()
|
||||
@ -319,12 +349,19 @@ abstract class BaseCommentViewModel(
|
||||
mApi.deleteVideoComment(entity.id).toObservable()
|
||||
}
|
||||
}
|
||||
|
||||
questionId.isNotEmpty() -> {
|
||||
mApi.deleteQuestionComment(questionId, entity.id).toObservable()
|
||||
}
|
||||
|
||||
articleId.isNotEmpty() -> {
|
||||
mApi.hideCommunityArticleComment(entity.id)
|
||||
}
|
||||
|
||||
imageArticleId.isNotEmpty() -> {
|
||||
mApi.deleteImageArticleComment(entity.id)
|
||||
}
|
||||
|
||||
else -> null
|
||||
} ?: return
|
||||
observable.compose(observableToMain())
|
||||
@ -373,12 +410,19 @@ abstract class BaseCommentViewModel(
|
||||
articleId.isNotEmpty() -> {
|
||||
mApi.postArticleCommentTop(commentId, map)
|
||||
}
|
||||
|
||||
questionId.isNotEmpty() -> {
|
||||
mApi.postQuestionCommentTop(questionId, commentId, map)
|
||||
}
|
||||
|
||||
videoId.isNotEmpty() -> {
|
||||
mApi.postVideoCommentTop(commentId, map)
|
||||
}
|
||||
|
||||
imageArticleId.isNotEmpty() -> {
|
||||
mApi.postImageArticleTop(commentId, map)
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
} else {
|
||||
@ -386,12 +430,19 @@ abstract class BaseCommentViewModel(
|
||||
articleId.isNotEmpty() -> {
|
||||
mApi.postArticleCommentUnTop(commentId)
|
||||
}
|
||||
|
||||
questionId.isNotEmpty() -> {
|
||||
mApi.postQuestionCommentUnTop(questionId, commentId)
|
||||
}
|
||||
|
||||
videoId.isNotEmpty() -> {
|
||||
mApi.postVideoCommentUnTop(commentId)
|
||||
}
|
||||
|
||||
imageArticleId.isNotEmpty() -> {
|
||||
mApi.postImageArticleUnTop(commentId)
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
} ?: return
|
||||
@ -502,6 +553,7 @@ abstract class BaseCommentViewModel(
|
||||
when {
|
||||
commentNormal?.id == cloneComment.id -> it[index] =
|
||||
CommentItemData(commentNormal = cloneComment)
|
||||
|
||||
commentTop?.id == cloneComment.id -> it[index] = CommentItemData(commentTop = cloneComment)
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ import com.gh.gamecenter.qa.comment.base.BaseCommentFragment
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
|
||||
import com.gh.gamecenter.qa.article.detail.CommentItemData
|
||||
import com.gh.gamecenter.qa.comment.CommentActivity
|
||||
import com.gh.gamecenter.qa.comment.CommentActivity.Companion.IMAGE_ARTICLE_ID
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
class CommentConversationFragment :
|
||||
@ -118,7 +119,8 @@ class CommentConversationFragment :
|
||||
// 取消掉
|
||||
if (mUseAlternativeLayout) {
|
||||
toolbarContainer.root.visibility = View.GONE
|
||||
container.updateLayoutParams { this as FrameLayout.LayoutParams
|
||||
container.updateLayoutParams {
|
||||
this as FrameLayout.LayoutParams
|
||||
setMargins(0, 0, 0, 0)
|
||||
}
|
||||
}
|
||||
@ -192,6 +194,7 @@ class CommentConversationFragment :
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (it == BaseCommentViewModel.LoadResult.DELETED) {
|
||||
mReuseNoConn?.visibility = View.GONE
|
||||
@ -228,7 +231,8 @@ class CommentConversationFragment :
|
||||
arguments?.getString(EntranceConsts.KEY_COMMUNITY_ID) ?: "",
|
||||
arguments?.getString(CommentActivity.GAME_COLLECTION_ID) ?: "",
|
||||
arguments?.getString(EntranceConsts.KEY_COMMENT_ID) ?: "",
|
||||
arguments?.getString(EntranceConsts.KEY_TOP_COMMENT_ID) ?: ""
|
||||
arguments?.getString(EntranceConsts.KEY_TOP_COMMENT_ID) ?: "",
|
||||
arguments?.getString(IMAGE_ARTICLE_ID) ?: ""
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -284,6 +288,15 @@ class CommentConversationFragment :
|
||||
comment
|
||||
)
|
||||
startActivityForResult(intent, CommentActivity.REQUEST_CODE)
|
||||
} else if (mViewModel.imageArticleId.isNotEmpty()) {
|
||||
val intent = CommentActivity.getImageArticleCommentReplyIntent(
|
||||
requireContext(),
|
||||
mViewModel.imageArticleId,
|
||||
arguments?.getString(EntranceConsts.KEY_COMMENT_ID) ?: "",
|
||||
mViewModel.commentCount,
|
||||
comment
|
||||
)
|
||||
startActivityForResult(intent, CommentActivity.REQUEST_CODE)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,10 +4,12 @@ import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.qa.article.detail.CommentItemData
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
@ -21,8 +23,9 @@ class CommentConversationViewModel(
|
||||
communityId: String = "",
|
||||
gameCollectionId: String = "",
|
||||
var commentId: String = "",
|
||||
topCommentId: String = ""
|
||||
) : BaseCommentViewModel(application, articleId, videoId, questionId, communityId, topCommentId) {
|
||||
topCommentId: String = "",
|
||||
imageArticleId: String = ""
|
||||
) : BaseCommentViewModel(application, articleId, videoId, questionId, communityId,gameCollectionId, topCommentId, imageArticleId) {
|
||||
var commentDetail: CommentEntity? = null
|
||||
var positionInOriginList = -1
|
||||
|
||||
@ -42,15 +45,30 @@ class CommentConversationViewModel(
|
||||
map
|
||||
)
|
||||
}
|
||||
|
||||
videoId.isNotEmpty() -> {
|
||||
mApi.getVideoCommentReply(videoId, commentId, currentSortType.value, page, map)
|
||||
}
|
||||
|
||||
questionId.isNotEmpty() -> {
|
||||
mApi.getQuestionCommentReply(questionId, commentId, currentSortType.value, page, map)
|
||||
}
|
||||
|
||||
gameCollectionId.isNotEmpty() -> {
|
||||
mApi.getGameCollectionCommentReply(gameCollectionId, commentId, page, map)
|
||||
}
|
||||
|
||||
imageArticleId.isNotEmpty() -> {
|
||||
mApi.getImageArticleDetailCommentReply(
|
||||
commentId,
|
||||
currentSortType.value,
|
||||
page,
|
||||
BuildConfig.VERSION_NAME,
|
||||
HaloApp.getInstance().channel,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@ -61,15 +79,28 @@ class CommentConversationViewModel(
|
||||
articleId.isNotEmpty() -> {
|
||||
mApi.getCommunityArticleComment(commentId)
|
||||
}
|
||||
|
||||
videoId.isNotEmpty() -> {
|
||||
mApi.getCommunityVideoComment(commentId)
|
||||
}
|
||||
|
||||
questionId.isNotEmpty() -> {
|
||||
mApi.getCommunityQuestionComment(questionId, commentId)
|
||||
}
|
||||
|
||||
gameCollectionId.isNotEmpty() -> {
|
||||
mApi.getGameCollectionComment(gameCollectionId, commentId)
|
||||
}
|
||||
|
||||
imageArticleId.isNotEmpty() -> {
|
||||
mApi.getImageArticleCommentDetail(
|
||||
commentId,
|
||||
BuildConfig.VERSION_NAME,
|
||||
HaloApp.getInstance().channel,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
}
|
||||
|
||||
else -> null
|
||||
} ?: return
|
||||
single.subscribeOn(Schedulers.io())
|
||||
@ -113,6 +144,7 @@ class CommentConversationViewModel(
|
||||
when {
|
||||
commentNormal?.id == cloneComment.id -> it[index] =
|
||||
CommentItemData(commentNormal = cloneComment)
|
||||
|
||||
commentTop?.id == cloneComment.id -> {
|
||||
commentDetail = cloneComment
|
||||
it[index] = CommentItemData(commentTop = cloneComment)
|
||||
@ -132,7 +164,8 @@ class CommentConversationViewModel(
|
||||
private val communityId: String = "",
|
||||
private val gameCollectionId: String = "",
|
||||
private val commentId: String,
|
||||
private val topCommentId: String
|
||||
private val topCommentId: String,
|
||||
private val imageArticleId: String,
|
||||
) : ViewModelProvider.NewInstanceFactory() {
|
||||
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
@ -144,7 +177,8 @@ class CommentConversationViewModel(
|
||||
communityId = communityId,
|
||||
gameCollectionId = gameCollectionId,
|
||||
commentId = commentId,
|
||||
topCommentId = topCommentId
|
||||
topCommentId = topCommentId,
|
||||
imageArticleId = imageArticleId
|
||||
) as T
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,12 +2,15 @@ package com.gh.gamecenter.qa.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
@ -45,8 +48,8 @@ class ChooseForumActivity : BaseActivity() {
|
||||
val sourceEntrance = intent.getStringExtra(EntranceConsts.KEY_SOURCE_ENTRANCE) ?: ""
|
||||
|
||||
initViewPager()
|
||||
binding.searchEt.doOnTextChanged { _, _, _, _ ->
|
||||
val searchKey = binding.searchEt.text?.toString()
|
||||
binding.searchEt.doOnTextChanged { text, _, _, _ ->
|
||||
val searchKey = text?.toString()
|
||||
if (searchKey.isNullOrEmpty()) {
|
||||
switchUI(false)
|
||||
} else {
|
||||
@ -61,6 +64,25 @@ class ChooseForumActivity : BaseActivity() {
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
binding.searchEt.setOnEditorActionListener { v, actionId, event ->
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||
// 开始搜索
|
||||
mSearchResultFragment?.setSearchKeyAndType(
|
||||
binding.searchEt.text?.toString() ?: "",
|
||||
SearchType.MANUAL.value
|
||||
)
|
||||
// 清除焦点以保持搜索按钮
|
||||
binding.searchEt.clearFocus()
|
||||
|
||||
// 隐藏软键盘
|
||||
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(binding.searchEt.windowToken, 0)
|
||||
return@setOnEditorActionListener true
|
||||
} else {
|
||||
return@setOnEditorActionListener false
|
||||
}
|
||||
}
|
||||
binding.closeIv.setOnClickListener {
|
||||
NewLogUtils.logChooseForumPanelClick("click_select_forum_panel_close", "", "", "")
|
||||
finish()
|
||||
|
||||
@ -5,7 +5,10 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity_TabLayout
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.toResString
|
||||
import com.gh.gamecenter.common.utils.updateStatusBarColor
|
||||
import com.gh.gamecenter.forum.home.recommend.fragment.ImageArticleDraftFragment
|
||||
import com.gh.gamecenter.qa.article.draft.ArticleDraftFragment
|
||||
import com.gh.gamecenter.qa.questions.draft.QuestionDraftFragment
|
||||
import com.gh.gamecenter.video.videomanager.VideoDraftFragment
|
||||
@ -22,15 +25,17 @@ class CommunityDraftWrapperActivity : BaseActivity_TabLayout() {
|
||||
}
|
||||
|
||||
override fun initFragmentList(fragments: MutableList<Fragment>) {
|
||||
fragments.add(ImageArticleDraftFragment())
|
||||
fragments.add(ArticleDraftFragment())
|
||||
fragments.add(QuestionDraftFragment())
|
||||
fragments.add(VideoDraftFragment())
|
||||
}
|
||||
|
||||
override fun initTabTitleList(tabTitleList: MutableList<String>) {
|
||||
tabTitleList.add("帖子草稿")
|
||||
tabTitleList.add("问题草稿")
|
||||
tabTitleList.add("视频草稿")
|
||||
tabTitleList.add(R.string.image_article.toResString())
|
||||
tabTitleList.add("帖子")
|
||||
tabTitleList.add("问题")
|
||||
tabTitleList.add("视频")
|
||||
}
|
||||
|
||||
override fun isAutoResetViewBackgroundEnabled(): Boolean = true
|
||||
|
||||
@ -324,6 +324,7 @@ class NewQuestionDetailFragment :
|
||||
mBinding.root.setBackgroundColor(Color.TRANSPARENT)
|
||||
updateView()
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (it == BaseCommentViewModel.LoadResult.DELETED) {
|
||||
mReuseNoConn?.visibility = View.GONE
|
||||
@ -430,7 +431,7 @@ class NewQuestionDetailFragment :
|
||||
mAdapter?.questionDetailVH?.bindView(it)
|
||||
}
|
||||
mViewModel.top.observeNonNull(this) { top ->
|
||||
val topSuccessToast = if(top) {
|
||||
val topSuccessToast = if (top) {
|
||||
R.string.article_detail_top_success_toast
|
||||
} else {
|
||||
R.string.article_detail_cancel_top_success_toast
|
||||
@ -626,12 +627,24 @@ class NewQuestionDetailFragment :
|
||||
// 置顶/取消置顶
|
||||
if (questionEntity.me.isModerator
|
||||
&& !questionEntity.me.isCommunityTop
|
||||
&& moderatorPermissions.topQuestion > Permissions.GUEST) {
|
||||
entities.add(MenuItemEntity(getString(R.string.article_detail_more_top_title), R.drawable.icon_more_panel_top))
|
||||
&& moderatorPermissions.topQuestion > Permissions.GUEST
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_top_title),
|
||||
R.drawable.icon_more_panel_top
|
||||
)
|
||||
)
|
||||
} else if (questionEntity.me.isModerator
|
||||
&& questionEntity.me.isCommunityTop
|
||||
&& moderatorPermissions.cancelTopQuestion > Permissions.GUEST) {
|
||||
entities.add(MenuItemEntity(getString(R.string.article_detail_more_cancel_top_title), R.drawable.icon_more_panel_top_cancel))
|
||||
&& moderatorPermissions.cancelTopQuestion > Permissions.GUEST
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_cancel_top_title),
|
||||
R.drawable.icon_more_panel_top_cancel
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
MoreFunctionPanelDialog.showMoreDialog(
|
||||
@ -682,8 +695,7 @@ class NewQuestionDetailFragment :
|
||||
"投诉" -> {
|
||||
ifLogin("提问贴") {
|
||||
BbsReportHelper.showReportDialog(
|
||||
mViewModel.questionDetail?.id
|
||||
?: ""
|
||||
BbsReportHelper.PostsReporter(mViewModel.questionDetail?.id ?: "")
|
||||
)
|
||||
}
|
||||
NewLogUtils.logSharePanelClick(
|
||||
@ -695,6 +707,7 @@ class NewQuestionDetailFragment :
|
||||
mViewModel.questionDetail?.community?.typeChinese ?: "综合论坛"
|
||||
)
|
||||
}
|
||||
|
||||
"编辑" -> {
|
||||
val intent = if (questionEntity.me.isModerator) {
|
||||
QuestionEditActivity.getManagerIntent(
|
||||
@ -737,6 +750,7 @@ class NewQuestionDetailFragment :
|
||||
mViewModel.questionDetail?.community?.typeChinese ?: "综合论坛"
|
||||
)
|
||||
}
|
||||
|
||||
"解决", "已解决" -> {
|
||||
val content =
|
||||
if (!questionEntity.finish) "该问题确定标记已解决?" else "该问题确定标记未解决?"
|
||||
@ -752,6 +766,7 @@ class NewQuestionDetailFragment :
|
||||
mViewModel.questionDetail?.community?.typeChinese ?: "综合论坛"
|
||||
)
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_top_title) -> {
|
||||
TopCommunityCategoryDialog.show(
|
||||
childFragmentManager
|
||||
@ -759,6 +774,7 @@ class NewQuestionDetailFragment :
|
||||
mViewModel.topCommunityQuestion(category.id)
|
||||
}
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_cancel_top_title) -> {
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
|
||||
@ -171,7 +171,8 @@ class ForumVideoDetailFragment : BaseLazyTabFragment() {
|
||||
mVideoId = arguments?.getString(EntranceConsts.KEY_VIDEO_ID) ?: ""
|
||||
mBbsId = arguments?.getString(EntranceConsts.KEY_BBS_ID) ?: ""
|
||||
mTopCommentId = arguments?.getString(EntranceConsts.KEY_TOP_COMMENT_ID) ?: ""
|
||||
mBasicExposureSourceList = arguments?.getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST) ?: arrayListOf()
|
||||
mBasicExposureSourceList =
|
||||
arguments?.getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST) ?: arrayListOf()
|
||||
sourceEntrance = arguments?.getString(EntranceConsts.KEY_SOURCE_ENTRANCE) ?: ""
|
||||
super.onCreate(savedInstanceState)
|
||||
NewLogUtils.logVideoDetailClick("view_video_detail")
|
||||
@ -189,7 +190,8 @@ class ForumVideoDetailFragment : BaseLazyTabFragment() {
|
||||
}
|
||||
}
|
||||
if (mIsFromMainWrapper) {
|
||||
(mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = DisplayUtils.getStatusBarHeight(requireContext().resources)
|
||||
(mBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin =
|
||||
DisplayUtils.getStatusBarHeight(requireContext().resources)
|
||||
}
|
||||
mViewModel = viewModelProviderFromParent(
|
||||
ForumVideoDetailViewModel.Factory(
|
||||
@ -704,7 +706,7 @@ class ForumVideoDetailFragment : BaseLazyTabFragment() {
|
||||
}
|
||||
|
||||
"投诉" -> {
|
||||
BbsReportHelper.showReportDialog(mForumVideoEntity?.id ?: "")
|
||||
BbsReportHelper.showReportDialog(BbsReportHelper.PostsReporter(mForumVideoEntity?.id ?: ""))
|
||||
NewLogUtils.logSharePanelClick(
|
||||
"click_report",
|
||||
mForumVideoEntity?.user?.id ?: "",
|
||||
@ -746,9 +748,11 @@ class ForumVideoDetailFragment : BaseLazyTabFragment() {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
"取消精选" -> {
|
||||
showHighlightDialog(false)
|
||||
}
|
||||
|
||||
"修改活动标签" -> {
|
||||
ChooseActivityDialogFragment.show(
|
||||
requireActivity() as AppCompatActivity,
|
||||
@ -758,6 +762,7 @@ class ForumVideoDetailFragment : BaseLazyTabFragment() {
|
||||
tag ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
"删除", "隐藏" -> {
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
@ -770,7 +775,7 @@ class ForumVideoDetailFragment : BaseLazyTabFragment() {
|
||||
)
|
||||
NewLogUtils.logSharePanelClick(
|
||||
"click_delete",
|
||||
mForumVideoEntity?.user?.id ?: "",
|
||||
mForumVideoEntity?.user?.id ?: "",
|
||||
"视频帖",
|
||||
mForumVideoEntity?.id ?: "",
|
||||
mForumVideoEntity?.bbs?.id ?: "",
|
||||
@ -785,6 +790,7 @@ class ForumVideoDetailFragment : BaseLazyTabFragment() {
|
||||
mViewModel.topCommunityVideo(category.id)
|
||||
}
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_cancel_top_title) -> {
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
|
||||
@ -55,6 +55,7 @@ import com.gh.gamecenter.entity.GamesCollectionEntity;
|
||||
import com.gh.gamecenter.entity.HaloAddonEntity;
|
||||
import com.gh.gamecenter.entity.HomeGameCollectionEntity;
|
||||
import com.gh.gamecenter.entity.HomeItemTestV2Entity;
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity;
|
||||
import com.gh.gamecenter.entity.ImageInfoEntity;
|
||||
import com.gh.gamecenter.entity.InterestedGameEntity;
|
||||
import com.gh.gamecenter.entity.LibaoDetailEntity;
|
||||
@ -66,6 +67,7 @@ import com.gh.gamecenter.entity.NewsDetailEntity;
|
||||
import com.gh.gamecenter.entity.PackageFilter;
|
||||
import com.gh.gamecenter.entity.PackageGame;
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity;
|
||||
import com.gh.gamecenter.entity.PublishImageTextRequest;
|
||||
import com.gh.gamecenter.entity.PullDownPush;
|
||||
import com.gh.gamecenter.entity.Rating;
|
||||
import com.gh.gamecenter.entity.RatingComment;
|
||||
@ -154,6 +156,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.RequestBody;
|
||||
@ -3425,4 +3428,195 @@ public interface ApiService {
|
||||
@GET("game_lists/search")
|
||||
Single<List<CustomPageData.LinkColumnCollection.CustomSubjectEntity>> searchGameList(@Query("keyword") String keyword, @Query("page") int page);
|
||||
|
||||
|
||||
/**
|
||||
* 发布图文
|
||||
*/
|
||||
@POST("communities/image_articles")
|
||||
Single<JsonObject> publishImageText(@Body PublishImageTextRequest request);
|
||||
|
||||
/**
|
||||
* 编辑图文
|
||||
*/
|
||||
@PUT("communities/image_articles/{id}")
|
||||
Completable editImageArticle(@Path("id") String id, @Body PublishImageTextRequest request);
|
||||
|
||||
|
||||
/**
|
||||
* 新建草稿
|
||||
*/
|
||||
@POST("users/{user_id}/communities/image_article_drafts")
|
||||
Single<ResponseBody> createImageArticleDrafts(@Path("user_id") String userId, @Body PublishImageTextRequest request);
|
||||
|
||||
/**
|
||||
* 编辑草稿
|
||||
*/
|
||||
@PUT("users/{user_id}/communities/image_article_drafts/{id}")
|
||||
Completable editImageArticleDrafts(@Path("user_id") String userId, @Path("id") String draftId, @Body PublishImageTextRequest request);
|
||||
|
||||
/**
|
||||
* 草稿箱
|
||||
*/
|
||||
@GET("users/{user_id}/communities/image_article_drafts")
|
||||
Single<List<ImageArticleEntity>> loadImageTextDrafts(@Path("user_id") String userId, @Query("version") String version, @Query("channel") String channel);
|
||||
|
||||
/**
|
||||
* 删除草稿
|
||||
*/
|
||||
@DELETE("users/{user_id}/communities/image_article_drafts/{id}")
|
||||
Completable deleteImageArticleDraft(@Path("user_id") String userId, @Path("id") String id);
|
||||
|
||||
/**
|
||||
* 图文详情
|
||||
*/
|
||||
@GET("communities/image_articles/{id}")
|
||||
Single<ImageArticleEntity> loadImageArticleDetail(
|
||||
@Path("id") String imageArticleId,
|
||||
@Query("view") String view,
|
||||
@Query("version") String version,
|
||||
@Query("channel") String channel);
|
||||
|
||||
/**
|
||||
* 推荐-图文列表
|
||||
*/
|
||||
@GET("bbses/image_article_recommends")
|
||||
Single<List<ImageArticleEntity>> loadImageArticleRecommends(
|
||||
@Query("sort") String sort,
|
||||
@Query("page") int page,
|
||||
@Query("version") String version,
|
||||
@Query("channel") String channel);
|
||||
|
||||
/**
|
||||
* 评论图文
|
||||
*/
|
||||
@POST("communities/image_articles/{article_id}/comments")
|
||||
Observable<ResponseBody> postImageArticleComment(@Path("article_id") String articleId, @Body RequestBody body);
|
||||
|
||||
/**
|
||||
* 回复图文评论
|
||||
*/
|
||||
@POST("communities/image_articles/comments/{comment_id}:reply")
|
||||
Observable<ResponseBody> postReplyToImageArticleComment(@Path("comment_id") String commentId, @Body RequestBody body);
|
||||
|
||||
/**
|
||||
* 图文详情评论列表
|
||||
*/
|
||||
@GET("communities/image_articles/{article_id}/comments")
|
||||
Observable<retrofit2.Response<JsonArray>> getImageArticleComments(@Path("article_id") String articleId,
|
||||
@Query("sort") String type,
|
||||
@Query("page") int page,
|
||||
@QueryMap Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 图文评论详情
|
||||
*/
|
||||
@GET("communities/image_articles/comments/{comment_id}")
|
||||
Single<CommentEntity> getImageArticleCommentDetail(
|
||||
@Path("comment_id") String commentId,
|
||||
@Query("version") String version,
|
||||
@Query("channel") String channel,
|
||||
@Query("timestamp") long timeStamp);
|
||||
|
||||
/**
|
||||
* 图文详情回复列表
|
||||
*/
|
||||
@GET("communities/image_articles/comments/{comment_id}/replies")
|
||||
Single<List<CommentEntity>> getImageArticleDetailCommentReply(
|
||||
@Path("comment_id") String commentId,
|
||||
@Query("sort") String sort,
|
||||
@Query("page") int page,
|
||||
@Query("version") String version,
|
||||
@Query("channel") String channel,
|
||||
@Query("timestamp") long timestamp);
|
||||
|
||||
/**
|
||||
* 投诉图文评论
|
||||
*/
|
||||
@POST("communities/image_articles/comments/{comment_id}:report")
|
||||
Observable<ResponseBody> reportImageArticleComment(@Path("comment_id") String commentId, @Body RequestBody body);
|
||||
|
||||
/**
|
||||
* 删除图文评论
|
||||
*/
|
||||
@POST("communities/image_articles/comments/{comment_id}:hide")
|
||||
Observable<ResponseBody> deleteImageArticleComment(@Path("comment_id") String commendId);
|
||||
|
||||
/**
|
||||
* 收藏图文
|
||||
*/
|
||||
@POST("users/favorites/communities/image_articles/{id}")
|
||||
Single<ResponseBody> collectImageArticle(@Path("id") String id);
|
||||
|
||||
/**
|
||||
* 取消收藏图文
|
||||
*/
|
||||
@DELETE("users/favorites/communities/image_articles/{id}")
|
||||
Completable cancelImageArticleCollection(@Path("id") String id);
|
||||
|
||||
/**
|
||||
* 点赞图文
|
||||
*/
|
||||
@POST("communities/image_articles/{id}:vote")
|
||||
Single<VoteEntity> voteArticleImage(@Path("id") String id);
|
||||
|
||||
/**
|
||||
* 取消点赞图文
|
||||
*/
|
||||
@POST("communities/image_articles/{id}:unvote")
|
||||
Single<VoteEntity> unVoteArticleImage(@Path("id") String id);
|
||||
|
||||
/**
|
||||
* 置顶图文
|
||||
*/
|
||||
@POST("communities/image_articles/comments/{comment_id}:set-top")
|
||||
Observable<ResponseBody> postImageArticleTop(@Path("comment_id") String commentId, @QueryMap Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 取消置顶图文
|
||||
*/
|
||||
@POST("communities/image_articles/comments/{comment_id}:unset-top")
|
||||
Observable<ResponseBody> postImageArticleUnTop(@Path("comment_id") String commentId);
|
||||
|
||||
/**
|
||||
* 点赞图文
|
||||
*/
|
||||
@POST("communities/image_articles/comments/{comment_id}:vote")
|
||||
Observable<ResponseBody> postVoteToImageArticle(@Path("comment_id") String commentId);
|
||||
|
||||
/**
|
||||
* 取消点赞图文
|
||||
*/
|
||||
@POST("communities/image_articles/comments/{comment_id}:unvote")
|
||||
Observable<ResponseBody> postUnVoteImageArticle(@Path("comment_id") String commentId);
|
||||
|
||||
/**
|
||||
* 图文申请加精
|
||||
*/
|
||||
@POST("communities/image_articles/{id}:choiceness")
|
||||
Completable applyHighlightForImageArticle(@Path("id") String id);
|
||||
|
||||
/**
|
||||
* 图文加精选
|
||||
*/
|
||||
@POST("communities/image_articles/{id}:moderator_choiceness")
|
||||
Single<ResponseBody> addHighlightForImageArticle(@Path("id") String imageArticleId);
|
||||
|
||||
/**
|
||||
* 图文取消加精
|
||||
*/
|
||||
@POST("communities/image_articles/{id}:cancel_choiceness")
|
||||
Single<ResponseBody> cancelHighlightForImageArticle(@Path("id") String imageArticleId);
|
||||
|
||||
/**
|
||||
* 删除/隐藏图文
|
||||
*/
|
||||
@POST("communities/image_articles/{id}:hide")
|
||||
Single<ResponseBody> deleteOrHideImageArticle(@Path("id") String imageArticleId);
|
||||
|
||||
/**
|
||||
* 投诉图文
|
||||
*/
|
||||
@POST("bbses/contents/{content_id}:report")
|
||||
Single<ResponseBody> postImageArticleReport(@Path("content_id") String contentId, @Body RequestBody body);
|
||||
|
||||
}
|
||||
@ -94,7 +94,8 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
mBasicExposureSourceList = arguments?.getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST) ?: arrayListOf()
|
||||
mBasicExposureSourceList =
|
||||
arguments?.getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST) ?: arrayListOf()
|
||||
mInitialVideoId = arguments?.getString(EntranceConsts.KEY_ID) ?: ""
|
||||
mLocation = arguments?.getString(EntranceConsts.KEY_LOCATION) ?: ""
|
||||
mReferer = arguments?.getString(EntranceConsts.KEY_REFERER) ?: ""
|
||||
@ -154,7 +155,8 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener {
|
||||
mBinding.recyclerview.visibility = View.VISIBLE
|
||||
mBinding.attentionNoDataContainer.visibility = View.GONE
|
||||
if (!::mAdapter.isInitialized) {
|
||||
mAdapter = VideoAdapter(this, mBinding.recyclerview, mBinding.refresh, mViewModel, mBasicExposureSourceList)
|
||||
mAdapter =
|
||||
VideoAdapter(this, mBinding.recyclerview, mBinding.refresh, mViewModel, mBasicExposureSourceList)
|
||||
mExposureListener = ExposureListener(this, mAdapter)
|
||||
mBinding.recyclerview.addOnScrollListener(mExposureListener!!)
|
||||
mBinding.recyclerview.adapter = mAdapter
|
||||
@ -574,6 +576,7 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener {
|
||||
CheckLoginUtils.checkLogin(context, "(视频详情)") {}
|
||||
}
|
||||
}
|
||||
|
||||
"取消收藏" -> {
|
||||
if (UserManager.getInstance().isLoggedIn) {
|
||||
MtaHelper.onEvent("视频详情", "更多-取消收藏", combinedTitleAndId)
|
||||
@ -587,9 +590,10 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener {
|
||||
CheckLoginUtils.checkLogin(context, "(视频详情)") {}
|
||||
}
|
||||
}
|
||||
|
||||
"投诉" -> {
|
||||
ifLogin("视频详情") {
|
||||
BbsReportHelper.showReportDialog(videoEntity.id)
|
||||
BbsReportHelper.showReportDialog(BbsReportHelper.PostsReporter(videoEntity.id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user