Compare commits
21 Commits
refactor/s
...
feat/GHZSC
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d645d408b | |||
| 880c7df2ce | |||
| 8cf8207d5b | |||
| 2ce6b1665d | |||
| ba70162638 | |||
| a3d1b1a262 | |||
| ebcb68fb7e | |||
| 1f1bf4f9ee | |||
| 9de1ef1f99 | |||
| b5bfce7a60 | |||
| 49e77f7464 | |||
| e3056ec6a1 | |||
| b06a452b8b | |||
| ae269298e4 | |||
| bfac3a6684 | |||
| 03921fb64d | |||
| 01603ee8c9 | |||
| f22033b61f | |||
| 8b44d65118 | |||
| 838caaa5fc | |||
| 4c521c75b2 |
@ -72,6 +72,7 @@ android_build:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-6136
|
||||
|
||||
# 代码检查
|
||||
sonarqube_analysis:
|
||||
@ -103,6 +104,7 @@ sonarqube_analysis:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-6136
|
||||
|
||||
## 发送简易检测结果报告
|
||||
send_sonar_report:
|
||||
@ -121,6 +123,7 @@ send_sonar_report:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-6136
|
||||
|
||||
oss-upload&send-email:
|
||||
tags:
|
||||
@ -157,3 +160,4 @@ oss-upload&send-email:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-6136
|
||||
@ -815,6 +815,14 @@
|
||||
<!-- android:taskAffinity="${applicationId}"-->
|
||||
<!-- android:exported="true" />-->
|
||||
|
||||
<activity
|
||||
android:name=".forum.home.recommend.PublishImageArticleActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".forum.home.recommend.ImageArticleDetailActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}"
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.gh.common.exposure
|
||||
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.common.loghub.LoghubUtils
|
||||
import com.gh.gamecenter.common.loghub.TLogHubHelper
|
||||
import com.gh.gamecenter.common.utils.FixedSizeLinkedHashSet
|
||||
import com.gh.gamecenter.common.utils.toJson
|
||||
@ -78,7 +79,12 @@ object ExposureManager {
|
||||
|
||||
private fun uploadExposures(eventSet: HashSet<ExposureEvent>, forced: Boolean) {
|
||||
eventSet.forEach {
|
||||
TLogHubHelper.sendLog(buildLog(it), LOG_STORE)
|
||||
val jsonExposure = it.jsonExposure
|
||||
if (jsonExposure == null) {
|
||||
TLogHubHelper.sendLog(buildLog(it), LOG_STORE)
|
||||
} else {
|
||||
LoghubUtils.log(jsonExposure, it.logStore, true)
|
||||
}
|
||||
// LoghubHelper.uploadLog(buildLog(it), LOG_STORE, forced)
|
||||
// it.recycle()
|
||||
}
|
||||
|
||||
@ -77,6 +77,19 @@ class NewCommentDetailProviderImpl : INewCommentDetailProvider {
|
||||
)
|
||||
}
|
||||
|
||||
override fun getImageArticleCommentIntent(
|
||||
context: Context,
|
||||
commentId: String,
|
||||
imageArticleId: String,
|
||||
topCommentId: String,
|
||||
entrance: String,
|
||||
path: String
|
||||
):Intent {
|
||||
return NewCommentDetailActivity.getImageArticleCommentIntent(
|
||||
context, commentId, imageArticleId, topCommentId, entrance, path
|
||||
)
|
||||
}
|
||||
|
||||
override fun init(context: Context?) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@ -14,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,16 @@ object DirectUtils {
|
||||
}
|
||||
}
|
||||
|
||||
"image_article" -> {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(KEY_IMAGE_ARTICLE_ID, linkEntity.link)
|
||||
.appendQueryParameter(KEY_SOURCE_ENTRANCE, sourceEntrance)
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
}
|
||||
|
||||
|
||||
"" -> {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@ -33,6 +33,8 @@ object NewFlatLogUtils {
|
||||
private const val EVENT_INSTALLED_LAUNCH_DIALOG_SHOW = "halo_fun_installed_launch_dialog_show"
|
||||
private const val EVENT_INSTALLED_LAUNCH_DIALOG_CLICK = "halo_fun_installed_launch_dialog_click"
|
||||
|
||||
private const val LOG_STORE_BBS_COMMUNITY = "bbs_community"
|
||||
|
||||
private fun log(jsonObject: JSONObject, logStore: String = "event", uploadImmediately: Boolean = false) {
|
||||
Utils.log("NewFlatLogUtils", jsonObject.toString(4))
|
||||
LoghubUtils.log(jsonObject, logStore, uploadImmediately, true)
|
||||
@ -96,7 +98,12 @@ object NewFlatLogUtils {
|
||||
|
||||
// 畅玩助手更新弹窗展示事件
|
||||
@JvmStatic
|
||||
fun logHaloFunUpdateDialogShow(gameId: String, gameName: String, gameArchitecture: String, targetVaVersion: String) {
|
||||
fun logHaloFunUpdateDialogShow(
|
||||
gameId: String,
|
||||
gameName: String,
|
||||
gameArchitecture: String,
|
||||
targetVaVersion: String
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "halo_fun_update_dialog_show"
|
||||
"game_id" to gameId
|
||||
@ -146,7 +153,12 @@ object NewFlatLogUtils {
|
||||
|
||||
// 畅玩助手更新弹窗点击事件
|
||||
@JvmStatic
|
||||
fun logHaloFunUpdateDialogClick(dialogType: String, buttonType: String, architecture: String, targetVaVersion: String) {
|
||||
fun logHaloFunUpdateDialogClick(
|
||||
dialogType: String,
|
||||
buttonType: String,
|
||||
architecture: String,
|
||||
targetVaVersion: String
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "halo_fun_update_dialog_click"
|
||||
"dialog_type" to dialogType
|
||||
@ -740,7 +752,7 @@ object NewFlatLogUtils {
|
||||
"search_key" to searchKey
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json)
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
}
|
||||
|
||||
//社区搜索结果浏览
|
||||
@ -752,7 +764,7 @@ object NewFlatLogUtils {
|
||||
"search_key" to searchKey
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json)
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
}
|
||||
|
||||
//社区搜索tab结果切换事件
|
||||
@ -764,7 +776,7 @@ object NewFlatLogUtils {
|
||||
"tab_type" to tab
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json)
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
}
|
||||
|
||||
//点击论坛-搜索页返回按钮
|
||||
@ -776,7 +788,7 @@ object NewFlatLogUtils {
|
||||
"bbs_id" to bbsId
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json)
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
}
|
||||
|
||||
//论坛搜索结果浏览
|
||||
@ -789,7 +801,7 @@ object NewFlatLogUtils {
|
||||
"bbs_id" to bbsId
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json)
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
}
|
||||
|
||||
//新版我的光环触发登录
|
||||
@ -869,7 +881,7 @@ object NewFlatLogUtils {
|
||||
"bbs_id" to bbsId
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json)
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
}
|
||||
|
||||
//个人主页-内容
|
||||
@ -882,7 +894,7 @@ object NewFlatLogUtils {
|
||||
"tab_name" to tabName
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json)
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
}
|
||||
|
||||
//游戏详情页-视频合集内容
|
||||
@ -894,7 +906,7 @@ object NewFlatLogUtils {
|
||||
"ref_user_id" to refUserId
|
||||
parseAndPutMeta().invoke(this)
|
||||
}
|
||||
log(json)
|
||||
log(json, LOG_STORE_BBS_COMMUNITY)
|
||||
}
|
||||
|
||||
//进入游戏详情
|
||||
|
||||
@ -31,9 +31,10 @@ object NewLogUtils {
|
||||
private const val KEY_CONTENT_TYPE = "content_type"
|
||||
private const val KEY_CONTENT_ID = "content_id"
|
||||
private const val KEY_USER_ID = "ref_user_id"
|
||||
private const val KEY_BUTTON = "button"
|
||||
|
||||
private const val LOG_STORE_EVENT = "event"
|
||||
private const val LOG_STORE_BBS = "bbs_community"
|
||||
const val LOG_STORE_BBS = "bbs_community"
|
||||
|
||||
private fun log(jsonObject: JSONObject, logStore: String, uploadImmediately: Boolean = false) {
|
||||
Utils.log("NewLogUtils", jsonObject.toString(4))
|
||||
@ -2104,7 +2105,13 @@ object NewLogUtils {
|
||||
|
||||
//点击底部导航栏
|
||||
@JvmStatic
|
||||
fun logBottomNavigationClick(navigationName: String, linkType: String, linkText: String, linkId: String = "", sequence: Int) {
|
||||
fun logBottomNavigationClick(
|
||||
navigationName: String,
|
||||
linkType: String,
|
||||
linkText: String,
|
||||
linkId: String = "",
|
||||
sequence: Int
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "bottom_navigation_click"
|
||||
"navigation_name" to navigationName
|
||||
@ -2638,4 +2645,183 @@ object NewLogUtils {
|
||||
}
|
||||
log(json, LOG_STORE_EVENT)
|
||||
}
|
||||
|
||||
/**
|
||||
* 社区推荐信息流曝光埋点
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getCommunityExposureJsonObject(
|
||||
contentId: String,
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
sequence: Int,
|
||||
location: String
|
||||
): JSONObject {
|
||||
return json {
|
||||
KEY_EVENT to "community_exposure"
|
||||
KEY_CONTENT_ID to contentId
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
"sequence" to sequence
|
||||
KEY_LOCATION to location
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:180
|
||||
* 事件ID:view_note_detail
|
||||
* 事件名称:进入图文帖详情页
|
||||
* 触发时机:点击图文帖类型的内容时触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logViewNoteDetail(
|
||||
contentId: String,
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
userId: String
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "view_note_detail"
|
||||
KEY_CONTENT_ID to contentId
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
KEY_USER_ID to userId
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:181
|
||||
* 事件ID:click_note_detail_more
|
||||
* 事件名称:点击更多按钮
|
||||
* 触发时机:点击时触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logClickNoteDetailMore() {
|
||||
val json = json {
|
||||
KEY_EVENT to "click_note_detail_more"
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:182
|
||||
* 事件ID:click_note_detail_profile_photo
|
||||
* 事件名称:点击头像
|
||||
* 触发时机:点击时触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logClickNoteDetailProfilePhoto(
|
||||
contentId: String,
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
userId: String
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "click_note_detail_profile_photo"
|
||||
KEY_CONTENT_ID to contentId
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
KEY_USER_ID to userId
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:183
|
||||
* 事件ID:click_note_detail_nickname
|
||||
* 事件名称:点击昵称
|
||||
* 触发时机:点击时触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logClickNoteDetailNickname(
|
||||
contentId: String,
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
userId: String
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "click_note_detail_nickname"
|
||||
KEY_CONTENT_ID to contentId
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
KEY_USER_ID to userId
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:184
|
||||
* 事件ID:click_note_detail_follow
|
||||
* 事件名称:点击关注按钮
|
||||
* 触发时机:点击时触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logClickNoteDetailFollow(
|
||||
contentId: String,
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
userId: String,
|
||||
follow: Boolean
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "click_note_detail_follow"
|
||||
KEY_CONTENT_ID to contentId
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
KEY_USER_ID to userId
|
||||
KEY_BUTTON to if(follow) "关注" else "取消关注"
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:185
|
||||
* 事件ID:jump_note_detail
|
||||
* 事件名称:跳出帖子详情页
|
||||
* 触发时机:跳出当前页后触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logJumpNoteDetail(
|
||||
contentId: String,
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
stayTime: Long
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "jump_note_detail"
|
||||
KEY_CONTENT_ID to contentId
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
"stay_time" to stayTime
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点序号:186
|
||||
* 事件ID:click_note_detail_forum
|
||||
* 事件名称:点击论坛
|
||||
* 触发时机:点击时触发
|
||||
*/
|
||||
@JvmStatic
|
||||
fun logClickNoteDetailForum(
|
||||
bbsId: String,
|
||||
bbsType: String,
|
||||
) {
|
||||
val json = json {
|
||||
KEY_EVENT to "click_note_detail_forum"
|
||||
KEY_BBS_ID to bbsId
|
||||
KEY_BBS_TYPE to bbsType
|
||||
parseAndPutMeta()(this)
|
||||
}
|
||||
log(json, LOG_STORE_BBS)
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.TopCutProcess
|
||||
import com.gh.gamecenter.databinding.ItemCommunityImageBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
import com.gh.gamecenter.feature.entity.ImageInfo
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
@ -311,7 +312,7 @@ class ImageContainerView : LinearLayout {
|
||||
|| images.isNullOrEmpty())
|
||||
return ImageContainerData(
|
||||
status = status,
|
||||
isPostCard = type == COMMUNITY_ARTICLE,
|
||||
isPostCard = type == COMMUNITY_ARTICLE || type == ImageArticleEntity.IMAGE_ARTICLE_TYPE,
|
||||
images = imageInfoList,
|
||||
video = video,
|
||||
show
|
||||
|
||||
@ -0,0 +1,277 @@
|
||||
package com.gh.common.view
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
|
||||
class RedBookBannerIndicatorView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0,
|
||||
) : View(context, attrs, defStyleAttr) {
|
||||
|
||||
private var defaultColor = com.gh.gamecenter.common.R.color.text_instance.toColor(context)
|
||||
private var selectedColor = com.gh.gamecenter.common.R.color.primary_theme.toColor(context)
|
||||
private var largeRadius = 2F.dip2px().toFloat()
|
||||
private var smallRadius = 1.2F.dip2px().toFloat()
|
||||
private var distanceBetweenCenters = 8F.dip2px().toFloat()
|
||||
private var maxShowDotCount = 5
|
||||
|
||||
private var lastPosition = 0
|
||||
private var currentPosition = 0
|
||||
private var firstShowPosition = 0
|
||||
private var lastShowPosition = 0
|
||||
|
||||
private var animationProgress = 0F
|
||||
|
||||
private var animationState: AnimationState = AnimationState.No
|
||||
|
||||
private var valueAnimator: ValueAnimator? = null
|
||||
|
||||
private val paint by lazy {
|
||||
Paint().apply {
|
||||
style = Paint.Style.FILL
|
||||
isAntiAlias = true
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
initAttrs(context, attrs)
|
||||
}
|
||||
|
||||
private fun initAttrs(context: Context, attrs: AttributeSet?) {
|
||||
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RedBookBannerIndicatorView)
|
||||
defaultColor = typedArray.getColor(R.styleable.RedBookBannerIndicatorView_default_color, defaultColor)
|
||||
selectedColor = typedArray.getColor(R.styleable.RedBookBannerIndicatorView_selected_color, selectedColor)
|
||||
largeRadius = typedArray.getDimension(R.styleable.RedBookBannerIndicatorView_large_radius, largeRadius)
|
||||
smallRadius = typedArray.getDimension(R.styleable.RedBookBannerIndicatorView_small_radius, smallRadius)
|
||||
distanceBetweenCenters = typedArray.getDimension(
|
||||
R.styleable.RedBookBannerIndicatorView_distance_between_centers,
|
||||
distanceBetweenCenters
|
||||
)
|
||||
maxShowDotCount =
|
||||
typedArray.getInt(R.styleable.RedBookBannerIndicatorView_max_show_dot_count, maxShowDotCount)
|
||||
typedArray.recycle()
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val width = if (lastPosition >= maxShowDotCount) {
|
||||
(maxShowDotCount - 1) * distanceBetweenCenters + 2 * largeRadius
|
||||
} else {
|
||||
lastShowPosition * distanceBetweenCenters + 2 * largeRadius
|
||||
}
|
||||
val height = largeRadius * 2
|
||||
setMeasuredDimension(width.toInt(), height.toInt())
|
||||
}
|
||||
|
||||
fun show(total: Int) {
|
||||
valueAnimator?.cancel()
|
||||
lastPosition = total - 1
|
||||
lastShowPosition = if (total > maxShowDotCount) {
|
||||
maxShowDotCount - 1
|
||||
} else {
|
||||
lastPosition
|
||||
}
|
||||
requestLayout()
|
||||
}
|
||||
|
||||
/**
|
||||
* 请注意,selectPosition只能一步一步跳
|
||||
* 比如:当currentPosition ==0 时,selectPosition为2,仍然只会往前跳一步,最终 currentPosition == 1
|
||||
*/
|
||||
fun selectPosition(position: Int) {
|
||||
if (currentPosition == position || position < 0 || position > lastPosition) {
|
||||
return
|
||||
}
|
||||
valueAnimator?.cancel()
|
||||
if (position > currentPosition) {
|
||||
currentPosition++
|
||||
} else if (position < currentPosition) {
|
||||
currentPosition--
|
||||
}
|
||||
|
||||
when (currentPosition) {
|
||||
0 -> {
|
||||
firstShowPosition = 0
|
||||
lastShowPosition = maxShowDotCount - 1
|
||||
if (lastShowPosition > lastPosition) {
|
||||
lastShowPosition = lastPosition
|
||||
}
|
||||
}
|
||||
|
||||
lastPosition -> {
|
||||
lastShowPosition = lastPosition
|
||||
firstShowPosition = lastPosition - maxShowDotCount + 1
|
||||
if (firstShowPosition < 0) {
|
||||
firstShowPosition = (0)
|
||||
}
|
||||
}
|
||||
|
||||
firstShowPosition -> {
|
||||
animationState = AnimationState.RightReady
|
||||
}
|
||||
|
||||
lastShowPosition -> {
|
||||
animationState = AnimationState.LeftReady
|
||||
}
|
||||
|
||||
}
|
||||
invalidate()
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
// 保存 Canvas 的当前状态
|
||||
canvas.save();
|
||||
|
||||
// 限制绘制区域为 View 的边界
|
||||
canvas.clipRect(0, 0, getWidth(), getHeight());
|
||||
if (lastShowPosition > firstShowPosition) {
|
||||
val first = if (firstShowPosition > 0) {
|
||||
firstShowPosition - 1
|
||||
} else {
|
||||
firstShowPosition
|
||||
}
|
||||
val last = if (lastShowPosition < lastPosition) {
|
||||
lastShowPosition + 1
|
||||
} else {
|
||||
lastPosition
|
||||
}
|
||||
|
||||
for (position in first..last) {
|
||||
var radius = when (position) {
|
||||
firstShowPosition -> if (firstShowPosition == 0) {
|
||||
largeRadius
|
||||
} else {
|
||||
smallRadius
|
||||
}
|
||||
|
||||
lastShowPosition -> if (lastShowPosition == lastPosition) {
|
||||
largeRadius
|
||||
} else {
|
||||
smallRadius
|
||||
}
|
||||
|
||||
else -> largeRadius
|
||||
}
|
||||
|
||||
val offset = if (animationState == AnimationState.LeftPlaying) {
|
||||
-animationProgress * distanceBetweenCenters
|
||||
} else {
|
||||
animationProgress * distanceBetweenCenters
|
||||
}
|
||||
val centerX = ((position - firstShowPosition) * distanceBetweenCenters + largeRadius) + offset
|
||||
paint.color = if (position == currentPosition) {
|
||||
selectedColor
|
||||
} else {
|
||||
defaultColor
|
||||
}
|
||||
|
||||
radius = getScaleRadius(position, radius)
|
||||
canvas.drawCircle(centerX, largeRadius, radius, paint)
|
||||
}
|
||||
|
||||
if (animationState == AnimationState.LeftReady || animationState == AnimationState.RightReady) {
|
||||
startAnimation()
|
||||
}
|
||||
}
|
||||
// 恢复 Canvas 到之前的状态
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
private fun getScaleRadius(position: Int, radius: Float): Float {
|
||||
var newRadius = radius
|
||||
if (animationState == AnimationState.LeftPlaying) {
|
||||
// 第二个可见的小圆点
|
||||
if (position - 1 == firstShowPosition) {
|
||||
newRadius = largeRadius - (largeRadius - smallRadius) * animationProgress
|
||||
}
|
||||
// 最后一个可见的小圆点
|
||||
if (position == lastShowPosition) {
|
||||
newRadius = smallRadius + (largeRadius - smallRadius) * animationProgress
|
||||
}
|
||||
// 最后一个不可见的小圆点
|
||||
if (position == lastShowPosition + 1) {
|
||||
newRadius = smallRadius
|
||||
}
|
||||
|
||||
}
|
||||
if (animationState == AnimationState.RightPlaying) {
|
||||
if (position == firstShowPosition - 1) {
|
||||
newRadius = smallRadius
|
||||
}
|
||||
if (position == firstShowPosition) {
|
||||
newRadius = smallRadius + (largeRadius - smallRadius) * animationProgress
|
||||
}
|
||||
if (position + 1 == lastShowPosition) {
|
||||
newRadius = largeRadius - (largeRadius - smallRadius) * animationProgress
|
||||
}
|
||||
}
|
||||
return newRadius
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行向左的平移动画
|
||||
*/
|
||||
private fun startAnimation() {
|
||||
animationState = if (animationState == AnimationState.LeftReady) {
|
||||
AnimationState.LeftPlaying
|
||||
} else {
|
||||
AnimationState.RightPlaying
|
||||
}
|
||||
fun resetShowPosition() {
|
||||
if (animationState == AnimationState.LeftPlaying) {
|
||||
firstShowPosition++
|
||||
lastShowPosition++
|
||||
} else {
|
||||
firstShowPosition--
|
||||
lastShowPosition--
|
||||
}
|
||||
animationState = AnimationState.No
|
||||
animationProgress = 0F
|
||||
invalidate()
|
||||
}
|
||||
valueAnimator = ValueAnimator.ofFloat(0F, 1F).apply {
|
||||
setDuration(ANIMATION_DURATION)
|
||||
addUpdateListener {
|
||||
val progress = it.animatedValue as Float
|
||||
animationProgress = progress
|
||||
invalidate()
|
||||
}
|
||||
addListener(object : Animator.AnimatorListener {
|
||||
override fun onAnimationStart(animation: Animator) = Unit
|
||||
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
resetShowPosition()
|
||||
}
|
||||
|
||||
override fun onAnimationCancel(animation: Animator) {
|
||||
resetShowPosition()
|
||||
}
|
||||
|
||||
override fun onAnimationRepeat(animation: Animator) = Unit
|
||||
|
||||
})
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ANIMATION_DURATION = 300L
|
||||
}
|
||||
|
||||
sealed class AnimationState {
|
||||
object No : AnimationState()
|
||||
object LeftReady : AnimationState()
|
||||
object RightReady : AnimationState()
|
||||
object LeftPlaying : AnimationState()
|
||||
object RightPlaying : AnimationState()
|
||||
}
|
||||
}
|
||||
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) {
|
||||
com.gh.gamecenter.common.R.color.text_theme
|
||||
} else {
|
||||
com.gh.gamecenter.common.R.color.text_secondary
|
||||
}
|
||||
binding.tvVoteCount.setTextColor(textColorResId.toColor(context))
|
||||
}
|
||||
|
||||
override fun setOnClickListener(l: OnClickListener?) {
|
||||
outClickListener = l
|
||||
super.setOnClickListener(inClickListener)
|
||||
}
|
||||
|
||||
private fun getVoteCountText(count: Int, context: Context) =
|
||||
when {
|
||||
count <= 0 -> R.string.like.toResString()
|
||||
count in 1 until VOTE_TEN_THOUSAND -> "$count"
|
||||
else -> context.getString(R.string.ten_thousand, "$count")
|
||||
}
|
||||
|
||||
private fun playVoteAnimation() {
|
||||
with(binding) {
|
||||
isAnimatorPlaying = true
|
||||
tvVoteCount.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
ivVote.isChecked = true
|
||||
ivVote.visibility = View.INVISIBLE
|
||||
voteAnimation.visibility = View.VISIBLE
|
||||
voteAnimation.setAnimation("lottie/community_vote.json")
|
||||
voteAnimation.playAnimation()
|
||||
voteAnimation.doOnAnimationEnd {
|
||||
voteAnimation.visibility = View.GONE
|
||||
ivVote.visibility = View.VISIBLE
|
||||
isAnimatorPlaying = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val VOTE_TEN_THOUSAND = 10000
|
||||
|
||||
private const val IMAGE_ARTICLE_PENDING = "pending"
|
||||
private const val IMAGE_ARTICLE_FAIL = "fail"
|
||||
private const val IMAGE_ARTICLE_PASS = "pass"
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
|
||||
@ -43,6 +43,7 @@ data class FollowDynamicEntity(
|
||||
const val FOLLOW_UPDATE_TYPE_LIBAO_EXCHANGE = "libao_exchange"
|
||||
const val FOLLOW_UPDATE_TYPE_ARTICLE = "article"
|
||||
const val FOLLOW_UPDATE_TYPE_USER_POST = "user_post"
|
||||
const val FOLLOW_UPDATE_TYPE_IMAGE_ARTICLE = "image_article"
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
|
||||
230
app/src/main/java/com/gh/gamecenter/entity/ImageArticleEntity.kt
Normal file
230
app/src/main/java/com/gh/gamecenter/entity/ImageArticleEntity.kt
Normal file
@ -0,0 +1,230 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.feature.entity.*
|
||||
import com.gh.gamecenter.feature.entity.TimeEntity
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class ImageArticleEntity(
|
||||
@SerializedName("_id")
|
||||
private var _id: String? = null,
|
||||
@SerializedName("title")
|
||||
private var _title: String? = null,
|
||||
@SerializedName("content")
|
||||
private val _content: String? = null,
|
||||
@SerializedName("community_id")
|
||||
private var _communityId: String? = null,
|
||||
@SerializedName("community_type")
|
||||
private val _communityType: String? = null,
|
||||
@SerializedName("sections")
|
||||
private val _sections: List<SectionEntity>? = null,
|
||||
@SerializedName("images")
|
||||
private var _images: List<String>? = null,
|
||||
@SerializedName("images_info")
|
||||
private val _imagesInfos: List<ImageInfo>? = null,
|
||||
@SerializedName("community")
|
||||
val community: Community? = null,
|
||||
@SerializedName("user")
|
||||
private val _user: UserEntity? = null,
|
||||
@SerializedName("time")
|
||||
private val _time: TimeEntity? = null,
|
||||
@SerializedName("status")
|
||||
private val _status: String? = null,
|
||||
@SerializedName("source")
|
||||
private val _source: SourceEntity? = null,
|
||||
@SerializedName("count")
|
||||
private val _count: Count? = null,
|
||||
@SerializedName("me")
|
||||
private val _me: MeEntity? = null,
|
||||
@SerializedName("_seq")
|
||||
private val _shortId: String? = null,
|
||||
@SerializedName("choiceness_status")
|
||||
private var _choicenessStatus: String? = null,// 精选状态 apply(申请), pass already(已精选) cancel not_yet(未精选)
|
||||
@SerializedName("recommend_id")
|
||||
private val _recommendId: String? = null,
|
||||
/**
|
||||
* 临时变量,区分是编辑发布还是编辑草稿
|
||||
*/
|
||||
var isDraft: Boolean = false
|
||||
) : Parcelable {
|
||||
|
||||
val id: String
|
||||
get() = _id ?: ""
|
||||
|
||||
val title: String
|
||||
get() = _title ?: ""
|
||||
|
||||
val content: String
|
||||
get() = _content ?: ""
|
||||
|
||||
val communityId: String
|
||||
get() = _communityId ?: ""
|
||||
|
||||
val communityType: String
|
||||
get() = _communityType ?: ""
|
||||
|
||||
val sections: List<SectionEntity>
|
||||
get() = _sections ?: emptyList()
|
||||
|
||||
val images: List<String>
|
||||
get() = _images ?: emptyList()
|
||||
|
||||
val imagesInfos: List<ImageInfo>
|
||||
get() = _imagesInfos ?: emptyList()
|
||||
|
||||
val user: UserEntity
|
||||
get() = _user ?: UserEntity()
|
||||
|
||||
val time: TimeEntity
|
||||
get() = _time ?: TimeEntity()
|
||||
|
||||
val status: String
|
||||
get() = _status ?: "pending"
|
||||
|
||||
val source: SourceEntity
|
||||
get() = _source ?: SourceEntity()
|
||||
|
||||
val count: Count
|
||||
get() = _count ?: Count()
|
||||
|
||||
val me: MeEntity
|
||||
get() = _me ?: MeEntity()
|
||||
|
||||
val shortId: String
|
||||
get() = _shortId ?: ""
|
||||
|
||||
var choicenessStatus: String
|
||||
get() = _choicenessStatus ?: ""
|
||||
set(value) {
|
||||
_choicenessStatus = value
|
||||
}
|
||||
|
||||
val recommendId: String
|
||||
get() = _recommendId ?: ""
|
||||
|
||||
fun getSimplifyChoicenessStatus(): String {
|
||||
return when (choicenessStatus) {
|
||||
"already" -> "pass"
|
||||
"not_yet" -> "cancel"
|
||||
else -> choicenessStatus ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val IMAGE_ARTICLE_TYPE = "image_article"
|
||||
|
||||
fun getImageRadio(imageInfo: ImageInfo?, minRadio: Float, maxRadio: Float): Float {
|
||||
return if (imageInfo != null && imageInfo.width > 0 && imageInfo.height > 0) {
|
||||
val imageRadio = imageInfo.height.toFloat() / imageInfo.width
|
||||
when {
|
||||
imageRadio < minRadio -> {
|
||||
minRadio
|
||||
}
|
||||
|
||||
imageRadio in 0.5..1.33 -> {
|
||||
imageRadio
|
||||
}
|
||||
|
||||
else -> {
|
||||
maxRadio
|
||||
}
|
||||
}
|
||||
} else {
|
||||
minRadio
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
data class Community(
|
||||
@SerializedName("_id")
|
||||
private val _id: String? = null,
|
||||
@SerializedName("name")
|
||||
private val _name: String? = null,
|
||||
@SerializedName("icon")
|
||||
private val _icon: String? = null,
|
||||
@SerializedName("hot")
|
||||
private val _hot: Int? = null,
|
||||
@SerializedName("game")
|
||||
val game: GameEntity? = null,
|
||||
@SerializedName("type")
|
||||
private val _type: String? = null,
|
||||
@SerializedName("me")
|
||||
private val _me: MeEntity?
|
||||
) : Parcelable {
|
||||
|
||||
val id: String
|
||||
get() = _id ?: ""
|
||||
|
||||
val name: String
|
||||
get() = _name ?: ""
|
||||
|
||||
val icon: String
|
||||
get() = _icon ?: ""
|
||||
|
||||
val hot: Int
|
||||
get() = _hot ?: 0
|
||||
|
||||
val type: String
|
||||
get() = _type ?: "game_bbs"
|
||||
|
||||
val typeChinese: String
|
||||
get() = when (type) {
|
||||
"game_bbs" -> "游戏论坛"
|
||||
"official_bbs" -> "综合论坛"
|
||||
else -> ""
|
||||
}
|
||||
|
||||
var isFollowed: Boolean
|
||||
get() = _me?.isFollower ?: false
|
||||
set(value) {
|
||||
_me?.isFollower = value
|
||||
}
|
||||
|
||||
fun toCommunityEntity() = CommunityEntity(
|
||||
id = id,
|
||||
name = name,
|
||||
icon = icon,
|
||||
type = type,
|
||||
)
|
||||
}
|
||||
|
||||
fun toPersonHistoryEntity() = PersonalHistoryEntity().also {
|
||||
it.id = id
|
||||
it.title = title
|
||||
it.brief = content
|
||||
it.community = community?.toCommunityEntity() ?: CommunityEntity()
|
||||
it.sections = sections
|
||||
it.images = images
|
||||
it.imagesInfo = imagesInfos
|
||||
it.count = count
|
||||
it.user = user
|
||||
it.time = time.update
|
||||
it.status = status
|
||||
it.me = me
|
||||
}
|
||||
|
||||
fun toAnswerEntity() = AnswerEntity().also {
|
||||
it.id = id
|
||||
it.title = title
|
||||
it.brief = content
|
||||
it.content = content
|
||||
it.community = community?.toCommunityEntity() ?: CommunityEntity()
|
||||
it.sections = sections
|
||||
it.images = images
|
||||
it.imagesInfo = imagesInfos
|
||||
it.count = count
|
||||
it.user = user
|
||||
it.time = time.update
|
||||
it.status = status
|
||||
it.me = me
|
||||
it.type = IMAGE_ARTICLE_TYPE
|
||||
}
|
||||
|
||||
}
|
||||
@ -36,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()
|
||||
}
|
||||
@ -1,11 +1,13 @@
|
||||
package com.gh.gamecenter.forum.detail
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
import com.gh.gamecenter.common.constant.ItemViewType
|
||||
import com.gh.gamecenter.common.syncpage.ISyncAdapterHandler
|
||||
@ -14,6 +16,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 +25,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 +52,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 +60,17 @@ class ForumArticleAskListAdapter(
|
||||
ItemViewType.ITEM_HEADER -> {
|
||||
ForumArticleHeadViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
ItemViewType.ITEM_FOOTER -> {
|
||||
FooterViewHolder(mLayoutInflater.inflate(com.gh.gamecenter.common.R.layout.refresh_footerview, parent, false))
|
||||
FooterViewHolder(
|
||||
mLayoutInflater.inflate(
|
||||
com.gh.gamecenter.common.R.layout.refresh_footerview,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
ForumArticleAskItemViewHolder(
|
||||
CommunityAnswerItemBinding.bind(
|
||||
@ -95,7 +108,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 +162,7 @@ class ForumArticleAskListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"video" -> {
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
"click_forum_detail_content",
|
||||
@ -164,8 +179,16 @@ class ForumArticleAskListAdapter(
|
||||
holder.getKey(entrance),
|
||||
"${answer.title}(${answer.id})"
|
||||
)
|
||||
mContext.startActivity(ForumVideoDetailActivity.getIntent(mContext, answer.id, bbsId, "论坛详情-信息流"))
|
||||
mContext.startActivity(
|
||||
ForumVideoDetailActivity.getIntent(
|
||||
mContext,
|
||||
answer.id,
|
||||
bbsId,
|
||||
"论坛详情-信息流"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"question" -> {
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
"click_forum_detail_content",
|
||||
@ -188,6 +211,7 @@ class ForumArticleAskListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"answer" -> {
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
"click_forum_detail_content",
|
||||
@ -215,29 +239,63 @@ class ForumArticleAskListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
"click_forum_detail_content",
|
||||
userId,
|
||||
contentId,
|
||||
"图文",
|
||||
sequence,
|
||||
bbsId,
|
||||
bbsType,
|
||||
tabInfo
|
||||
)
|
||||
val uri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, answer.id)
|
||||
.appendQueryParameter(EntranceConsts.KEY_SOURCE_ENTRANCE, "论坛详情-信息流")
|
||||
.build()
|
||||
ARouter.getInstance().build(uri).navigation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ItemViewType.ITEM_FOOTER -> {
|
||||
val footerViewHolder = holder as FooterViewHolder
|
||||
footerViewHolder.initItemPadding()
|
||||
footerViewHolder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver)
|
||||
footerViewHolder.hint.textSize = 12f
|
||||
footerViewHolder.hint.setTextColor(ContextCompat.getColor(mContext, com.gh.gamecenter.common.R.color.aaaaaa))
|
||||
footerViewHolder.hint.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
mContext,
|
||||
com.gh.gamecenter.common.R.color.aaaaaa
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ItemViewType.ITEM_HEADER -> {
|
||||
if (holder is ForumArticleHeadViewHolder) {
|
||||
val articleListHead = if (path == "全部") {
|
||||
viewModel.selectedSection.name
|
||||
} else path
|
||||
holder.binding.root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(mContext))
|
||||
holder.binding.articleListHeadTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
|
||||
holder.binding.articleListHeadTv.setTextColor(
|
||||
com.gh.gamecenter.common.R.color.text_primary.toColor(
|
||||
mContext
|
||||
)
|
||||
)
|
||||
holder.binding.articleListHeadTv.text = "${articleListHead}列表"
|
||||
|
||||
if (path != "精华") {
|
||||
holder.binding.orderSfv.run {
|
||||
visibility = View.VISIBLE
|
||||
setContainerBackground(com.gh.gamecenter.common.R.drawable.button_round_f5f5f5.toDrawable(mContext))
|
||||
setContainerBackground(
|
||||
com.gh.gamecenter.common.R.drawable.button_round_f5f5f5.toDrawable(
|
||||
mContext
|
||||
)
|
||||
)
|
||||
setIndicatorBackground(R.drawable.bg_game_collection_sfv_indicator.toDrawable(mContext))
|
||||
setTextColor(
|
||||
com.gh.gamecenter.common.R.color.text_secondary.toColor(mContext),
|
||||
|
||||
@ -10,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,72 @@ class ForumArticleAskListFragment : LazyListFragment<AnswerEntity, ForumArticleA
|
||||
mScrollCalculatorHelper?.currentPlayer?.release()
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
when {
|
||||
changed is EBImageArticleChanged.VoteChanged -> {
|
||||
updateImageArticleItem(changed.id, true) {
|
||||
val newCount = it.count
|
||||
newCount.vote = changed.count
|
||||
it.count = newCount
|
||||
it.me.isCommunityArticleVote = changed.isVoted
|
||||
}
|
||||
}
|
||||
|
||||
changed is EBImageArticleChanged.CommentChanged -> {
|
||||
updateImageArticleItem(changed.id, true) {
|
||||
val newCount = it.count
|
||||
newCount.comment = changed.count
|
||||
it.count = newCount
|
||||
}
|
||||
}
|
||||
|
||||
changed is EBImageArticleChanged.DataDeleted -> {
|
||||
mViewModel?.deleteImageArticle(changed.imageArticleId)
|
||||
}
|
||||
|
||||
changed is EBImageArticleChanged.DataChanged -> {
|
||||
val imageArticle = changed.data
|
||||
updateImageArticleItem(changed.data.id, false) {
|
||||
it.title = imageArticle.title
|
||||
it.brief = imageArticle.content
|
||||
it.images = imageArticle.images
|
||||
it.imagesInfo = imageArticle.imagesInfos
|
||||
it.community = imageArticle.community?.toCommunityEntity() ?: CommunityEntity()
|
||||
it.sections = imageArticle.sections
|
||||
it.count = imageArticle.count
|
||||
it.user = imageArticle.user
|
||||
it.time = imageArticle.time.update
|
||||
it.status = imageArticle.status
|
||||
}
|
||||
}
|
||||
|
||||
changed is EBImageArticleChanged.DataCreated -> {
|
||||
mViewModel?.addNewestImageArticle(changed.imageArticle.toAnswerEntity())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateImageArticleItem(
|
||||
id: String,
|
||||
hasPayload: Boolean,
|
||||
block: (AnswerEntity) -> Unit
|
||||
) {
|
||||
val dataList = mAdapter?.entityList ?: return
|
||||
val position =
|
||||
dataList.indexOfFirst { it.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE && it.id == id }
|
||||
if (position != -1) {
|
||||
val item = dataList[position]
|
||||
block(item)
|
||||
if (hasPayload) {
|
||||
mAdapter?.notifyItemChanged(position, USER_HISTORY_PAYLOADS_VOTE_CHANGED)
|
||||
} else {
|
||||
mAdapter?.notifyItemChanged(position)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLoadRefresh() {
|
||||
super.onLoadRefresh()
|
||||
if (::mBinding.isInitialized) {
|
||||
|
||||
@ -4,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
|
||||
|
||||
@ -8,6 +8,7 @@ import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
@ -28,6 +29,7 @@ import androidx.core.os.bundleOf
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
@ -35,6 +37,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 +59,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 +83,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 +270,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)
|
||||
@ -304,7 +311,12 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
|
||||
}
|
||||
|
||||
if (absVerticalOffset == total) {
|
||||
mBinding.toolbar.setTitleTextColor(ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.black))
|
||||
mBinding.toolbar.setTitleTextColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
com.gh.gamecenter.common.R.color.black
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
mViewPager.doOnPageSelected {
|
||||
@ -630,7 +642,10 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
|
||||
params.topMargin = DisplayUtils.dip2px(-8f)
|
||||
mBinding.tabContainer.layoutParams = params
|
||||
mBinding.tabContainer.background =
|
||||
ContextCompat.getDrawable(requireContext(), com.gh.gamecenter.common.R.drawable.background_shape_white_radius_5_top_only)
|
||||
ContextCompat.getDrawable(
|
||||
requireContext(),
|
||||
com.gh.gamecenter.common.R.drawable.background_shape_white_radius_5_top_only
|
||||
)
|
||||
}
|
||||
|
||||
if (background.isEmpty()) {
|
||||
@ -881,7 +896,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(
|
||||
@ -1020,14 +1035,31 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
|
||||
val headView = SimpleDraweeView(requireContext())
|
||||
val roundingParams = RoundingParams().apply {
|
||||
roundAsCircle = true
|
||||
setBorder(ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.white), 1F.dip2px().toFloat())
|
||||
setBorder(
|
||||
ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.white),
|
||||
1F.dip2px().toFloat()
|
||||
)
|
||||
}
|
||||
headView.hierarchy = GenericDraweeHierarchyBuilder(resources)
|
||||
.setFadeDuration(500)
|
||||
.setRoundingParams(roundingParams)
|
||||
.setPressedStateOverlay(ColorDrawable(ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.pressed_bg)))
|
||||
.setPressedStateOverlay(
|
||||
ColorDrawable(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
com.gh.gamecenter.common.R.color.pressed_bg
|
||||
)
|
||||
)
|
||||
)
|
||||
.setPlaceholderImage(com.gh.gamecenter.common.R.drawable.occupy2, ScalingUtils.ScaleType.CENTER)
|
||||
.setBackground(ColorDrawable(ContextCompat.getColor(requireContext(), com.gh.gamecenter.common.R.color.placeholder_bg)))
|
||||
.setBackground(
|
||||
ColorDrawable(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
com.gh.gamecenter.common.R.color.placeholder_bg
|
||||
)
|
||||
)
|
||||
)
|
||||
.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP)
|
||||
.build()
|
||||
headView.layoutParams = params
|
||||
@ -1089,6 +1121,35 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
|
||||
}
|
||||
}
|
||||
|
||||
contentView.findViewById<View>(R.id.community_edit_recommend_container).setOnClickListener {
|
||||
val icon = if ("official_bbs" == mForumDetail?.type) {
|
||||
mForumDetail?.icon ?: ""
|
||||
} else {
|
||||
mForumDetail?.game?.getIcon()
|
||||
}
|
||||
context?.ifLogin("论坛详情-发布-图文动态", action = {
|
||||
val uri = Uri.Builder()
|
||||
.path(RouteConsts.activity.publishImageArticleActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_ENTRANCE, "论坛详情页")
|
||||
.build()
|
||||
ARouter.getInstance()
|
||||
.build(uri)
|
||||
.withParcelable(
|
||||
EntranceConsts.KEY_COMMUNITY_DATA,
|
||||
CommunityEntity(
|
||||
mBbsId,
|
||||
name = mForumDetail?.name ?: "",
|
||||
iconSubscript = mForumDetail?.game?.iconSubscript,
|
||||
icon = icon,
|
||||
type = mForumDetail?.type ?: "",
|
||||
game = mForumDetail?.game?.toCommunityGameEntity()
|
||||
)
|
||||
)
|
||||
.navigation()
|
||||
dialog.dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
contentView.findViewById<View>(R.id.community_edit_article_container).setOnClickListener {
|
||||
context?.ifLogin("论坛详情-发布-发帖子", action = {
|
||||
checkStoragePermissionBeforeAction {
|
||||
@ -1214,10 +1275,12 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
|
||||
private fun toggleHighlightedView(targetView: View, highlightIt: Boolean) {
|
||||
val sectionTv = targetView.findViewById<TextView>(R.id.titleTv)
|
||||
if (highlightIt) {
|
||||
targetView.background = com.gh.gamecenter.common.R.drawable.button_round_theme_alpha_10.toDrawable(requireContext())
|
||||
targetView.background =
|
||||
com.gh.gamecenter.common.R.drawable.button_round_theme_alpha_10.toDrawable(requireContext())
|
||||
sectionTv?.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
|
||||
} else {
|
||||
targetView.background = com.gh.gamecenter.feature.R.drawable.button_round_gray_light.toDrawable(requireContext())
|
||||
targetView.background =
|
||||
com.gh.gamecenter.feature.R.drawable.button_round_gray_light.toDrawable(requireContext())
|
||||
sectionTv?.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,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
|
||||
@ -68,6 +73,7 @@ import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
|
||||
import com.halo.assistant.HaloApp
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import splitties.resources.int
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@ -127,6 +133,7 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
override fun getRealLayoutId(): Int {
|
||||
return R.layout.fragment_community_home
|
||||
}
|
||||
@ -135,7 +142,6 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
mBinding = FragmentCommunityHomeBinding.bind(inflatedView)
|
||||
}
|
||||
|
||||
|
||||
override fun onFragmentFirstVisible() {
|
||||
ArticleDetailWebCacheManager.init(requireContext().applicationContext)
|
||||
|
||||
@ -162,7 +168,8 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
|
||||
private fun addHomeVideoGuideHandler() {
|
||||
val decorView = activity?.window?.decorView as? FrameLayout
|
||||
val communityHomeGuideHandler = CommunityHomeGuideHandler(21, requireContext(), decorView, mBinding?.videoLottie)
|
||||
val communityHomeGuideHandler =
|
||||
CommunityHomeGuideHandler(21, requireContext(), decorView, mBinding?.videoLottie)
|
||||
mPriorityChain.addHandler(communityHomeGuideHandler)
|
||||
}
|
||||
|
||||
@ -306,14 +313,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 "社区"))
|
||||
@ -334,9 +341,18 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
doOnScroll(
|
||||
onPageSelected = { position ->
|
||||
communityEditBtn.goneIf(position != TAB_RECOMMEND_INDEX && position != TAB_FOLLOW_INDEX)
|
||||
if (position == TAB_RECOMMEND_INDEX) {
|
||||
communityEditBtn.setImageResource(R.drawable.ic_community_float_publish)
|
||||
} else {
|
||||
communityEditBtn.setImageResource(R.drawable.ic_community_float_create)
|
||||
}
|
||||
when (position) {
|
||||
TAB_FOLLOW_INDEX -> {
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_background.toColor(requireContext()))
|
||||
root.setBackgroundColor(
|
||||
com.gh.gamecenter.common.R.color.ui_background.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
topBg.translationY = 0F
|
||||
changeNavigationBg()
|
||||
NewLogUtils.logCommunityHomeEvent("click_for_you_tab")
|
||||
@ -344,7 +360,11 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
|
||||
TAB_RECOMMEND_INDEX -> {
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_background.toColor(requireContext()))
|
||||
root.setBackgroundColor(
|
||||
com.gh.gamecenter.common.R.color.ui_background.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
topBg.translationY = 0F
|
||||
changeNavigationBg()
|
||||
NewLogUtils.logCommunityHomeEvent("click_for_you_tab")
|
||||
@ -352,7 +372,11 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
|
||||
TAB_FORUM_INDEX -> {
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
|
||||
root.setBackgroundColor(
|
||||
com.gh.gamecenter.common.R.color.ui_surface.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
(mFragmentList[2] as ForumFragment).translationY.run {
|
||||
topBg.translationY = -this.toFloat()
|
||||
changeNavigationBg(this)
|
||||
@ -362,7 +386,11 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
|
||||
TAB_ACTIVITY_INDEX -> {
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_background.toColor(requireContext()))
|
||||
root.setBackgroundColor(
|
||||
com.gh.gamecenter.common.R.color.ui_background.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
(mFragmentList[3] as ForumActivityFragment).translationY.run {
|
||||
topBg.translationY = -this.toFloat()
|
||||
changeNavigationBg(this)
|
||||
@ -587,6 +615,20 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
UserRepository.getInstance().loginUserInfo.removeObserver(observer)
|
||||
}
|
||||
|
||||
contentView.findViewById<View>(R.id.community_edit_recommend_container).setOnClickListener {
|
||||
context?.ifLogin("论坛首页-发布-图文动态", action = {
|
||||
showRegulationTestDialogIfNeeded {
|
||||
NewLogUtils.logArticleEditEnter("推荐信息流", "", "")
|
||||
// ARouter不支持 Fragment.startActivityForResult的形式启动页面,这里无奈只能使用原生方法
|
||||
// ARouter.getInstance().build(RouteConsts.activity.publishImageArticleActivity)
|
||||
// .navigation(this, IMAGE_ARTICLE_REQUEST_CODE)
|
||||
val intent = PublishImageArticleActivity.getIntent(requireContext(), "社区推荐Tab")
|
||||
startActivityForResult(intent, IMAGE_ARTICLE_REQUEST_CODE)
|
||||
}
|
||||
dialog.dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
contentView.findViewById<View>(R.id.community_edit_article_container).setOnClickListener {
|
||||
context?.ifLogin("论坛首页-发布-发帖子", action = {
|
||||
showRegulationTestDialogIfNeeded {
|
||||
@ -637,6 +679,7 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun resetFollowTab() {
|
||||
mBinding?.tabLayout?.run {
|
||||
if (selectedTabPosition == TAB_FOLLOW_INDEX) {
|
||||
@ -653,6 +696,11 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
IMAGE_ARTICLE_REQUEST_CODE -> {
|
||||
// 发布图文成功,切换到推荐tab
|
||||
mBinding?.viewPager?.setCurrentItem(TAB_RECOMMEND_INDEX, false)
|
||||
}
|
||||
|
||||
ARTICLE_REQUEST_CODE -> {
|
||||
val articleId = data?.getStringExtra("article_id") ?: return
|
||||
// val communityId = data?.getStringExtra("community_id") ?: return
|
||||
@ -675,13 +723,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()
|
||||
@ -790,7 +838,11 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
}
|
||||
tvTitle.setTextColor(
|
||||
ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
ColorStateList.valueOf(
|
||||
com.gh.gamecenter.common.R.color.text_primary.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -799,7 +851,9 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
mBinding?.run {
|
||||
root.setBackgroundColor(
|
||||
if (viewPager.currentItem == TAB_FORUM_INDEX) com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()) else com.gh.gamecenter.common.R.color.ui_background.toColor(
|
||||
if (viewPager.currentItem == TAB_FORUM_INDEX) com.gh.gamecenter.common.R.color.ui_surface.toColor(
|
||||
requireContext()
|
||||
) else com.gh.gamecenter.common.R.color.ui_background.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
@ -820,10 +874,12 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
}
|
||||
searchIconIv.setImageResource(R.drawable.ic_column_search)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
searchIconIv.imageTintList = ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
searchIconIv.imageTintList =
|
||||
ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
}
|
||||
|
||||
val csl = AppCompatResources.getColorStateList(requireContext(), com.gh.gamecenter.common.R.color.text_primary)
|
||||
val csl =
|
||||
AppCompatResources.getColorStateList(requireContext(), com.gh.gamecenter.common.R.color.text_primary)
|
||||
val filter = SimpleColorFilter(csl.defaultColor)
|
||||
val keyPath = KeyPath("**")
|
||||
val callback = LottieValueCallback<ColorFilter>(filter)
|
||||
@ -856,6 +912,7 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
const val ARTICLE_REQUEST_CODE = 200
|
||||
const val QUESTION_REQUEST_CODE = 201
|
||||
const val VIDEO_REQUEST_CODE = 202
|
||||
const val IMAGE_ARTICLE_REQUEST_CODE = 203
|
||||
const val LAST_SELECTED_POSITION = "last_selected_position"
|
||||
const val EB_SHOW_QUESTION_BUTTON = "EB_SHOW_QUESTION_BUTTON"
|
||||
const val EB_HIDE_QUESTION_BUTTON = "EB_HIDE_QUESTION_BUTTON"
|
||||
|
||||
@ -8,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
|
||||
|
||||
@ -4,8 +4,10 @@ package com.gh.gamecenter.forum.home
|
||||
import android.app.Activity
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.net.Uri
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.view.View
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.DialogUtils
|
||||
@ -17,6 +19,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 +28,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
|
||||
@ -106,9 +111,14 @@ class ForumArticleAskItemViewHolder(
|
||||
else -> R.drawable.icon_forum_fail
|
||||
}
|
||||
)
|
||||
title.goneIf(entity.type == "answer")
|
||||
title.text = if (entity.type.contains("video")) entity.title else entity.questions.title
|
||||
content.text = if (entity.type.contains("video")) entity.des else entity.brief
|
||||
val titleText = if (entity.type.contains("video")) entity.title else entity.questions.title
|
||||
title.goneIf(entity.type == "answer" || titleText.isNullOrEmpty()) {
|
||||
title.text = titleText
|
||||
}
|
||||
val contentText = if (entity.type.contains("video")) entity.des else entity.brief
|
||||
content.goneIf(contentText.isEmpty()) {
|
||||
content.text = contentText
|
||||
}
|
||||
popularAnswerContainer.background = GradientDrawable().apply {
|
||||
setColor(Color.parseColor("#F5F6F7"))
|
||||
cornerRadius = 4F.dip2px().toFloat()
|
||||
@ -138,11 +148,8 @@ class ForumArticleAskItemViewHolder(
|
||||
binding.title.text = SpanBuilder(title).image(0, 1, this).build()
|
||||
}
|
||||
} else {
|
||||
binding.content.visibility = View.VISIBLE
|
||||
if (entity.type == "video") {
|
||||
binding.content.goneIf(entity.des.isEmpty())
|
||||
} else {
|
||||
binding.content.visibility = View.VISIBLE
|
||||
}
|
||||
//若文章内有图片和视频,标题后增加‘有视频’标签 issues-1052
|
||||
if (entity.getPassVideos().isNotEmpty()) {
|
||||
@ -202,6 +209,7 @@ class ForumArticleAskItemViewHolder(
|
||||
"community_article" -> "帖子"
|
||||
"video" -> "视频帖"
|
||||
"question" -> "提问帖"
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> "图文"
|
||||
else -> "提问帖评论"
|
||||
}
|
||||
val userId = user.id ?: ""
|
||||
@ -380,6 +388,7 @@ class ForumArticleAskItemViewHolder(
|
||||
voteCountContainer.visibility = View.GONE
|
||||
}
|
||||
|
||||
forumNameContainer?.visibleIf(entity.community.id.isNotBlank())
|
||||
if (entity.community.type == "official_bbs") {
|
||||
forumIcon?.displayGameIcon(entity.community.icon, null)
|
||||
} else {
|
||||
@ -449,15 +458,17 @@ class ForumArticleAskItemViewHolder(
|
||||
"community_article" -> "帖子"
|
||||
"video" -> "视频帖"
|
||||
"question" -> "提问帖"
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> "图文"
|
||||
else -> "提问帖评论"
|
||||
}
|
||||
val sequence = position + 1
|
||||
val bbsId = entity.community.id
|
||||
val bbsType = if (entity.community.type == "official_bbs") "综合论坛" else "游戏论坛"
|
||||
val bbsType = entity.community.typeChinese
|
||||
val tabInfo = "${path}tab"
|
||||
val commentType = when (entity.type) {
|
||||
"community_article" -> "帖子评论"
|
||||
"video" -> "视频帖评论"
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE ->"图文评论"
|
||||
else -> "提问帖评论"
|
||||
}
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
@ -528,6 +539,14 @@ class ForumArticleAskItemViewHolder(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, entity.id)
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -544,11 +563,12 @@ class ForumArticleAskItemViewHolder(
|
||||
"community_article" -> "帖子"
|
||||
"video" -> "视频帖"
|
||||
"question" -> "提问帖"
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> "图文"
|
||||
else -> "提问帖评论"
|
||||
}
|
||||
val sequence = position + 1
|
||||
val bbsId = entity.community.id
|
||||
val bbsType = if (entity.community.type == "official_bbs") "综合论坛" else "游戏论坛"
|
||||
val bbsType = entity.community.typeChinese
|
||||
val tabInfo = "${path}tab"
|
||||
NewLogUtils.logForumDetailFeedContentClick(
|
||||
"click_forum_detail_like",
|
||||
|
||||
@ -16,6 +16,7 @@ import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.viewholder.FooterViewHolder
|
||||
import com.gh.gamecenter.core.utils.MtaHelper
|
||||
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
|
||||
import com.gh.gamecenter.feature.entity.ArticleEntity
|
||||
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
|
||||
@ -71,7 +72,10 @@ class ForumArticleListAdapter(
|
||||
topMargin = if (position == 0) 8F.dip2px() else 0
|
||||
}
|
||||
if (position == 0) {
|
||||
root.background = com.gh.gamecenter.common.R.drawable.background_shape_white_radius_12_top_only.toDrawable(mContext)
|
||||
root.background =
|
||||
com.gh.gamecenter.common.R.drawable.background_shape_white_radius_12_top_only.toDrawable(
|
||||
mContext
|
||||
)
|
||||
} else {
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(mContext))
|
||||
}
|
||||
@ -98,6 +102,7 @@ class ForumArticleListAdapter(
|
||||
"community_article" -> "帖子"
|
||||
"video" -> "视频帖"
|
||||
"question" -> "提问帖"
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> "图文"
|
||||
else -> "提问帖评论"
|
||||
}
|
||||
val bbsType = if (community.type == "official_bbs") "综合论坛" else "游戏论坛"
|
||||
@ -136,6 +141,7 @@ class ForumArticleListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"video" -> {
|
||||
MtaHelper.onEvent(
|
||||
"论坛首页",
|
||||
@ -157,6 +163,7 @@ class ForumArticleListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"question" -> {
|
||||
MtaHelper.onEvent(
|
||||
"论坛首页",
|
||||
@ -180,6 +187,7 @@ class ForumArticleListAdapter(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"answer" -> {
|
||||
MtaHelper.onEvent(
|
||||
"论坛首页",
|
||||
@ -213,7 +221,12 @@ class ForumArticleListAdapter(
|
||||
footerViewHolder.initItemPadding()
|
||||
footerViewHolder.initFooterViewHolder(viewModel, mIsLoading, mIsNetworkError, mIsOver)
|
||||
footerViewHolder.hint.textSize = 12f
|
||||
footerViewHolder.hint.setTextColor(ContextCompat.getColor(mContext, com.gh.gamecenter.common.R.color.aaaaaa))
|
||||
footerViewHolder.hint.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
mContext,
|
||||
com.gh.gamecenter.common.R.color.aaaaaa
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,14 +2,19 @@ package com.gh.gamecenter.forum.home.follow
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.ActivityResultRegistry
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.activity.result.contract.ActivityResultContracts.GetContent
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.common.util.SyncDataBetweenPageHelper
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity
|
||||
import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
import com.gh.gamecenter.feature.entity.ArticleEntity
|
||||
@ -235,6 +240,15 @@ class FollowActivityResultLauncher(
|
||||
questionsDetailLauncher.launch(LauncherDestination(position, historyEntity = entity))
|
||||
}
|
||||
|
||||
entity.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, entity.id)
|
||||
.appendQueryParameter(EntranceConsts.KEY_SOURCE_ENTRANCE, "关注-个人动态")
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
}
|
||||
|
||||
else -> {
|
||||
commentEntityLauncher.launch(LauncherDestination(position, historyEntity = entity))
|
||||
}
|
||||
@ -258,6 +272,14 @@ class FollowActivityResultLauncher(
|
||||
"answer" -> {
|
||||
questionsDetailLauncher.launch(LauncherDestination(position, answerEntity = answerEntity))
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_SOURCE_ENTRANCE, "关注-论坛动态")
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
package com.gh.gamecenter.forum.home.follow
|
||||
|
||||
import com.gh.gamecenter.entity.HistoryGameEntity
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity
|
||||
import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
import com.gh.gamecenter.feature.entity.Count
|
||||
import com.gh.gamecenter.feature.entity.MeEntity
|
||||
|
||||
abstract class FollowDynamicItem {
|
||||
|
||||
@ -19,6 +20,14 @@ abstract class FollowDynamicItem {
|
||||
|
||||
protected open fun doAreContentsTheSame(other: FollowDynamicItem) = this == other
|
||||
|
||||
open val id = ""
|
||||
|
||||
open val type = ""
|
||||
|
||||
open var count: Count = Count()
|
||||
|
||||
open val me = MeEntity()
|
||||
|
||||
companion object {
|
||||
|
||||
const val FOLLOW_DYNAMIC_ITEM_TYPE_FOOTER = -1
|
||||
@ -39,6 +48,21 @@ data class FollowDynamicPersonalItem(
|
||||
&& data.id == other.data.id
|
||||
}
|
||||
|
||||
override val id: String
|
||||
get() = data.id
|
||||
|
||||
override val type: String
|
||||
get() = data.type
|
||||
|
||||
override var count: Count
|
||||
get() = data.count
|
||||
set(value) {
|
||||
data.count = value
|
||||
}
|
||||
|
||||
override val me: MeEntity
|
||||
get() = data.me
|
||||
|
||||
}
|
||||
|
||||
data class FollowDynamicBbsItem(
|
||||
@ -53,6 +77,20 @@ data class FollowDynamicBbsItem(
|
||||
&& data.id == other.data.id
|
||||
}
|
||||
|
||||
override val id: String
|
||||
get() = data.id
|
||||
|
||||
override val type: String
|
||||
get() = data.type
|
||||
|
||||
override var count: Count
|
||||
get() = data.count
|
||||
set(value) {
|
||||
data.count = value
|
||||
}
|
||||
|
||||
override val me: MeEntity
|
||||
get() = data.me
|
||||
}
|
||||
|
||||
object FollowDynamicFooterItem : FollowDynamicItem() {
|
||||
|
||||
@ -28,8 +28,6 @@ import com.gh.gamecenter.forum.home.follow.FollowDynamicPersonalItem
|
||||
import com.gh.gamecenter.forum.home.follow.viewholder.FollowFooterViewHolder
|
||||
import com.gh.gamecenter.forum.home.follow.viewholder.FollowInvalidViewHolder
|
||||
import com.gh.gamecenter.forum.home.follow.viewmodel.FollowDynamicListViewModel
|
||||
import com.gh.gamecenter.forum.home.follow.viewmodel.FollowDynamicViewModel
|
||||
import com.gh.gamecenter.forum.search.CommunitySearchEventListener
|
||||
import com.gh.gamecenter.personalhome.PersonalItemViewHolder
|
||||
|
||||
class FollowDynamicAdapter(
|
||||
|
||||
@ -3,11 +3,8 @@ package com.gh.gamecenter.forum.home.follow.fragment
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.children
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
@ -16,23 +13,29 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.BaseFragment
|
||||
import com.gh.gamecenter.common.base.fragment.ToolbarFragment
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.FragmentFollowDynamicListBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.feature.entity.ForumVideoEntity
|
||||
import com.gh.gamecenter.forum.detail.ForumDetailActivity
|
||||
import com.gh.gamecenter.forum.home.follow.FollowActivityResultLauncher
|
||||
import com.gh.gamecenter.forum.home.follow.FollowDynamicBbsItem
|
||||
import com.gh.gamecenter.forum.home.follow.FollowDynamicItem
|
||||
import com.gh.gamecenter.forum.home.follow.FollowDynamicPersonalItem
|
||||
import com.gh.gamecenter.forum.home.follow.adapter.FollowDynamicAdapter
|
||||
import com.gh.gamecenter.forum.home.follow.viewmodel.FollowDynamicListViewModel
|
||||
import com.gh.gamecenter.forum.home.follow.viewmodel.FollowDynamicViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.gh.gamecenter.personalhome.home.UserHistoryAdapter.Companion.USER_HISTORY_PAYLOADS_VOTE_CHANGED
|
||||
import com.gh.gamecenter.qa.BbsType
|
||||
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
|
||||
import com.gh.gamecenter.qa.entity.QuestionsDetailEntity
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class FollowDynamicListFragment : BaseFragment<Unit>() {
|
||||
|
||||
@ -267,10 +270,99 @@ class FollowDynamicListFragment : BaseFragment<Unit>() {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
when (changed) {
|
||||
is EBImageArticleChanged.VoteChanged -> {
|
||||
updateImageArticleItem(changed.id, true) {
|
||||
it.id
|
||||
val newCount = it.count
|
||||
newCount.vote = changed.count
|
||||
it.count = newCount
|
||||
it.me.isCommunityArticleVote = changed.isVoted
|
||||
it.me.isVoted = changed.isVoted
|
||||
it.count = newCount
|
||||
}
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.CommentChanged -> {
|
||||
updateImageArticleItem(changed.id, true) {
|
||||
val newCount = it.count
|
||||
newCount.comment = changed.count
|
||||
it.count = newCount
|
||||
}
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataDeleted -> {
|
||||
viewModel.deleteImageArticle(changed.imageArticleId)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataChanged -> {
|
||||
val imageArticle = changed.data
|
||||
updateImageArticleItem(changed.data.id, false) {
|
||||
when (it) {
|
||||
is FollowDynamicPersonalItem -> {
|
||||
it.data.title = imageArticle.title
|
||||
it.data.brief = imageArticle.content
|
||||
it.data.images = imageArticle.images
|
||||
it.data.imagesInfo = imageArticle.imagesInfos
|
||||
it.data.community = imageArticle.community?.toCommunityEntity() ?: CommunityEntity()
|
||||
it.data.sections = imageArticle.sections
|
||||
it.count = imageArticle.count
|
||||
it.data.user = imageArticle.user
|
||||
it.data.time = imageArticle.time.update
|
||||
it.data.status = imageArticle.status
|
||||
}
|
||||
|
||||
is FollowDynamicBbsItem -> {
|
||||
it.data.title = imageArticle.title
|
||||
it.data.brief = imageArticle.content
|
||||
it.data.images = imageArticle.images
|
||||
it.data.imagesInfo = imageArticle.imagesInfos
|
||||
it.data.community = imageArticle.community?.toCommunityEntity() ?: CommunityEntity()
|
||||
it.data.sections = imageArticle.sections
|
||||
it.count = imageArticle.count
|
||||
it.data.user = imageArticle.user
|
||||
it.data.time = imageArticle.time.update
|
||||
it.data.status = imageArticle.status
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateImageArticleItem(
|
||||
id: String,
|
||||
hasPayload: Boolean,
|
||||
block: (FollowDynamicItem) -> Unit
|
||||
) {
|
||||
val dataList = adapter.currentList
|
||||
val position =
|
||||
dataList.indexOfFirst {
|
||||
it.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE && it.id == id
|
||||
}
|
||||
if (position != -1) {
|
||||
val item = dataList[position]
|
||||
block(item)
|
||||
if (hasPayload) {
|
||||
adapter.notifyItemChanged(position, USER_HISTORY_PAYLOADS_VOTE_CHANGED)
|
||||
} else {
|
||||
adapter.notifyItemChanged(position)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
context?.let {
|
||||
binding.vHeaderBackground.background = com.gh.gamecenter.common.R.drawable.background_shape_white_radius_8_top_only.toDrawable(it)
|
||||
binding.vHeaderBackground.background =
|
||||
com.gh.gamecenter.common.R.drawable.background_shape_white_radius_8_top_only.toDrawable(it)
|
||||
}
|
||||
binding.rvDynamic.tryToClearRecycler()
|
||||
binding.rvDynamic.recycledViewPool.clear()
|
||||
|
||||
@ -35,6 +35,7 @@ import com.gh.gamecenter.core.provider.IVisitManagerProvider
|
||||
import com.gh.gamecenter.core.utils.MD5Utils
|
||||
import com.gh.gamecenter.databinding.FragmentFollowHomeBinding
|
||||
import com.gh.gamecenter.entity.FollowUserEntity
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.eventbus.EBUserFollow
|
||||
import com.gh.gamecenter.feature.provider.IMessageDetailProvider
|
||||
import com.gh.gamecenter.forum.home.CommunityHomeFragment
|
||||
@ -69,6 +70,7 @@ class FollowHomeFragment : LazyFragment(), IScrollable {
|
||||
ownerProducer = { requireParentFragment() }
|
||||
)
|
||||
|
||||
|
||||
private lateinit var userViewModel: UserViewModel
|
||||
|
||||
private var userId: String? = null
|
||||
@ -454,6 +456,30 @@ class FollowHomeFragment : LazyFragment(), IScrollable {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
when (changed) {
|
||||
is EBImageArticleChanged.VoteChanged -> {
|
||||
viewModel.voteChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.CommentChanged ->{
|
||||
viewModel.commentChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataChanged -> {
|
||||
viewModel.itemChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataDeleted -> {
|
||||
viewModel.itemDeleted(changed)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mScrollCalculatorHelper?.currentPlayer?.release()
|
||||
|
||||
@ -7,6 +7,7 @@ import com.gh.gamecenter.core.utils.UrlFilterUtils
|
||||
import com.gh.gamecenter.entity.FollowCommonContentCollection
|
||||
import com.gh.gamecenter.entity.FollowDynamicEntity
|
||||
import com.gh.gamecenter.entity.FollowDynamicEntity.Companion.FOLLOW_UPDATE_TYPE_ARTICLE
|
||||
import com.gh.gamecenter.entity.FollowDynamicEntity.Companion.FOLLOW_UPDATE_TYPE_IMAGE_ARTICLE
|
||||
import com.gh.gamecenter.entity.FollowDynamicEntity.Companion.FOLLOW_UPDATE_TYPE_LIBAO
|
||||
import com.gh.gamecenter.entity.FollowDynamicEntity.Companion.FOLLOW_UPDATE_TYPE_LIBAO_EXCHANGE
|
||||
import com.gh.gamecenter.entity.FollowDynamicEntity.Companion.FOLLOW_UPDATE_TYPE_USER_POST
|
||||
|
||||
@ -2,12 +2,17 @@ package com.gh.gamecenter.forum.home.follow.viewholder
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.ArticleEntity
|
||||
import com.gh.gamecenter.forum.home.ForumArticleAskItemViewHolder
|
||||
import com.gh.gamecenter.forum.search.CommunitySearchEventListener
|
||||
@ -29,13 +34,13 @@ class FollowPostCardViewHolder(
|
||||
|
||||
fun bind(data: ArticleEntity, position: Int) {
|
||||
val articleEntity = data
|
||||
|
||||
viewHolder.binding.run {
|
||||
root.layoutParams = (root.layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
topMargin = if (position == 0) 8F.dip2px() else 0
|
||||
}
|
||||
if (position == 0) {
|
||||
root.background = com.gh.gamecenter.common.R.drawable.background_shape_white_radius_12_top_only.toDrawable(context)
|
||||
root.background =
|
||||
com.gh.gamecenter.common.R.drawable.background_shape_white_radius_12_top_only.toDrawable(context)
|
||||
} else {
|
||||
root.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(context))
|
||||
}
|
||||
@ -118,6 +123,15 @@ class FollowPostCardViewHolder(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, articleEntity.id)
|
||||
.appendQueryParameter(EntranceConsts.KEY_SOURCE_ENTRANCE, "社区-关注")
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package com.gh.gamecenter.forum.home.follow.viewmodel
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
@ -8,6 +7,7 @@ import com.gh.common.util.ErrorHelper
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.observableToMain
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity
|
||||
import com.gh.gamecenter.feature.entity.AnswerEntity
|
||||
import com.gh.gamecenter.forum.home.follow.FollowDynamicItem
|
||||
@ -119,5 +119,15 @@ class FollowDynamicListViewModel : ViewModel() {
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
fun deleteImageArticle(imageArticleId: String) {
|
||||
val oldData = dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val hasRemoved =
|
||||
newData.removeAll { it.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE && it.id == imageArticleId }
|
||||
if (hasRemoved) {
|
||||
_dataList.value = newData
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -8,6 +8,7 @@ import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.common.util.CheckLoginUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.retrofit.JSONObjectResponse
|
||||
@ -16,6 +17,8 @@ import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.observableToMain
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.entity.FollowUserEntity
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.eventbus.EBUserFollow
|
||||
import com.gh.gamecenter.feature.entity.*
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
@ -312,5 +315,71 @@ class FollowHomeViewModel(application: Application) : AndroidViewModel(applicati
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
fun voteChanged(changed: EBImageArticleChanged.VoteChanged) {
|
||||
notifyImageArticleItemChanged(changed.id) {
|
||||
FollowPostCardItem(
|
||||
data = it.copy(
|
||||
_me = it.me.copy(isCommunityArticleVote = changed.isVoted),
|
||||
_count = it.count.copy(vote = changed.count)
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun commentChanged(changed: EBImageArticleChanged.CommentChanged) {
|
||||
notifyImageArticleItemChanged(changed.id) {
|
||||
FollowPostCardItem(
|
||||
data = it.copy(
|
||||
_count = it.count.copy(comment = changed.count)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun itemChanged(changed: EBImageArticleChanged.DataChanged) {
|
||||
val imageArticle = changed.data
|
||||
notifyImageArticleItemChanged(imageArticle.id) { _ ->
|
||||
val newArticle = ArticleEntity(
|
||||
_id = imageArticle.id,
|
||||
_title = imageArticle.title,
|
||||
content = imageArticle.content,
|
||||
_count = imageArticle.count,
|
||||
time = imageArticle.time,
|
||||
_images = imageArticle.images,
|
||||
imagesInfo = imageArticle.imagesInfos,
|
||||
_user = imageArticle.user,
|
||||
_community = imageArticle.community?.toCommunityEntity() ?: CommunityEntity()
|
||||
)
|
||||
FollowPostCardItem(newArticle)
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyImageArticleItemChanged(
|
||||
imageArticleId: String,
|
||||
block: (ArticleEntity) -> FollowPostCardItem
|
||||
) {
|
||||
val oldData = dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val position = newData.indexOfFirst {
|
||||
it is FollowPostCardItem && it.data.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE && it.data.id == imageArticleId
|
||||
}
|
||||
if (position != -1) {
|
||||
val oldImageArticle = (newData[position] as FollowPostCardItem).data
|
||||
val newItem = block(oldImageArticle)
|
||||
newData[position] = newItem
|
||||
_dataList.value = newData
|
||||
}
|
||||
}
|
||||
|
||||
fun itemDeleted(changed: EBImageArticleChanged.DataDeleted) {
|
||||
val oldData = dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val position = newData.indexOfFirst {
|
||||
it is FollowPostCardItem && it.data.type == ImageArticleEntity.IMAGE_ARTICLE_TYPE && it.data.id == changed.imageArticleId
|
||||
}
|
||||
if (position != -1) {
|
||||
newData.removeAt(position)
|
||||
_dataList.value = newData
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package com.gh.gamecenter.forum.home.recommend
|
||||
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import com.alibaba.android.arouter.facade.annotation.Autowired
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.forum.home.recommend.fragment.ImageArticleDetailFragment
|
||||
|
||||
@Route(path = RouteConsts.activity.imageArticleDetailActivity)
|
||||
class ImageArticleDetailActivity : BaseActivity() {
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_IMAGE_ARTICLE_ID, desc = "图文 id", required = true)
|
||||
var imageArticleId = ""
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_TOP_COMMENT_ID, desc = "置顶评论 id", required = false)
|
||||
var topCommentId: String? = null
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_SCROLL_TO_COMMENT_AREA, desc = "是否需要自动滚动到评论区域", required = false)
|
||||
var scrollToCommentArea: Boolean = false
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_SOURCE_ENTRANCE, desc = "来源入口", required = false)
|
||||
var sourceEntrance: String = ""
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_RECOMMEND_ID, desc = "推荐 id", required = false)
|
||||
var recommendId: String = ""
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return com.gh.gamecenter.common.R.layout.activity_image_article_detail
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
ARouter.getInstance().inject(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
DisplayUtils.setLightStatusBar(this, true)
|
||||
setStatusBarColor(Color.TRANSPARENT)
|
||||
|
||||
val tag = ImageArticleDetailFragment::class.java.toString()
|
||||
val fragment =
|
||||
supportFragmentManager.findFragmentByTag(tag) ?: ImageArticleDetailFragment().apply {
|
||||
arguments = intent.extras
|
||||
}
|
||||
val transaction = supportFragmentManager.beginTransaction()
|
||||
transaction.replace(R.id.layout_activity_content, fragment, tag)
|
||||
transaction.commitAllowingStateLoss()
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -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,51 @@
|
||||
package com.gh.gamecenter.forum.home.recommend
|
||||
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.VoteEntity
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
class ImageArticleUseCase(
|
||||
private val repository: ImageArticleRepository,
|
||||
private val compositeDisposable: CompositeDisposable
|
||||
) {
|
||||
|
||||
fun voteImageArticle(imageArticleId: String, isVote: Boolean) {
|
||||
repository.voteImageArticle(imageArticleId, isVote)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<VoteEntity>() {
|
||||
override fun onSuccess(data: VoteEntity) {
|
||||
notifyVoteChanged(imageArticleId, isVote, data.vote)
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
|
||||
fun notifyVoteChanged(id: String, isVoted: Boolean, count: Int) {
|
||||
EventBus.getDefault().post(EBImageArticleChanged.VoteChanged(id, isVoted, count))
|
||||
}
|
||||
|
||||
fun notifyCommentChanged(id: String, count: Int) {
|
||||
EventBus.getDefault().post(EBImageArticleChanged.CommentChanged(id, count))
|
||||
}
|
||||
|
||||
fun notifyDataDeleted(id: String) {
|
||||
EventBus.getDefault().post(EBImageArticleChanged.DataDeleted(id))
|
||||
}
|
||||
|
||||
fun notifyDataCreated(data: ImageArticleEntity, draftId: String = "") {
|
||||
EventBus.getDefault().post(EBImageArticleChanged.DataCreated(data, draftId))
|
||||
}
|
||||
|
||||
fun notifyDataEdited(data: ImageArticleEntity) {
|
||||
EventBus.getDefault().post(EBImageArticleChanged.DataChanged(data))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,209 @@
|
||||
package com.gh.gamecenter.forum.home.recommend
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.activity.result.ActivityResultCallback
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.activity.viewModels
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.alibaba.android.arouter.facade.annotation.Autowired
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.utils.PermissionHelper
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.feature.selector.ChooseType
|
||||
import com.gh.gamecenter.feature.selector.LocalMediaActivity
|
||||
import com.gh.gamecenter.forum.home.CommunityHomeFragment.Companion.IMAGE_ARTICLE_REQUEST_CODE
|
||||
import com.gh.gamecenter.forum.home.recommend.fragment.ImageArticleDraftFragment
|
||||
import com.gh.gamecenter.forum.home.recommend.fragment.PublishImageArticleFragment
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.PublishImageArticleActivityViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.zhihu.matisse.Matisse
|
||||
|
||||
@Route(path = RouteConsts.activity.publishImageArticleActivity)
|
||||
class PublishImageArticleActivity : BaseActivity() {
|
||||
|
||||
private val viewModel by viewModels<PublishImageArticleActivityViewModel>()
|
||||
|
||||
private lateinit var chooseImageLauncher: ActivityResultLauncher<Int>
|
||||
|
||||
private var isFirstEnter = true
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_IMAGE_ARTICLE_ENTITY, desc = "编辑图文实体", required = false)
|
||||
var imageArticleEntity: ImageArticleEntity? = null
|
||||
|
||||
@JvmField
|
||||
@Autowired(name = EntranceConsts.KEY_COMMUNITY_DATA, desc = "绑定的社区实体", required = false)
|
||||
var communityEntity: CommunityEntity? = null
|
||||
|
||||
private lateinit var tvTitle: TextView
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return R.layout.activity_publish_image_article
|
||||
}
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
ARouter.getInstance().inject(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
DisplayUtils.setLightStatusBar(this, true)
|
||||
setStatusBarColor(Color.TRANSPARENT)
|
||||
|
||||
tvTitle = findViewById(R.id.tv_title)
|
||||
val ivBack = findViewById<ImageView>(R.id.iv_back)
|
||||
ivBack.setOnClickListener {
|
||||
val fragment = supportFragmentManager.fragments.lastOrNull()
|
||||
if(fragment is PublishImageArticleFragment){
|
||||
SensorsBridge.trackEvent("ArticleCancelclick")
|
||||
}
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
supportFragmentManager.addOnBackStackChangedListener {
|
||||
val fragment = supportFragmentManager.fragments.lastOrNull()
|
||||
val titleResId = if (fragment is ImageArticleDraftFragment) {
|
||||
R.string.image_article_draft
|
||||
} else {
|
||||
R.string.post_image_and_text
|
||||
}
|
||||
tvTitle.setText(titleResId)
|
||||
}
|
||||
|
||||
chooseImageLauncher = registerForActivityResult(object : ActivityResultContract<Int, Intent?>() {
|
||||
override fun createIntent(context: Context, input: Int): Intent {
|
||||
return LocalMediaActivity.getIntent(
|
||||
context,
|
||||
ChooseType.IMAGE,
|
||||
input,
|
||||
"图文动态"
|
||||
)
|
||||
}
|
||||
|
||||
override fun parseResult(resultCode: Int, intent: Intent?): Intent? {
|
||||
return intent
|
||||
}
|
||||
}, ActivityResultCallback<Intent?> {
|
||||
if (it != null) {
|
||||
val uris = Matisse.obtainResult(it)
|
||||
if (uris.isEmpty()) {
|
||||
if (isFirstEnter) {
|
||||
finish()
|
||||
}
|
||||
|
||||
} else {
|
||||
viewModel.addImages(uris)
|
||||
// 打开发布页
|
||||
if (isFirstEnter) {
|
||||
replaceFragment(true) {
|
||||
PublishImageArticleFragment.newInstance()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isFirstEnter) {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
if (imageArticleEntity == null) {
|
||||
// 新建图文,优先进入图库选择页
|
||||
replaceFragment(false, ::ImageArticleRequestPermissionFragment)
|
||||
PermissionHelper.checkStoragePermissionBeforeActionForResult(this) { grant ->
|
||||
if (grant) {
|
||||
chooseImage(9)
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 编辑图文草稿,不用弹出授权页,直接进入发布页
|
||||
replaceFragment(true) {
|
||||
PublishImageArticleFragment.newInstance()
|
||||
}
|
||||
}
|
||||
SensorsBridge.trackEvent(
|
||||
"ViewPostArticle",
|
||||
"source_entrance",
|
||||
mEntrance,
|
||||
"article_type",
|
||||
"图文",
|
||||
"bbs_type",
|
||||
imageArticleEntity?.community?.type ?: communityEntity?.type ?: "",
|
||||
"bbs_id",
|
||||
imageArticleEntity?.community?.id ?: communityEntity?.id ?: ""
|
||||
)
|
||||
|
||||
with(viewModel) {
|
||||
val lifecycleOwner = this@PublishImageArticleActivity
|
||||
chooseImageAction.observe(lifecycleOwner, EventObserver {
|
||||
isFirstEnter = false
|
||||
PermissionHelper.checkStoragePermissionBeforeActionForResult(this@PublishImageArticleActivity) { grant ->
|
||||
if (grant) {
|
||||
this@PublishImageArticleActivity.chooseImage(it)
|
||||
}
|
||||
}
|
||||
NewLogUtils.logChooseMedia(
|
||||
"view_media",
|
||||
"图文",
|
||||
"图片"
|
||||
)
|
||||
})
|
||||
|
||||
draftBoxDestination.observe(lifecycleOwner, EventObserver {
|
||||
replaceFragment(true) {
|
||||
ImageArticleDraftFragment.newInstance(true)
|
||||
}
|
||||
})
|
||||
|
||||
setEditImageArticle(imageArticleEntity)
|
||||
communityEntity?.let(::setCommunity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun chooseImage(limit: Int) {
|
||||
try {
|
||||
chooseImageLauncher.launch(limit)
|
||||
} catch (e: Exception) {
|
||||
toast(R.string.media_image_hint)
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified T : Fragment> replaceFragment(addBackStack: Boolean = true, creator: () -> T) {
|
||||
val tag = T::class.java.toString()
|
||||
val fragment = supportFragmentManager.findFragmentByTag(tag) ?: creator()
|
||||
val transaction = supportFragmentManager.beginTransaction()
|
||||
transaction.replace(R.id.layout_activity_content, fragment, tag)
|
||||
if (addBackStack) {
|
||||
transaction.addToBackStack(tag)
|
||||
}
|
||||
transaction.commitAllowingStateLoss()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun getIntent(context: Context, entrance: String): Intent {
|
||||
val intent = Intent(context, PublishImageArticleActivity::class.java)
|
||||
intent.putExtra(EntranceConsts.KEY_ENTRANCE, entrance)
|
||||
return intent
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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,193 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.DiffUtil.ItemCallback
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.RecyclerRecommendHomeBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.PersonalHistoryEntity
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleFooterWrapperAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDraftAdapter.Companion.DRAFT_RADIO_MAX
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDraftAdapter.Companion.DRAFT_RADIO_MIN
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.RecommendHomeAdapter.Companion.PAYLOADS_CHANGED_COVER
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.RecommendHomeAdapter.Companion.PAYLOADS_CHANGED_TITLE
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.RecommendHomeAdapter.Companion.PAYLOADS_CHANGED_VOTE
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.MyImageArticleListViewModel
|
||||
import com.lzf.easyfloat.utils.DisplayUtils
|
||||
|
||||
class MyImageArticleAdapter(
|
||||
private val context: Context,
|
||||
private val viewModel: MyImageArticleListViewModel
|
||||
) :
|
||||
ImageArticleFooterWrapperAdapter<PersonalHistoryEntity, MyImageArticleAdapter.MyImageArticleViewHolder>(
|
||||
createDiffCallback()
|
||||
) {
|
||||
|
||||
override fun onCreateDataViewHolder(parent: ViewGroup): MyImageArticleViewHolder {
|
||||
return MyImageArticleViewHolder(parent.toBinding(), object : MyImageArticleViewHolder.OnMyArticleImageListener {
|
||||
override fun navigateToImageArticleDetailPage(item: PersonalHistoryEntity, position: Int) {
|
||||
viewModel.navigateToImageArticleDetailPage(item.id)
|
||||
}
|
||||
|
||||
override fun voteImageArticle(id: String, vote: Boolean) {
|
||||
viewModel.useCase.voteImageArticle(id, vote)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
override fun onBindDataViewHolder(holder: MyImageArticleViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
holder.bind(item, position)
|
||||
|
||||
}
|
||||
|
||||
override fun onBindDataViewHolder(holder: MyImageArticleViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||
val item = getItem(position)
|
||||
holder.bind(item, position, payloads)
|
||||
}
|
||||
|
||||
override fun loadMore() {
|
||||
viewModel.loadMore()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun createDiffCallback() = object : ItemCallback<PersonalHistoryEntity>() {
|
||||
override fun areItemsTheSame(oldItem: PersonalHistoryEntity, newItem: PersonalHistoryEntity): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: PersonalHistoryEntity, newItem: PersonalHistoryEntity): Boolean {
|
||||
return oldItem.title == newItem.title
|
||||
&& oldItem.brief == newItem.brief
|
||||
&& oldItem.user.id == newItem.user.id
|
||||
&& oldItem.user.icon == newItem.user.icon
|
||||
&& oldItem.user.name == newItem.user.name
|
||||
&& oldItem.count.vote == newItem.count.vote
|
||||
&& oldItem.status == newItem.status
|
||||
}
|
||||
|
||||
override fun getChangePayload(oldItem: PersonalHistoryEntity, newItem: PersonalHistoryEntity): Any {
|
||||
val payloads = mutableListOf<String>()
|
||||
if (oldItem.images.firstOrNull() != newItem.images.firstOrNull()
|
||||
|| oldItem.imagesInfo.firstOrNull() != newItem.imagesInfo.firstOrNull()
|
||||
) {
|
||||
payloads.add(PAYLOADS_CHANGED_COVER)
|
||||
}
|
||||
|
||||
val oldTitle = oldItem.title.ifBlank { oldItem.content }
|
||||
val newTitle = newItem.title.ifBlank { newItem.content }
|
||||
if (oldTitle != newTitle) {
|
||||
payloads.add(PAYLOADS_CHANGED_TITLE)
|
||||
}
|
||||
|
||||
if (oldItem.me.isCommunityArticleVote != newItem.me.isCommunityArticleVote
|
||||
|| oldItem.count.vote != newItem.count.vote
|
||||
) {
|
||||
payloads.add(PAYLOADS_CHANGED_VOTE)
|
||||
}
|
||||
return payloads
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class MyImageArticleViewHolder(
|
||||
val binding: RecyclerRecommendHomeBinding,
|
||||
private val listener: OnMyArticleImageListener
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
private val itemWidth by lazy {
|
||||
(DisplayUtils.getScreenWidth(itemView.context) - 20F.dip2px()) / 2F
|
||||
}
|
||||
|
||||
fun bind(item: PersonalHistoryEntity, position: Int, payloads: List<Any?>? = null) {
|
||||
fun setCover() {
|
||||
val imageInfo = item.imagesInfo.firstOrNull()
|
||||
val imageRadio = ImageArticleEntity.getImageRadio(imageInfo, DRAFT_RADIO_MIN, DRAFT_RADIO_MAX)
|
||||
binding.ivCover.updateLayoutParams {
|
||||
height = (itemWidth * imageRadio).toInt()
|
||||
}
|
||||
binding.ivCover.display(item.images.firstOrNull())
|
||||
}
|
||||
|
||||
fun setTitle() {
|
||||
val title = item.title.ifBlank { item.content }
|
||||
binding.tvTitle.goneIf(title.isBlank()) {
|
||||
binding.tvTitle.text = title
|
||||
}
|
||||
}
|
||||
|
||||
fun setVote() {
|
||||
binding.voteState.setVote(item.me.isCommunityArticleVote, item.count.vote, item.status)
|
||||
}
|
||||
|
||||
with(binding) {
|
||||
if (payloads.isNullOrEmpty()) {
|
||||
ivIcon.displayGameIcon(item.user.icon, null)
|
||||
tvAuthorName.text = item.user.name
|
||||
|
||||
setTitle()
|
||||
|
||||
setCover()
|
||||
|
||||
setVote()
|
||||
|
||||
} else {
|
||||
payloads.filterIsInstance<List<String>>()
|
||||
.flatten()
|
||||
.forEach { change ->
|
||||
when (change) {
|
||||
PAYLOADS_CHANGED_COVER -> {
|
||||
setCover()
|
||||
}
|
||||
|
||||
PAYLOADS_CHANGED_TITLE -> {
|
||||
setTitle()
|
||||
}
|
||||
|
||||
PAYLOADS_CHANGED_VOTE -> {
|
||||
binding.voteState.setVote(
|
||||
item.me.isCommunityArticleVote,
|
||||
item.count.vote,
|
||||
item.status
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
root.setOnClickListener {
|
||||
listener.navigateToImageArticleDetailPage(item, position)
|
||||
}
|
||||
|
||||
setVote()
|
||||
voteState.setOnClickListener {
|
||||
val vote = !item.me.isCommunityArticleVote
|
||||
SensorsBridge.trackArticleLikeClick(
|
||||
customerType = item.user.auth?.text ?: "",
|
||||
articleId = item.id,
|
||||
bbsId = item.community.id,
|
||||
bbsType = item.community.typeChinese,
|
||||
activityTag = "",
|
||||
gameForumType = item.community.game?.categoryChinese ?: "",
|
||||
articleType = "图文",
|
||||
buttonName = if (item.me.isCommunityArticleVote) "取消点赞" else "赞同"
|
||||
)
|
||||
listener.voteImageArticle(item.id, vote)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnMyArticleImageListener {
|
||||
|
||||
fun navigateToImageArticleDetailPage(item: PersonalHistoryEntity, position: Int)
|
||||
|
||||
fun voteImageArticle(id: String, vote: Boolean)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,269 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.util.SparseArray
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.DiffUtil.ItemCallback
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.gh.common.exposure.IExposable
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.common.util.NewLogUtils.LOG_STORE_BBS
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.RecyclerRecommendHomeBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleFooterWrapperAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDraftAdapter.Companion.DRAFT_RADIO_MAX
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDraftAdapter.Companion.DRAFT_RADIO_MIN
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.ImageArticleHomeViewModel
|
||||
import com.lzf.easyfloat.utils.DisplayUtils
|
||||
|
||||
class RecommendHomeAdapter(
|
||||
private val context: Context,
|
||||
private val viewModel: ImageArticleHomeViewModel
|
||||
) :
|
||||
ImageArticleFooterWrapperAdapter<ImageArticleEntity, RecommendHomeAdapter.RecommendHomeViewHolder>(
|
||||
createDiffCallback()
|
||||
), IExposable {
|
||||
|
||||
private val viewHolderSet = mutableSetOf<RecommendHomeViewHolder>()
|
||||
private val exposureEventSparseArray: SparseArray<ExposureEvent> = SparseArray()
|
||||
|
||||
override fun onViewAttachedToWindow(holder: ViewHolder) {
|
||||
if (holder is RecommendHomeViewHolder) {
|
||||
viewHolderSet.add(holder)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onViewDetachedFromWindow(holder: ViewHolder) {
|
||||
viewHolderSet.remove(holder)
|
||||
}
|
||||
|
||||
override fun onCreateDataViewHolder(parent: ViewGroup): RecommendHomeViewHolder {
|
||||
return RecommendHomeViewHolder(parent.toBinding(), object : OnImageArticleListener {
|
||||
override fun navigateToImageArticleDetailPage(imageArticleEntity: ImageArticleEntity) {
|
||||
viewModel.navigateToImageArticleDetailPage(imageArticleEntity)
|
||||
}
|
||||
|
||||
override fun voteImageArticle(position: Int, item: ImageArticleEntity) {
|
||||
val vote = !item.me.isCommunityArticleVote
|
||||
SensorsBridge.trackArticleLikeClick(
|
||||
customerType = item.user.auth?.text ?: "",
|
||||
articleId = item.id,
|
||||
bbsId = item.community?.id ?: "",
|
||||
bbsType = item.community?.typeChinese ?: "综合论坛",
|
||||
activityTag = "",
|
||||
gameForumType = item.community?.game?.categoryChinese ?: "",
|
||||
articleType = "图文",
|
||||
buttonName = if (item.me.isCommunityArticleVote) "取消点赞" else "赞同"
|
||||
)
|
||||
|
||||
NewLogUtils.logRecommendFeedContentClick(
|
||||
"click_for_you_like",
|
||||
"图文",
|
||||
item.id,
|
||||
position + 1,
|
||||
item.community?.id ?: "",
|
||||
item.community?.typeChinese ?: "",
|
||||
item.user.id ?: ""
|
||||
)
|
||||
viewModel.useCase.voteImageArticle(item.id, vote)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
override fun onBindDataViewHolder(holder: RecommendHomeViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
val exposureEvent = ExposureEvent.createEvent(null, listOf())
|
||||
.apply {
|
||||
jsonExposure = NewLogUtils.getCommunityExposureJsonObject(
|
||||
item.id,
|
||||
item.community?.id ?: "",
|
||||
item.community?.typeChinese ?: "",
|
||||
position + 1,
|
||||
"社区推荐信息流"
|
||||
)
|
||||
logStore = LOG_STORE_BBS
|
||||
}
|
||||
exposureEventSparseArray.append(position, exposureEvent)
|
||||
holder.bind(item, position)
|
||||
}
|
||||
|
||||
override fun onBindDataViewHolder(holder: RecommendHomeViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||
holder.bind(getItem(position), position, payloads)
|
||||
}
|
||||
|
||||
override fun loadMore() {
|
||||
viewModel.loadMore()
|
||||
}
|
||||
|
||||
fun notifyItemChanged(result: ImageArticleEntity) {
|
||||
val position = currentList.indexOfFirst { it.id == result.id }
|
||||
if (position != -1) {
|
||||
val newData = currentList.toMutableList()
|
||||
newData[position] = result
|
||||
submitList(newData)
|
||||
}
|
||||
}
|
||||
|
||||
fun onDarkModeChanged() {
|
||||
viewHolderSet.forEach {
|
||||
it.binding.root.setCardBackgroundColor(
|
||||
com.gh.gamecenter.common.R.color.ui_surface.toColor(
|
||||
it.itemView.context
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getEventByPosition(pos: Int): ExposureEvent? {
|
||||
val event = exposureEventSparseArray.get(pos)
|
||||
return event
|
||||
}
|
||||
|
||||
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? = null
|
||||
|
||||
companion object {
|
||||
|
||||
const val PAYLOADS_CHANGED_COVER = "payloads_changed_cover"
|
||||
const val PAYLOADS_CHANGED_TITLE = "payloads_changed_title"
|
||||
const val PAYLOADS_CHANGED_VOTE = "payloads_changed_vote"
|
||||
const val PAYLOADS_CHANGED_DARK_MODE = "payloads_changed_dark_mode"
|
||||
|
||||
fun createDiffCallback() = object : ItemCallback<ImageArticleEntity>() {
|
||||
override fun areItemsTheSame(oldItem: ImageArticleEntity, newItem: ImageArticleEntity): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: ImageArticleEntity, newItem: ImageArticleEntity): Boolean {
|
||||
return oldItem.title == newItem.title
|
||||
&& oldItem.content == newItem.content
|
||||
&& oldItem.user.id == newItem.user.id
|
||||
&& oldItem.user.icon == newItem.user.icon
|
||||
&& oldItem.user.name == newItem.user.name
|
||||
&& oldItem.count.vote == newItem.count.vote
|
||||
|
||||
}
|
||||
|
||||
override fun getChangePayload(oldItem: ImageArticleEntity, newItem: ImageArticleEntity): Any? {
|
||||
val payloads = mutableListOf<String>()
|
||||
if (oldItem.images.firstOrNull() != newItem.images.firstOrNull()
|
||||
|| oldItem.imagesInfos.firstOrNull() != newItem.imagesInfos.firstOrNull()
|
||||
) {
|
||||
payloads.add(PAYLOADS_CHANGED_COVER)
|
||||
}
|
||||
|
||||
val oldTitle = oldItem.title.ifBlank { oldItem.content }
|
||||
val newTitle = newItem.title.ifBlank { newItem.content }
|
||||
if (oldTitle != newTitle) {
|
||||
payloads.add(PAYLOADS_CHANGED_TITLE)
|
||||
}
|
||||
|
||||
if (oldItem.me.isCommunityArticleVote != newItem.me.isCommunityArticleVote
|
||||
|| oldItem.count.vote != newItem.count.vote
|
||||
) {
|
||||
payloads.add(PAYLOADS_CHANGED_VOTE)
|
||||
}
|
||||
return payloads
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class RecommendHomeViewHolder(
|
||||
val binding: RecyclerRecommendHomeBinding,
|
||||
private val listener: OnImageArticleListener
|
||||
) : ViewHolder(binding.root) {
|
||||
|
||||
private val itemWidth by lazy {
|
||||
(DisplayUtils.getScreenWidth(itemView.context) - 20F.dip2px()) / 2F
|
||||
}
|
||||
|
||||
fun bind(item: ImageArticleEntity, position: Int, payloads: MutableList<Any> = mutableListOf()) {
|
||||
fun setCover() {
|
||||
val imageInfo = item.imagesInfos.firstOrNull()
|
||||
val imageRadio = ImageArticleEntity.getImageRadio(imageInfo, DRAFT_RADIO_MIN, DRAFT_RADIO_MAX)
|
||||
binding.ivCover.updateLayoutParams {
|
||||
height = (itemWidth * imageRadio).toInt()
|
||||
}
|
||||
binding.ivCover.display(item.images.firstOrNull())
|
||||
}
|
||||
|
||||
fun setTitle() {
|
||||
val title = item.title.ifBlank { item.content }
|
||||
binding.tvTitle.goneIf(title.isBlank()) {
|
||||
binding.tvTitle.text = title
|
||||
}
|
||||
}
|
||||
|
||||
fun setVote() {
|
||||
binding.voteState.setVote(item.me.isCommunityArticleVote, item.count.vote, item.status)
|
||||
}
|
||||
|
||||
binding.root.setCardBackgroundColor(
|
||||
com.gh.gamecenter.common.R.color.ui_surface.toColor(
|
||||
itemView.context
|
||||
)
|
||||
)
|
||||
with(binding) {
|
||||
if (payloads.isEmpty()) {
|
||||
ivIcon.displayGameIcon(item.user.icon, null)
|
||||
tvAuthorName.text = item.user.name
|
||||
|
||||
setTitle()
|
||||
|
||||
setCover()
|
||||
|
||||
setVote()
|
||||
|
||||
} else {
|
||||
payloads.filterIsInstance<List<String>>()
|
||||
.flatten()
|
||||
.forEach { change ->
|
||||
when (change) {
|
||||
PAYLOADS_CHANGED_COVER -> {
|
||||
setCover()
|
||||
}
|
||||
|
||||
PAYLOADS_CHANGED_TITLE -> {
|
||||
setTitle()
|
||||
}
|
||||
|
||||
PAYLOADS_CHANGED_VOTE -> {
|
||||
setVote()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
root.setOnClickListener {
|
||||
NewLogUtils.logRecommendFeedContentClick(
|
||||
"click_for_you_content",
|
||||
"图文",
|
||||
item.id,
|
||||
position + 1,
|
||||
item.community?.id ?: "",
|
||||
item.community?.typeChinese ?: "",
|
||||
item.user.id ?: ""
|
||||
)
|
||||
listener.navigateToImageArticleDetailPage(item)
|
||||
}
|
||||
voteState.setOnClickListener {
|
||||
listener.voteImageArticle(position, item)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface OnImageArticleListener {
|
||||
|
||||
fun navigateToImageArticleDetailPage(imageArticleEntity: ImageArticleEntity)
|
||||
|
||||
fun voteImageArticle(position: Int, item: ImageArticleEntity)
|
||||
}
|
||||
}
|
||||
@ -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.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.baselist.ListAdapter
|
||||
import com.gh.gamecenter.common.baselist.ListFragment
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.viewModelProvider
|
||||
import com.gh.gamecenter.common.view.CustomDividerItemDecoration
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDetailCommentAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.ImageArticleCommentViewModel
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.ImageArticleDetailViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.gh.gamecenter.qa.article.detail.CommentItemData
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentAdapter
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
class ImageArticleCommentFragment : ListFragment<CommentItemData, ImageArticleCommentViewModel>() {
|
||||
|
||||
var imageArticleId = ""
|
||||
|
||||
var topCommentId: String? = ""
|
||||
|
||||
private val parentViewModel by viewModels<ImageArticleDetailViewModel>(ownerProducer = { parentFragment ?: this })
|
||||
|
||||
private val adapter by lazy {
|
||||
ImageArticleDetailCommentAdapter(
|
||||
requireContext(),
|
||||
mListViewModel,
|
||||
BaseCommentAdapter.AdapterType.COMMENT,
|
||||
mEntrance
|
||||
)
|
||||
}
|
||||
|
||||
override fun provideListAdapter(): ListAdapter<*> = adapter
|
||||
|
||||
override fun provideListViewModel(): ImageArticleCommentViewModel {
|
||||
return viewModelProvider(
|
||||
ImageArticleCommentViewModel.Factory(
|
||||
HaloApp.getInstance().application,
|
||||
imageArticleId,
|
||||
topCommentId ?: ""
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getItemDecoration(): RecyclerView.ItemDecoration {
|
||||
|
||||
val drawable = ContextCompat.getDrawable(requireContext(), R.drawable.divider_article_detail_comment)
|
||||
val itemDecoration = CustomDividerItemDecoration(
|
||||
requireContext(),
|
||||
notDecorateTheFirstItem = true,
|
||||
notDecorateTheLastItem = true
|
||||
)
|
||||
|
||||
itemDecoration.setDrawable(drawable!!)
|
||||
mItemDecoration = itemDecoration
|
||||
return itemDecoration
|
||||
}
|
||||
|
||||
override fun addSyncPageObserver() = true
|
||||
|
||||
override fun provideSyncAdapter() = adapter
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return R.layout.fragment_list_article_detail_comment
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
ARouter.getInstance().inject(this)
|
||||
arguments?.let {
|
||||
imageArticleId = it.getString(EntranceConsts.KEY_IMAGE_ARTICLE_ID) ?: ""
|
||||
topCommentId = it.getString(EntranceConsts.KEY_TOP_COMMENT_ID) ?: ""
|
||||
}
|
||||
super.onCreate(savedInstanceState)
|
||||
with(parentViewModel) {
|
||||
sortType.observe(this@ImageArticleCommentFragment, EventObserver {
|
||||
mListViewModel.changeSort(it)
|
||||
})
|
||||
|
||||
insertNewestCommentAction.observe(this@ImageArticleCommentFragment, EventObserver {
|
||||
mListViewModel.insertNewestComment(it)
|
||||
})
|
||||
|
||||
commentCount.observe(this@ImageArticleCommentFragment) {
|
||||
mListViewModel.commentCount = it
|
||||
}
|
||||
|
||||
imageArticleDetailEntity.observe(this@ImageArticleCommentFragment) {
|
||||
mListViewModel.topItemData = CommentItemData(imageArticleDetail = it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mListRefresh?.isEnabled = false
|
||||
|
||||
with(mListViewModel) {
|
||||
updateCommentCountAction.observe(viewLifecycleOwner, EventObserver {
|
||||
parentViewModel.updateComment("", commentCount)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLoadError() {
|
||||
super.onLoadError()
|
||||
mListRv.goneIf(false)
|
||||
}
|
||||
|
||||
override fun onLoadNotFound() {
|
||||
super.onLoadNotFound()
|
||||
mListRv.goneIf(false)
|
||||
}
|
||||
|
||||
override fun onLoadEmpty() {
|
||||
super.onLoadEmpty()
|
||||
mListRv.goneIf(false)
|
||||
}
|
||||
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
if (mListRv != null) {
|
||||
mListRv.removeItemDecoration(mItemDecoration)
|
||||
mListRv.addItemDecoration(itemDecoration)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,938 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.Path
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.widget.TextViewCompat
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.common.browse.ValueBrowseTimer
|
||||
import com.gh.common.browse.asObserver
|
||||
import com.gh.common.browse.withLifecycle
|
||||
import com.gh.common.databind.BindingAdapters
|
||||
import com.gh.common.util.BbsReportHelper
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.DownloadItemUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.common.util.NewsUtils
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.GameDetailActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
|
||||
import com.gh.gamecenter.common.base.fragment.BaseFragment
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.entity.AdditionalParamsEntity
|
||||
import com.gh.gamecenter.common.entity.NormalShareEntity
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.databinding.FragmentImageArticleDetailBinding
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.MenuItemEntity
|
||||
import com.gh.gamecenter.eventbus.EBDownloadStatus
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.ImageInfo
|
||||
import com.gh.gamecenter.feature.entity.Permissions
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDetailBannerAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.ImageArticleDetailViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.qa.comment.CommentActivity
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
|
||||
import com.gh.gamecenter.qa.dialog.MoreFunctionPanelDialog
|
||||
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
|
||||
import com.lightgame.download.DataWatcher
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class ImageArticleDetailFragment : BaseFragment<Unit>() {
|
||||
|
||||
private val viewModel by viewModels<ImageArticleDetailViewModel>()
|
||||
|
||||
private var imageArticleId = ""
|
||||
|
||||
private var topCommentId: String? = null
|
||||
|
||||
var scrollToCommentArea: Boolean = false
|
||||
|
||||
private var recommendId: String = ""
|
||||
|
||||
private var showIndicator = false
|
||||
|
||||
private var sourceEntrance = ""
|
||||
|
||||
private val binding: FragmentImageArticleDetailBinding by lazy {
|
||||
FragmentImageArticleDetailBinding.inflate(layoutInflater)
|
||||
}
|
||||
|
||||
private val adapter by lazy {
|
||||
ImageArticleDetailBannerAdapter()
|
||||
}
|
||||
|
||||
private val handler = object : Handler(Looper.getMainLooper()) {
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
if (msg.what == HIDE_BANNER_NUMBER_INDICATOR) {
|
||||
binding.llNumberIndicator.goneIf(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val dataWatcher = object : DataWatcher() {
|
||||
override fun onDataChanged(downloadEntity: DownloadEntity) {
|
||||
setDownloadButton(viewModel.imageArticleDetailEntity.value?.community?.game)
|
||||
}
|
||||
|
||||
override fun onDataInit(downloadEntity: DownloadEntity) {
|
||||
onDataChanged(downloadEntity)
|
||||
}
|
||||
}
|
||||
|
||||
private val browseTimer = ValueBrowseTimer<ImageArticleEntity>()
|
||||
.withLifecycle(this)
|
||||
.withStart {
|
||||
SensorsBridge.trackArticleDetailsBrowsing(
|
||||
bbsId = it?.community?.id ?: "",
|
||||
bbsType = it?.community?.typeChinese ?: "",
|
||||
customerType = it?.user?.auth?.text ?: "",
|
||||
gameForumType = it?.community?.game?.categoryChinese ?: "",
|
||||
activityTag = "",
|
||||
articleType = "图文",
|
||||
sourceEntrance = sourceEntrance,
|
||||
articleId = it?.id ?: ""
|
||||
)
|
||||
}
|
||||
.withResult { detail, time ->
|
||||
SensorsBridge.trackArticleBrowsingDuration(
|
||||
bbsId = detail?.community?.id ?: "",
|
||||
bbsType = detail?.community?.typeChinese ?: "",
|
||||
customerType = detail?.user?.auth?.text ?: "",
|
||||
gameForumType = detail?.community?.game?.categoryChinese ?: "",
|
||||
activityTag = "",
|
||||
articleId = detail?.id ?: "",
|
||||
articleType = "图文",
|
||||
stayLength = time / 1000.0,
|
||||
sourceEntrance = sourceEntrance
|
||||
)
|
||||
|
||||
NewLogUtils.logJumpNoteDetail(
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: "",
|
||||
stayTime = time / 1000
|
||||
)
|
||||
}
|
||||
|
||||
override fun getInflatedLayout() = binding.root
|
||||
|
||||
override fun getLayoutId() = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
arguments?.let {
|
||||
imageArticleId = it.getString(EntranceConsts.KEY_IMAGE_ARTICLE_ID) ?: ""
|
||||
topCommentId = it.getString(EntranceConsts.KEY_TOP_COMMENT_ID) ?: ""
|
||||
scrollToCommentArea = it.getBoolean(EntranceConsts.KEY_SCROLL_TO_COMMENT_AREA)
|
||||
sourceEntrance = it.getString(EntranceConsts.KEY_SOURCE_ENTRANCE) ?: ""
|
||||
recommendId = it.getString(EntranceConsts.KEY_RECOMMEND_ID) ?: ""
|
||||
}
|
||||
super.onCreate(savedInstanceState)
|
||||
viewModel.imageArticleDetailEntity.observe(this, browseTimer.asObserver())
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val tag = ImageArticleDetailFragment::class.java.name
|
||||
val fragment =
|
||||
childFragmentManager.findFragmentByTag(tag) ?: ImageArticleCommentFragment()
|
||||
fragment.arguments = arguments
|
||||
childFragmentManager.beginTransaction()
|
||||
.replace(R.id.fcv_comment_container, fragment, tag)
|
||||
.commitNowAllowingStateLoss()
|
||||
|
||||
with(viewModel) {
|
||||
|
||||
pageStatus.observe(viewLifecycleOwner) {
|
||||
binding.reuseNoConnection.root.goneIf(it != LoadStatus.INIT_FAILED)
|
||||
binding.clContent.goneIf(it != LoadStatus.INIT_LOADED)
|
||||
binding.inputContainer.root.goneIf(it != LoadStatus.INIT_LOADED)
|
||||
binding.layoutLoading.root.goneIf(it != LoadStatus.INIT_LOADING)
|
||||
binding.reuseNoneData.root.goneIf(it != LoadStatus.INIT_EMPTY)
|
||||
if (it == LoadStatus.INIT_EMPTY) {
|
||||
toast(com.gh.gamecenter.common.R.string.content_delete_toast)
|
||||
}
|
||||
}
|
||||
|
||||
imageArticleDetailEntity.observe(viewLifecycleOwner) {
|
||||
NewLogUtils.logViewNoteDetail(
|
||||
it.id,
|
||||
it.community?.id ?: "",
|
||||
it.community?.typeChinese ?: "",
|
||||
it.user.id ?: ""
|
||||
)
|
||||
fillUi(it)
|
||||
}
|
||||
|
||||
isUserFollowed.observe(viewLifecycleOwner) {
|
||||
binding.ctvFollow.isChecked = it
|
||||
binding.ctvFollow.setText(
|
||||
if (it) {
|
||||
R.string.concerned
|
||||
} else {
|
||||
R.string.follow
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
commentCount.observe(viewLifecycleOwner) {
|
||||
binding.inputContainer.bottomCommentTv.text = if (it == 0) {
|
||||
R.string.comment.toResString()
|
||||
} else {
|
||||
"$it"
|
||||
}
|
||||
binding.tvCommentCount.text = "$it"
|
||||
}
|
||||
|
||||
vote.observe(viewLifecycleOwner) {
|
||||
val (isVoted, count) = it
|
||||
val (imageDrawableResId, textColorResId) = if (isVoted) {
|
||||
R.drawable.ic_article_detail_liked_bottom_bar to com.gh.gamecenter.common.R.color.text_theme
|
||||
} else {
|
||||
R.drawable.ic_article_detail_like_bottom_bar to com.gh.gamecenter.common.R.color.text_secondary
|
||||
}
|
||||
binding.inputContainer.bottomLikeIv.setImageResource(imageDrawableResId)
|
||||
binding.inputContainer.bottomLikeTv.setTextColor(textColorResId.toColor(requireContext()))
|
||||
binding.inputContainer.bottomLikeTv.text = if (count == 0) {
|
||||
R.string.agree.toResString()
|
||||
} else {
|
||||
"$count"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
isBbsFollowed.observe(viewLifecycleOwner) {
|
||||
binding.ctvFollowBbs.isChecked = it
|
||||
binding.ctvFollowBbs.setText(
|
||||
if (it) {
|
||||
R.string.concerned
|
||||
} else {
|
||||
R.string.follow
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
isFavorite.observe(viewLifecycleOwner) {
|
||||
val (drawableResId, textColorResId) = if (it) {
|
||||
R.drawable.ic_article_detail_stared_bottom_bar to com.gh.gamecenter.common.R.color.text_theme
|
||||
} else {
|
||||
R.drawable.ic_article_detail_star_bottom_bar to com.gh.gamecenter.common.R.color.text_secondary
|
||||
}
|
||||
binding.inputContainer.bottomStarIv.setImageResource(drawableResId)
|
||||
binding.inputContainer.bottomStarTv.setTextColor(textColorResId.toColor(requireContext()))
|
||||
binding.inputContainer.bottomStarTv.setText(
|
||||
if (it) {
|
||||
R.string.already_saved
|
||||
} else {
|
||||
R.string.menu_collect
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
applyHighlightAction.observe(viewLifecycleOwner, EventObserver {
|
||||
val toastResId = if (it) {
|
||||
R.string.apply_successfully
|
||||
} else {
|
||||
R.string.apply_failure
|
||||
}
|
||||
ToastUtils.showToast(toastResId.toResString())
|
||||
})
|
||||
|
||||
addHighlightAction.observe(viewLifecycleOwner, EventObserver {
|
||||
ToastUtils.showToast(it.toResString())
|
||||
})
|
||||
|
||||
deleteOrHideImageArticleSuccessfully.observe(viewLifecycleOwner, EventObserver {
|
||||
val (isSuccess, toastResId) = it
|
||||
ToastUtils.showToast(toastResId.toResString())
|
||||
if (isSuccess) {
|
||||
EventBus.getDefault().post(EBImageArticleChanged.DataDeleted(imageArticleId))
|
||||
requireActivity().finish()
|
||||
}
|
||||
})
|
||||
|
||||
loadImageArticleDetail(this@ImageArticleDetailFragment.imageArticleId, recommendId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun initView(view: View?) {
|
||||
super.initView(view)
|
||||
binding.vpBanner.adapter = adapter
|
||||
binding.vpBanner.offscreenPageLimit = 2
|
||||
|
||||
binding.vMore.setOnClickListener {
|
||||
showMoreItemDialog()
|
||||
}
|
||||
binding.sfvOrder.setItemList(
|
||||
listOf(R.string.positive_older.toResString(), R.string.reverse_order.toResString()), 0
|
||||
)
|
||||
|
||||
binding.inputContainer.replyTv.setText(R.string.message_detail_comment_hint2)
|
||||
binding.inputContainer.replyTv.setRoundedColorBackground(com.gh.gamecenter.common.R.color.ui_container_2, 19F)
|
||||
binding.inputContainer.replyTv.setDebouncedClickListener {
|
||||
NewLogUtils.logCommentClick(
|
||||
"click_comment_area_comment_input_box",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
viewModel.imageArticleDetailEntity.value?.id
|
||||
?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
clickToastByStatus(viewModel.imageArticleDetailEntity.value?.status ?: "") {
|
||||
val imageArticle = viewModel.imageArticleDetailEntity.value ?: return@clickToastByStatus
|
||||
val intent = CommentActivity.getImageArticleCommentIntent(
|
||||
requireContext(),
|
||||
imageArticle.id,
|
||||
imageArticle.communityId,
|
||||
viewModel.commentCount.value
|
||||
)
|
||||
startActivityForResult(intent, CommentActivity.REQUEST_CODE)
|
||||
}
|
||||
}
|
||||
binding.inputContainer.bottomCommentIv.setOnClickListener {
|
||||
binding.appBar.setExpanded(false, true)
|
||||
NewLogUtils.logCommentAreaEnter("图文")
|
||||
}
|
||||
binding.inputContainer.bottomCommentTv.setOnClickListener { binding.inputContainer.bottomCommentIv.performClick() }
|
||||
|
||||
binding.inputContainer.bottomStarIv.setOnClickListener {
|
||||
requireContext().ifLogin(entrance = "帖子详情-收藏") {
|
||||
clickToastByStatus(viewModel.imageArticleDetailEntity.value?.status ?: "") {
|
||||
viewModel.collect()
|
||||
}
|
||||
NewLogUtils.logCommentClick(
|
||||
"click_comment_area_collect",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
binding.inputContainer.bottomStarTv.setOnClickListener { binding.inputContainer.bottomStarIv.performClick() }
|
||||
|
||||
binding.inputContainer.bottomLikeIv.setOnClickListener {
|
||||
requireContext().ifLogin("帖子详情-赞同") {
|
||||
clickToastByStatus(viewModel.imageArticleDetailEntity.value?.status ?: "") {
|
||||
viewModel.vote()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.inputContainer.bottomLikeTv.setOnClickListener { binding.inputContainer.bottomLikeIv.performClick() }
|
||||
|
||||
binding.sfvOrder.setOnCheckedCallback {
|
||||
val newSort = if (it == 0) {
|
||||
BaseCommentViewModel.SortType.OLDEST
|
||||
} else {
|
||||
BaseCommentViewModel.SortType.LATEST
|
||||
}
|
||||
viewModel.changeSort(newSort)
|
||||
}
|
||||
binding.ctvFollow.setOnClickListener {
|
||||
ifLogin("图文详情-关注") {
|
||||
viewModel.followUser()
|
||||
}
|
||||
NewLogUtils.logClickNoteDetailFollow(
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
!(viewModel.isUserFollowed.value ?: false)
|
||||
)
|
||||
}
|
||||
binding.vBack.setOnClickListener {
|
||||
activity?.finish()
|
||||
}
|
||||
binding.ivAvatar.setOnClickListener {
|
||||
DirectUtils.directToHomeActivity(
|
||||
requireContext(),
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id,
|
||||
1,
|
||||
mEntrance,
|
||||
"图文详情"
|
||||
)
|
||||
NewLogUtils.logClickNoteDetailProfilePhoto(
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
binding.tvName.setOnClickListener {
|
||||
DirectUtils.directToHomeActivity(
|
||||
requireContext(),
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id,
|
||||
1,
|
||||
mEntrance,
|
||||
"图文详情"
|
||||
)
|
||||
NewLogUtils.logClickNoteDetailNickname(
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
binding.vpBanner.registerOnPageChangeCallback(object : OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
showNumberIndicator(position)
|
||||
}
|
||||
})
|
||||
|
||||
binding.reuseNoConnection.connectionReloadTv.setOnClickListener {
|
||||
viewModel.loadImageArticleDetail(imageArticleId, recommendId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fillUi(imageArticle: ImageArticleEntity) {
|
||||
binding.tvTitle.goneIf(imageArticle.title.isBlank()) {
|
||||
binding.tvTitle.text = imageArticle.title
|
||||
}
|
||||
binding.tvContent.goneIf(imageArticle.content.isBlank()) {
|
||||
binding.tvContent.text = imageArticle.content
|
||||
}
|
||||
|
||||
binding.ivAvatar.display(imageArticle.user.border, imageArticle.user.icon, imageArticle.user.auth?.icon)
|
||||
binding.tvName.text = imageArticle.user.name
|
||||
if (imageArticle.user.auth == null) {
|
||||
binding.tvAuth.goneIf(true)
|
||||
TextViewCompat.setTextAppearance(binding.tvName, com.gh.gamecenter.common.R.style.TextHeadline)
|
||||
} else {
|
||||
binding.tvAuth.goneIf(false)
|
||||
binding.tvAuth.text = imageArticle.user.auth?.text
|
||||
TextViewCompat.setTextAppearance(binding.tvName, com.gh.gamecenter.common.R.style.TextBody2)
|
||||
}
|
||||
|
||||
binding.ctvFollow.goneIf(imageArticle.me.isContentOwner)
|
||||
binding.tvTime.text = NewsUtils.getFormattedTime(imageArticle.time.edit)
|
||||
|
||||
val imagesSize = imageArticle.images.size
|
||||
showIndicator = imagesSize >= SHOW_DOT_INDICATOR_MIN
|
||||
binding.dorIndicator.goneIf(!showIndicator) {
|
||||
binding.dorIndicator.show(imagesSize)
|
||||
}
|
||||
binding.llNumberIndicator.goneIf(!showIndicator) {
|
||||
binding.tvIndicatorTotal.text = "/${imagesSize}"
|
||||
showNumberIndicator(0)
|
||||
}
|
||||
|
||||
|
||||
setBannerSize(imageArticle.imagesInfos.firstOrNull())
|
||||
adapter.submitList(imageArticle.images)
|
||||
|
||||
val community = imageArticle.community
|
||||
val game = community?.game
|
||||
when {
|
||||
game != null -> {
|
||||
// 显示游戏
|
||||
showGame(game, imageArticle.community.id)
|
||||
}
|
||||
|
||||
community != null -> {
|
||||
showCommunity(community)
|
||||
}
|
||||
|
||||
else -> {
|
||||
binding.clBbsContainer.goneIf(true)
|
||||
binding.clGameContainer.goneIf(true)
|
||||
}
|
||||
}
|
||||
|
||||
if (scrollToCommentArea) {
|
||||
scrollToCommentArea = false
|
||||
binding.appBar.setExpanded(false, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showCommunity(community: ImageArticleEntity.Community) {
|
||||
binding.clBbsContainer.goneIf(false)
|
||||
binding.clGameContainer.goneIf(true)
|
||||
binding.ivBbsIcon.display(community.icon)
|
||||
binding.tvBbsName.text = community.name
|
||||
binding.tvHeat.text = "${community.hot}"
|
||||
binding.clBbsContainer.setOnClickListener {
|
||||
DirectUtils.directForumDetail(requireContext(), community.id, "帖子详情")
|
||||
NewLogUtils.logClickNoteDetailForum(community.id, community.typeChinese)
|
||||
}
|
||||
binding.ctvFollowBbs.setOnClickListener {
|
||||
SensorsBridge.trackFollowForumClick(
|
||||
bbsId = community.id,
|
||||
forumName = community.name,
|
||||
bbsType = community.typeChinese,
|
||||
buttonName = binding.ctvFollowBbs.text.toString(),
|
||||
gameForumType = community.game?.categoryChinese ?: ""
|
||||
)
|
||||
viewModel.followBbs(community.id)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showGame(game: GameEntity, communityId: String) {
|
||||
game.exposureEvent = ExposureEvent.createEventWithSourceConcat(
|
||||
game,
|
||||
listOf(),
|
||||
listOf(ExposureSource("其他"), ExposureSource("图文详情"))
|
||||
)
|
||||
binding.clBbsContainer.goneIf(true)
|
||||
binding.clGameContainer.goneIf(false)
|
||||
binding.ivGameIcon.displayGameIcon(game)
|
||||
binding.tvGameName.text = game.name
|
||||
binding.tvGameRating.goneIf(!(game.commentCount > 3 && game.star >= 7)) {
|
||||
binding.tvGameRating.text = game.star.toString()
|
||||
}
|
||||
BindingAdapters.setGameTags(binding.gtcvGameTags, game)
|
||||
|
||||
setDownloadButton(game)
|
||||
binding.clGameContainer.setOnClickListener {
|
||||
GameDetailActivity.startGameDetailActivity(
|
||||
requireContext(),
|
||||
game,
|
||||
"图文详情",
|
||||
traceEvent = game.exposureEvent
|
||||
)
|
||||
}
|
||||
|
||||
binding.tvGoBbs.setOnClickListener {
|
||||
DirectUtils.directForumDetail(requireContext(), communityId, "帖子详情")
|
||||
}
|
||||
}
|
||||
|
||||
private fun setDownloadButton(gameEntity: GameEntity?) {
|
||||
if (gameEntity == null) return
|
||||
DownloadItemUtils.setOnClickListener(
|
||||
requireContext(), binding.btnDownload,
|
||||
gameEntity, 0, null,
|
||||
mEntrance,
|
||||
location = "视频详情",
|
||||
traceEvent = gameEntity.exposureEvent,
|
||||
clickCallback = {
|
||||
|
||||
},
|
||||
refreshCallback = { setDownloadButton(gameEntity) },
|
||||
allStateClickCallback = null
|
||||
)
|
||||
DownloadItemUtils.updateItem(
|
||||
requireContext(),
|
||||
gameEntity,
|
||||
GameViewHolder(binding.clGameContainer).apply {
|
||||
gameDownloadBtn = binding.btnDownload
|
||||
gameDownloadTips = binding.downloadTipsLottie
|
||||
multiVersionDownloadTv = binding.multiVersionDownloadTv
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun setBannerSize(imageInfo: ImageInfo?) {
|
||||
binding.vpBanner.goneIf(imageInfo == null) {
|
||||
val bannerRadio = ImageArticleEntity.getImageRadio(imageInfo, BANNER_RADIO_MIN, BANNER_RADIO_MAX)
|
||||
binding.vpBanner.updateLayoutParams {
|
||||
height = (resources.displayMetrics.widthPixels * bannerRadio).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun showNumberIndicator(position: Int) {
|
||||
if (showIndicator) {
|
||||
binding.llNumberIndicator.goneIf(false)
|
||||
binding.tvIndicatorPosition.text = "${position + 1}"
|
||||
handler.removeMessages(HIDE_BANNER_NUMBER_INDICATOR)
|
||||
handler.sendEmptyMessageDelayed(HIDE_BANNER_NUMBER_INDICATOR, SHOW_NUMBER_INDICATOR_DURATION)
|
||||
binding.dorIndicator.selectPosition(position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMoreItemDialog() {
|
||||
val imageArticle = viewModel.imageArticleDetailEntity.value ?: return
|
||||
NewLogUtils.logShareEnter("图文详情页")
|
||||
NewLogUtils.logClickNoteDetailMore()
|
||||
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
|
||||
val entities = ArrayList<MenuItemEntity>()
|
||||
// 申请加精
|
||||
val simplifyChoicenessStatus = imageArticle.getSimplifyChoicenessStatus()
|
||||
if (imageArticle.user.id == UserManager.getInstance().userId && !imageArticle.me.isModerator && imageArticle.status == "pass") {
|
||||
val isEnable =
|
||||
simplifyChoicenessStatus != ArticleDetailEntity.STATUS_PASS
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_apply_select_title),
|
||||
if (isEnable)
|
||||
R.drawable.icon_more_panel_essence else R.drawable.icon_more_panel_essence_unenable,
|
||||
isEnable = isEnable
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// 修改
|
||||
if (imageArticle.me.isContentOwner
|
||||
&& imageArticle.status == ArticleDetailEntity.STATUS_PASS
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(getString(R.string.article_detail_more_edit_title), R.drawable.icon_more_panel_edit)
|
||||
)
|
||||
}
|
||||
|
||||
// 举报
|
||||
if (!imageArticle.me.isContentOwner) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_complaint_title),
|
||||
R.drawable.icon_gamedetail_copyright
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val moderatorPermissions = imageArticle.me.moderatorPermissions
|
||||
// 取消精选
|
||||
if (imageArticle.me.isModerator
|
||||
&& imageArticle.status == ArticleDetailEntity.STATUS_PASS
|
||||
) {
|
||||
if (simplifyChoicenessStatus == ArticleDetailEntity.STATUS_PASS) {
|
||||
if ((moderatorPermissions.cancelChoicenessImageArticle) > Permissions.GUEST
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_unselect_title),
|
||||
R.drawable.icon_more_panel_essence_cancel
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if ((moderatorPermissions.choicenessImageArticle) > Permissions.GUEST
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_select_title),
|
||||
R.drawable.icon_more_panel_essence
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 修改活动标签
|
||||
if (imageArticle.me.isModerator &&
|
||||
(moderatorPermissions.updateArticleActivityTag) > Permissions.GUEST &&
|
||||
imageArticle.status == ArticleDetailEntity.STATUS_PASS
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_edit_activity_tag_title),
|
||||
R.drawable.icon_more_panel_modify_label
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// 隐藏/删除
|
||||
if (imageArticle.me.isModerator && moderatorPermissions.hideImageArticle > Permissions.GUEST
|
||||
) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_hide_title),
|
||||
R.drawable.icon_more_panel_delete
|
||||
)
|
||||
)
|
||||
} else {
|
||||
if (imageArticle.me.isContentOwner) {
|
||||
entities.add(
|
||||
MenuItemEntity(
|
||||
getString(R.string.article_detail_more_delete_title),
|
||||
R.drawable.icon_more_panel_delete
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
MoreFunctionPanelDialog.showMoreDialog(
|
||||
requireActivity() as AppCompatActivity,
|
||||
entities,
|
||||
imageArticle.title.ifBlank { imageArticle.content },
|
||||
getShareEntity(imageArticle),
|
||||
imageArticle.status,
|
||||
tag ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getShareEntity(imageArticle: ImageArticleEntity): NormalShareEntity {
|
||||
val params = AdditionalParamsEntity().apply {
|
||||
contentType = "图文"
|
||||
contentId = imageArticle.id
|
||||
bbsId = imageArticle.communityId
|
||||
bbsType = imageArticle.community?.typeChinese ?: "综合论坛"
|
||||
customerType = imageArticle.user.auth?.text ?: ""
|
||||
activityTagName = ""
|
||||
gameForumType = imageArticle.community?.game?.categoryChinese ?: ""
|
||||
refUserId = UserManager.getInstance().userId
|
||||
}
|
||||
return NormalShareEntity(
|
||||
id = imageArticle.id,
|
||||
shareUrl = requireContext().getString(
|
||||
R.string.share_community_image_article_url,
|
||||
imageArticle.shortId
|
||||
),
|
||||
shareIcon = if (imageArticle.images.isNotEmpty()) {
|
||||
imageArticle.images.first()
|
||||
} else {
|
||||
requireContext().getString(R.string.share_ghzs_logo)
|
||||
},
|
||||
shareTitle = imageArticle.title.ifBlank { imageArticle.content }
|
||||
.ifBlank { getString(R.string.image_article) },
|
||||
shareSummary = imageArticle.content,
|
||||
shareEntrance = ShareUtils.ShareEntrance.communityArticle,
|
||||
additionalParams = params
|
||||
)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
DownloadManager.getInstance().addObserver(dataWatcher)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
DownloadManager.getInstance().removeObserver(dataWatcher)
|
||||
}
|
||||
|
||||
//下载被删除事件
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(status: EBDownloadStatus) {
|
||||
if ("delete" == status.status) {
|
||||
setDownloadButton(viewModel.imageArticleDetailEntity.value?.community?.game)
|
||||
}
|
||||
}
|
||||
|
||||
//安装、卸载事件
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(busFour: EBPackage) {
|
||||
setDownloadButton(viewModel.imageArticleDetailEntity.value?.community?.game)
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(reuse: EBReuse) {
|
||||
if (reuse.type == Constants.LOGIN_TAG) { // 登入
|
||||
viewModel.loadImageArticleDetail(imageArticleId, recommendId)
|
||||
|
||||
}
|
||||
val path = Path()
|
||||
path.reset()
|
||||
}
|
||||
|
||||
//
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
viewModel.imageArticleChanged(changed)
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
setDownloadButton(viewModel.imageArticleDetailEntity.value?.community?.game)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
when {
|
||||
requestCode == CommentActivity.REQUEST_CODE && resultCode == Activity.RESULT_OK -> {
|
||||
val commentCount = data?.getIntExtra(CommentActivity.COMMENT_COUNT, 0) ?: 0
|
||||
val commentId = data?.getStringExtra(EntranceConsts.KEY_COMMENT_ID) ?: ""
|
||||
viewModel.updateComment(commentId, commentCount)
|
||||
}
|
||||
|
||||
requestCode == MoreFunctionPanelDialog.REQUEST_CODE && resultCode == Activity.RESULT_OK -> {
|
||||
getItemClickCallback().invoke(data?.getParcelableExtra(EntranceConsts.KEY_DATA))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getItemClickCallback(): (menuItem: MenuItemEntity?) -> Unit {
|
||||
return {
|
||||
when (it?.text) {
|
||||
getString(R.string.article_detail_more_edit_title) -> {
|
||||
val uri = Uri.Builder()
|
||||
.path(RouteConsts.activity.publishImageArticleActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_ENTRANCE, "图文详情")
|
||||
.build()
|
||||
ARouter.getInstance().build(uri)
|
||||
.withParcelable(
|
||||
EntranceConsts.KEY_IMAGE_ARTICLE_ENTITY,
|
||||
viewModel.imageArticleDetailEntity.value
|
||||
)
|
||||
.navigation()
|
||||
|
||||
NewLogUtils.logSharePanelClick(
|
||||
"click_modification",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_complaint_title) -> {
|
||||
ifLogin("图文详情") {
|
||||
BbsReportHelper.showReportDialog(BbsReportHelper.ImageArticleReporter(imageArticleId))
|
||||
}
|
||||
NewLogUtils.logSharePanelClick(
|
||||
"click_report",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_apply_select_title) -> {
|
||||
if (viewModel.imageArticleDetailEntity.value?.getSimplifyChoicenessStatus() == "apply") {
|
||||
ToastUtils.showToast("申请加精审核中")
|
||||
} else {
|
||||
viewModel.applyHighlightForImageArticle()
|
||||
NewLogUtils.logSharePanelClick(
|
||||
"click_apply_essence",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_select_title) -> {
|
||||
if (viewModel.imageArticleDetailEntity.value?.getSimplifyChoicenessStatus() == "apply") {
|
||||
ToastUtils.showToast("加精审核中")
|
||||
} else {
|
||||
showHighlightDialog(true)
|
||||
NewLogUtils.logSharePanelClick(
|
||||
"click_essence",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_unselect_title) -> {
|
||||
showHighlightDialog(false)
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_delete_title),
|
||||
getString(R.string.article_detail_more_hide_title) -> {
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
"提示",
|
||||
"${it.text}帖子后,其中的所有评论及回复都将被${it.text}",
|
||||
it.text,
|
||||
"取消",
|
||||
confirmClickCallback = {
|
||||
viewModel.deleteOrHideImageArticle()
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
NewLogUtils.logSharePanelClick(
|
||||
"click_delete",
|
||||
viewModel.imageArticleDetailEntity.value?.user?.id ?: "",
|
||||
"图文",
|
||||
imageArticleId,
|
||||
viewModel.imageArticleDetailEntity.value?.community?.id ?: "",
|
||||
viewModel.imageArticleDetailEntity.value?.community?.typeChinese ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_top_title) -> {
|
||||
// TopCommunityCategoryDialog.show(
|
||||
// childFragmentManager
|
||||
// ) { category ->
|
||||
// mViewModel.topCommunityArticle(category.id)
|
||||
// }
|
||||
}
|
||||
|
||||
getString(R.string.article_detail_more_cancel_top_title) -> {
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
getString(R.string.article_detail_cancel_top_dialog_title),
|
||||
getString(R.string.article_detail_cancel_top_dialog_hint),
|
||||
getString(R.string.article_detail_cancel_top_dialog_confirm),
|
||||
getString(R.string.article_detail_cancel_top_dialog_cancel),
|
||||
confirmClickCallback = {
|
||||
// mViewModel.cancelTopCommunityArticle()
|
||||
},
|
||||
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showHighlightDialog(isHighlight: Boolean) {
|
||||
val imageArticle = viewModel.imageArticleDetailEntity.value ?: return
|
||||
var highlightDialogHintContent = ""
|
||||
val permissions = imageArticle.me.moderatorPermissions
|
||||
if ((isHighlight && permissions.choicenessImageArticle > Permissions.GUEST) ||
|
||||
(!isHighlight && permissions.cancelChoicenessImageArticle > Permissions.GUEST)
|
||||
) {
|
||||
highlightDialogHintContent =
|
||||
if ((isHighlight && permissions.choicenessImageArticle == Permissions.REPORTER) ||
|
||||
(!isHighlight && permissions.cancelChoicenessImageArticle == Permissions.REPORTER)
|
||||
) {
|
||||
"你的操作将提交给小编审核,确定提交吗?"
|
||||
} else {
|
||||
"你的操作将立即生效,确定提交吗?"
|
||||
}
|
||||
}
|
||||
val title = if (isHighlight) "加精帖子" else "取消精选"
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
title,
|
||||
highlightDialogHintContent,
|
||||
"确定",
|
||||
"取消",
|
||||
{
|
||||
viewModel.addHighlight(isHighlight)
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val HIDE_BANNER_NUMBER_INDICATOR = 1
|
||||
private const val SHOW_NUMBER_INDICATOR_DURATION = 5000L
|
||||
private const val SHOW_DOT_INDICATOR_MIN = 2
|
||||
private const val BANNER_RADIO_MIN = 0.5F
|
||||
private const val BANNER_RADIO_MAX = 1.33F
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,166 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.LazyFragment
|
||||
import com.gh.gamecenter.common.baselist.PageLoader
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.utils.DialogHelper
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toResString
|
||||
import com.gh.gamecenter.databinding.FragmentImageArticleDraftBinding
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageArticleDraftAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.ImageArticleDraftViewModel
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.PublishImageArticleActivityViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class ImageArticleDraftFragment : LazyFragment() {
|
||||
|
||||
private val viewModel by viewModels<ImageArticleDraftViewModel>()
|
||||
private val activityViewModel by activityViewModels<PublishImageArticleActivityViewModel>()
|
||||
|
||||
private lateinit var binding: FragmentImageArticleDraftBinding
|
||||
|
||||
private var isFromPublishPage = false
|
||||
|
||||
private val adapter by lazy {
|
||||
ImageArticleDraftAdapter(requireContext(), viewModel)
|
||||
}
|
||||
|
||||
override fun getRealLayoutId(): Int {
|
||||
return R.layout.fragment_image_article_draft
|
||||
}
|
||||
|
||||
override fun onRealLayoutInflated(inflatedView: View) {
|
||||
binding = FragmentImageArticleDraftBinding.bind(inflatedView)
|
||||
}
|
||||
|
||||
override fun initRealView() {
|
||||
super.initRealView()
|
||||
isFromPublishPage = arguments?.getBoolean(KEY_IS_FROM_PUBLISH_PAGE) ?: false
|
||||
binding.rvDrafts.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
|
||||
binding.rvDrafts.addItemDecoration(MyItemDecoration())
|
||||
binding.rvDrafts.adapter = adapter
|
||||
|
||||
binding.srlRefresh.setOnRefreshListener {
|
||||
viewModel.loadDraft(true)
|
||||
}
|
||||
|
||||
with(viewModel) {
|
||||
pageState.observe(viewLifecycleOwner) {
|
||||
|
||||
binding.srlRefresh.goneIf(
|
||||
it == PageLoader.PageState.PageNoData || it == PageLoader.PageState.PageInitFailure
|
||||
) {
|
||||
binding.srlRefresh.isRefreshing = false
|
||||
}
|
||||
binding.reuseLlLoading.root.goneIf(it != PageLoader.PageState.PageInitLoading)
|
||||
binding.reuseNoneData.root.goneIf(it != PageLoader.PageState.PageNoData)
|
||||
binding.reuseDataException.root.goneIf(it != PageLoader.PageState.PageInitFailure)
|
||||
|
||||
}
|
||||
|
||||
drafts.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(it)
|
||||
}
|
||||
|
||||
showDeleteDraftDialogAction.observe(viewLifecycleOwner, EventObserver {
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
R.string.warning.toResString(),
|
||||
R.string.delete_image_article_warning.toResString(),
|
||||
com.gh.gamecenter.core.R.string.confirm.toResString(),
|
||||
com.gh.gamecenter.common.R.string.cancel.toResString(),
|
||||
confirmClickCallback = {
|
||||
viewModel.deleteDraft(it)
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
})
|
||||
|
||||
publishImageArticleDestination.observe(viewLifecycleOwner, EventObserver {
|
||||
it.isDraft = true
|
||||
if (isFromPublishPage) {
|
||||
// 如果是从发布页进入草稿箱,则回到发布页,并将草稿数据回传
|
||||
activityViewModel.setEditImageArticle(it)
|
||||
activity?.onBackPressedDispatcher?.onBackPressed()
|
||||
} else {
|
||||
// 否则,直接打开新的发布页
|
||||
val uri = Uri.Builder()
|
||||
.path(RouteConsts.activity.publishImageArticleActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_ENTRANCE, "图文草稿")
|
||||
.build()
|
||||
ARouter.getInstance().build(uri)
|
||||
.withParcelable(EntranceConsts.KEY_IMAGE_ARTICLE_ENTITY, it)
|
||||
.navigation()
|
||||
}
|
||||
})
|
||||
|
||||
loadDraft(false)
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
if (changed is EBImageArticleChanged.DataCreated
|
||||
&& changed.draftId.isNotBlank()
|
||||
) {
|
||||
// 如果时选择的草稿发布,则删除当前选中草稿
|
||||
val draftList = viewModel.drafts.value?.toMutableList()
|
||||
if (draftList != null) {
|
||||
val hasRemoved = draftList.removeAll { it.id == changed.draftId }
|
||||
if (hasRemoved) {
|
||||
if (draftList.isEmpty()) {
|
||||
viewModel.loadDraft(true)
|
||||
} else {
|
||||
adapter.submitList(null)
|
||||
adapter.notifyDataSetChanged()
|
||||
viewModel.updateDrafts(draftList)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyItemDecoration : RecyclerView.ItemDecoration() {
|
||||
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
val layoutParams = view.layoutParams
|
||||
if (layoutParams is StaggeredGridLayoutManager.LayoutParams) {
|
||||
val spanIndex = layoutParams.spanIndex
|
||||
val (left, right) = if (spanIndex == 0) {
|
||||
8F.dip2px() to 2F.dip2px()
|
||||
} else {
|
||||
2F.dip2px() to 8F.dip2px()
|
||||
}
|
||||
outRect.left = left
|
||||
outRect.right = right
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val KEY_IS_FROM_PUBLISH_PAGE = "key_is_from_publish_page"
|
||||
|
||||
fun newInstance(isFromPublishPage: Boolean) =
|
||||
ImageArticleDraftFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putBoolean(KEY_IS_FROM_PUBLISH_PAGE, isFromPublishPage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,282 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.ethanhua.skeleton.Skeleton
|
||||
import com.gh.common.exposure.ExposureListener
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.LazyFragment
|
||||
import com.gh.gamecenter.common.baselist.PageLoader
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.tryToClearRecycler
|
||||
import com.gh.gamecenter.databinding.FragmentImageArticleHomeBinding
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleFooterWrapperAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.RecommendHomeAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.ImageArticleHomeViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class ImageArticleHomeFragment : LazyFragment() {
|
||||
|
||||
private val viewModel: ImageArticleHomeViewModel by viewModels()
|
||||
|
||||
private lateinit var binding: FragmentImageArticleHomeBinding
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
private var isFirstVisible = true
|
||||
|
||||
private val skeletonScreen by lazy {
|
||||
Skeleton.bind(binding.flSkeleton)
|
||||
.shimmer(true)
|
||||
.angle(Constants.SHIMMER_ANGLE)
|
||||
.color(com.gh.gamecenter.common.R.color.ui_skeleton_highlight)
|
||||
.duration(Constants.SHIMMER_DURATION)
|
||||
.maskWidth(Constants.MASK_WIDTH)
|
||||
.gradientCenterColorWidth(Constants.GRADIENT_CENTER_COLOR_WIDTH)
|
||||
.load(R.layout.fragment_image_article_home_skeleton)
|
||||
.show()
|
||||
}
|
||||
|
||||
private val adapter by lazy {
|
||||
RecommendHomeAdapter(requireContext(), viewModel)
|
||||
}
|
||||
|
||||
override fun getRealLayoutId(): Int = R.layout.fragment_image_article_home
|
||||
|
||||
override fun onRealLayoutInflated(inflatedView: View) {
|
||||
binding = FragmentImageArticleHomeBinding.bind(inflatedView)
|
||||
}
|
||||
|
||||
override fun onFragmentResume() {
|
||||
super.onFragmentResume()
|
||||
NewLogUtils.logRecommendFeedEvent("view_for_you_feed")
|
||||
}
|
||||
|
||||
override fun initRealView() {
|
||||
super.initRealView()
|
||||
isFirstVisible = false
|
||||
binding.rvRecommends.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL).also {
|
||||
it.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_NONE
|
||||
}
|
||||
binding.rvRecommends.adapter = adapter
|
||||
binding.rvRecommends.addItemDecoration(MyItemDecoration())
|
||||
|
||||
binding.srlRefresh.setOnRefreshListener {
|
||||
viewModel.pageLoader.pullToRefresh()
|
||||
}
|
||||
|
||||
binding.reuseNoConnection.connectionReloadTv.setOnClickListener {
|
||||
viewModel.initLoad()
|
||||
}
|
||||
|
||||
val exposureListener = ExposureListener(this, adapter)
|
||||
binding.rvRecommends.addOnScrollListener(exposureListener)
|
||||
binding.rvRecommends.addOnScrollListener(object : OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
val layoutManager = binding.rvRecommends.layoutManager
|
||||
if (layoutManager is StaggeredGridLayoutManager) {
|
||||
val itemPositions = layoutManager.findLastCompletelyVisibleItemPositions(null)
|
||||
val lastCompletePosition = itemPositions.maxOrNull() ?: -1
|
||||
val position = if (lastCompletePosition != -1) {
|
||||
lastCompletePosition
|
||||
} else {
|
||||
val itemVisible = layoutManager.findLastVisibleItemPositions(null)
|
||||
itemVisible.maxOrNull() ?: 0
|
||||
}
|
||||
NewLogUtils.logRecommendFeedSlide(position + 1)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
with(viewModel) {
|
||||
pageLoader.pageState.observe(viewLifecycleOwner) {
|
||||
if (it == PageLoader.PageState.PageInitLoading) {
|
||||
skeletonScreen
|
||||
} else {
|
||||
skeletonScreen.hide()
|
||||
}
|
||||
|
||||
if (it is PageLoader.PageState.PagePullToRefreshLoading) {
|
||||
// 正在下拉刷新,页面保持不变
|
||||
binding.srlRefresh.isRefreshing = true
|
||||
} else {
|
||||
binding.reuseNoneData.root.goneIf(it != PageLoader.PageState.PageNoData)
|
||||
binding.reuseNoConnection.root.goneIf(it != PageLoader.PageState.PageInitFailure)
|
||||
|
||||
binding.srlRefresh.isEnabled = it != PageLoader.PageState.PageInitLoading
|
||||
&& it != PageLoader.PageState.PageInitFailure
|
||||
binding.srlRefresh.isRefreshing = false
|
||||
}
|
||||
|
||||
if (it is PageLoader.PageState.PageLoadMoreReady
|
||||
&& (it.previousState is PageLoader.PageState.PagePullToRefreshLoading
|
||||
|| it.previousState is PageLoader.PageState.PageInitLoading)
|
||||
) {
|
||||
// 加载第一页完成
|
||||
if (it.previousState is PageLoader.PageState.PagePullToRefreshLoading) {
|
||||
// 下拉刷新成功,先清空上一次内容
|
||||
adapter.submitList(null)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
// 延时一下,检查第一页数据是否已铺满第一页,如果未铺满,则直接请求下一页
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
handler.postDelayed({
|
||||
checkIfLoadNextPage(binding.rvRecommends, viewModel::loadMore)
|
||||
}, 16)
|
||||
}
|
||||
adapter.setPageState(it)
|
||||
|
||||
}
|
||||
|
||||
pageLoader.dataList.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(it)
|
||||
}
|
||||
|
||||
imageDetailDestination.observe(viewLifecycleOwner, EventObserver {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, it.id)
|
||||
.appendQueryParameter(EntranceConsts.KEY_SOURCE_ENTRANCE, "社区-推荐信息流")
|
||||
.appendQueryParameter(EntranceConsts.KEY_RECOMMEND_ID, it.recommendId)
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
})
|
||||
|
||||
initLoad()
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
if (isFirstVisible) {
|
||||
return
|
||||
}
|
||||
when (changed) {
|
||||
is EBImageArticleChanged.VoteChanged -> {
|
||||
viewModel.voteChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataChanged -> {
|
||||
viewModel.itemChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataDeleted -> {
|
||||
itemDeleted(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataCreated -> {
|
||||
itemCreated(changed)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun itemCreated(changed: EBImageArticleChanged.DataCreated) {
|
||||
val newData = viewModel.pageLoader.dataList.value?.toMutableList() ?: mutableListOf()
|
||||
if (newData.isEmpty()) {
|
||||
viewModel.initLoad()
|
||||
} else {
|
||||
// 瀑布流布局,在中间添加或者移除item时,会出现错位的现象,这里需要先将原来的数据清空,在重新添加可以避免这个问题
|
||||
adapter.submitList(null)
|
||||
newData.add(0, changed.imageArticle)
|
||||
viewModel.pageLoader.updateData(newData)
|
||||
}
|
||||
}
|
||||
|
||||
private fun itemDeleted(changed: EBImageArticleChanged.DataDeleted) {
|
||||
val oldData = viewModel.pageLoader.dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val hasRemoved = newData.removeAll {
|
||||
it.id == changed.imageArticleId
|
||||
}
|
||||
if (hasRemoved) {
|
||||
if (newData.isEmpty()) {
|
||||
viewModel.initLoad()
|
||||
} else {
|
||||
adapter.submitList(null)
|
||||
viewModel.pageLoader.updateData(newData)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
isFirstVisible = true
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
if (::binding.isInitialized) {
|
||||
binding.rvRecommends.tryToClearRecycler()
|
||||
binding.rvRecommends.recycledViewPool.clear()
|
||||
adapter.onDarkModeChanged()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val KEY_IS_IN_MY_PUBLISH = "key_is_in_my_publish"
|
||||
|
||||
fun newInstance() = ImageArticleHomeFragment()
|
||||
|
||||
fun checkIfLoadNextPage(recyclerView: RecyclerView, loadNext: () -> Unit) {
|
||||
val layoutManager = recyclerView.layoutManager
|
||||
if (layoutManager is StaggeredGridLayoutManager) {
|
||||
val itemPositions = layoutManager.findLastVisibleItemPositions(null)
|
||||
val lastPosition = itemPositions.maxOrNull() ?: 0
|
||||
val itemType = recyclerView.adapter?.getItemViewType(lastPosition) ?: 0
|
||||
if (itemType == ImageArticleFooterWrapperAdapter.ITEM_TYPE_FOOTER) {
|
||||
// 底部加载更多的itemView显示在屏幕内,说明数据未铺满一屏:直接加载下一页
|
||||
loadNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyItemDecoration : RecyclerView.ItemDecoration() {
|
||||
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
val layoutParams = view.layoutParams
|
||||
if (layoutParams is StaggeredGridLayoutManager.LayoutParams) {
|
||||
if (parent.getChildAdapterPosition(view) == state.itemCount - 1) {
|
||||
layoutParams.isFullSpan = true
|
||||
} else {
|
||||
val spanIndex = layoutParams.spanIndex
|
||||
val (left, right) = if (spanIndex % 2 == 0) {
|
||||
8F.dip2px() to 2F.dip2px()
|
||||
} else {
|
||||
2F.dip2px() to 8F.dip2px()
|
||||
}
|
||||
outRect.left = left
|
||||
outRect.right = right
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,216 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.ethanhua.skeleton.Skeleton
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.LazyFragment
|
||||
import com.gh.gamecenter.common.baselist.PageLoader
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.databinding.FragmentImageArticleHomeBinding
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.MyImageArticleAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.fragment.ImageArticleHomeFragment.Companion.checkIfLoadNextPage
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.MyImageArticleListViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class MyImageArticleListFragment : LazyFragment() {
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
private val viewModel by viewModels<MyImageArticleListViewModel>()
|
||||
|
||||
private lateinit var binding: FragmentImageArticleHomeBinding
|
||||
|
||||
private val skeletonScreen by lazy {
|
||||
Skeleton.bind(binding.flSkeleton)
|
||||
.shimmer(true)
|
||||
.angle(Constants.SHIMMER_ANGLE)
|
||||
.color(com.gh.gamecenter.common.R.color.ui_skeleton_highlight)
|
||||
.duration(Constants.SHIMMER_DURATION)
|
||||
.maskWidth(Constants.MASK_WIDTH)
|
||||
.gradientCenterColorWidth(Constants.GRADIENT_CENTER_COLOR_WIDTH)
|
||||
.load(R.layout.fragment_image_article_home_skeleton)
|
||||
.show()
|
||||
}
|
||||
|
||||
private val adapter by lazy {
|
||||
MyImageArticleAdapter(requireContext(), viewModel)
|
||||
}
|
||||
|
||||
override fun getRealLayoutId(): Int = R.layout.fragment_image_article_home
|
||||
|
||||
override fun onRealLayoutInflated(inflatedView: View) {
|
||||
binding = FragmentImageArticleHomeBinding.bind(inflatedView)
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun initRealView() {
|
||||
super.initRealView()
|
||||
binding.rvRecommends.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
|
||||
binding.rvRecommends.adapter = adapter
|
||||
binding.rvRecommends.addItemDecoration(MyItemDecoration())
|
||||
|
||||
binding.srlRefresh.setOnRefreshListener {
|
||||
viewModel.pageLoader.pullToRefresh()
|
||||
}
|
||||
|
||||
binding.reuseNoConnection.connectionReloadTv.setOnClickListener {
|
||||
viewModel.initLoad()
|
||||
}
|
||||
|
||||
with(viewModel) {
|
||||
pageLoader.pageState.observe(viewLifecycleOwner) {
|
||||
if (it == PageLoader.PageState.PageInitLoading) {
|
||||
skeletonScreen
|
||||
} else {
|
||||
skeletonScreen.hide()
|
||||
}
|
||||
|
||||
if (it is PageLoader.PageState.PagePullToRefreshLoading) {
|
||||
// 正在下拉刷新,页面保持不变
|
||||
binding.srlRefresh.isRefreshing = true
|
||||
} else {
|
||||
binding.reuseNoneData.root.goneIf(it != PageLoader.PageState.PageNoData)
|
||||
binding.reuseNoConnection.root.goneIf(it != PageLoader.PageState.PageInitFailure)
|
||||
|
||||
binding.srlRefresh.isEnabled = it != PageLoader.PageState.PageInitLoading
|
||||
&& it != PageLoader.PageState.PageInitFailure
|
||||
binding.srlRefresh.isRefreshing = false
|
||||
}
|
||||
|
||||
if (it is PageLoader.PageState.PageLoadMoreReady
|
||||
&& (it.previousState is PageLoader.PageState.PagePullToRefreshLoading
|
||||
|| it.previousState is PageLoader.PageState.PageInitLoading)
|
||||
) {
|
||||
if (it.previousState is PageLoader.PageState.PagePullToRefreshLoading) {
|
||||
adapter.submitList(null)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
// 延时一下,检查第一页数据是否已铺满第一页,如果未铺满,则直接请求下一页
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
handler.postDelayed({
|
||||
checkIfLoadNextPage(binding.rvRecommends, viewModel::loadMore)
|
||||
}, 16)
|
||||
}
|
||||
adapter.setPageState(it)
|
||||
}
|
||||
|
||||
pageLoader.dataList.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(it)
|
||||
}
|
||||
|
||||
imageArticleDetailDestination.observe(viewLifecycleOwner, EventObserver {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, it)
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
})
|
||||
|
||||
initLoad()
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(changed: EBImageArticleChanged) {
|
||||
when (changed) {
|
||||
is EBImageArticleChanged.VoteChanged -> {
|
||||
viewModel.voteChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataChanged -> {
|
||||
viewModel.itemChanged(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataDeleted -> {
|
||||
itemDeleted(changed)
|
||||
}
|
||||
|
||||
is EBImageArticleChanged.DataCreated -> {
|
||||
itemCreated(changed)
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun itemCreated(changed: EBImageArticleChanged.DataCreated) {
|
||||
val newData = viewModel.pageLoader.dataList.value?.toMutableList() ?: mutableListOf()
|
||||
if (newData.isEmpty()) {
|
||||
viewModel.initLoad()
|
||||
} else {
|
||||
adapter.submitList(null)
|
||||
// 请注意:这一行代码不能省
|
||||
adapter.notifyDataSetChanged()
|
||||
newData.add(0, changed.imageArticle.toPersonHistoryEntity())
|
||||
viewModel.pageLoader.updateData(newData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun itemDeleted(changed: EBImageArticleChanged.DataDeleted) {
|
||||
val oldData = viewModel.pageLoader.dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val hasRemoved = newData.removeAll {
|
||||
it.id == changed.imageArticleId
|
||||
}
|
||||
if (hasRemoved) {
|
||||
adapter.submitList(null)
|
||||
adapter.notifyDataSetChanged()
|
||||
if (newData.isEmpty()) {
|
||||
viewModel.initLoad()
|
||||
} else {
|
||||
viewModel.pageLoader.updateData(newData)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance() = MyImageArticleListFragment()
|
||||
}
|
||||
|
||||
private class MyItemDecoration : RecyclerView.ItemDecoration() {
|
||||
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
val layoutParams = view.layoutParams
|
||||
if (layoutParams is StaggeredGridLayoutManager.LayoutParams) {
|
||||
if (parent.getChildAdapterPosition(view) == state.itemCount - 1) {
|
||||
layoutParams.isFullSpan = true
|
||||
} else {
|
||||
val spanIndex = layoutParams.spanIndex
|
||||
val (left, right) = if (spanIndex % 2 == 0) {
|
||||
8F.dip2px() to 2F.dip2px()
|
||||
} else {
|
||||
2F.dip2px() to 8F.dip2px()
|
||||
}
|
||||
outRect.left = left
|
||||
outRect.right = right
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,525 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.fragment
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.Editable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener
|
||||
import android.widget.EditText
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.ACTION_STATE_IDLE
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.ErrorHelper
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.BaseFragment
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.databinding.FragmentPublishImageArticleBinding
|
||||
import com.gh.gamecenter.entity.ForumDetailEntity
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageAndTextAdapter
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.PublishImageArticleActivityViewModel
|
||||
import com.gh.gamecenter.forum.home.recommend.viewmodel.PublishImageArticleViewModel
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.gh.gamecenter.qa.dialog.ChooseForumActivity
|
||||
import com.gh.gamecenter.qa.dialog.ChooseSectionDialogFragment
|
||||
import com.lightgame.listeners.OnBackPressedListener
|
||||
import com.lightgame.utils.Util_System_Keyboard
|
||||
|
||||
class PublishImageArticleFragment : BaseFragment<Unit>(), OnBackPressedListener {
|
||||
|
||||
private val activityViewModel by activityViewModels<PublishImageArticleActivityViewModel>()
|
||||
private val viewModel by viewModels<PublishImageArticleViewModel>()
|
||||
|
||||
private lateinit var binding: FragmentPublishImageArticleBinding
|
||||
|
||||
private val rootView: View?
|
||||
get() = activity?.findViewById(android.R.id.content)
|
||||
|
||||
private val itemTouchHelper by lazy {
|
||||
ItemTouchHelper(MyItemTouchCallback(activityViewModel))
|
||||
}
|
||||
|
||||
private val adapter by lazy {
|
||||
ImageAndTextAdapter(viewModel) {
|
||||
itemTouchHelper.startDrag(it)
|
||||
}
|
||||
}
|
||||
|
||||
private val savingDraftLoading by lazy {
|
||||
DialogHelper.getProgressDialog(requireContext(), R.string.draft_saving.toResString())
|
||||
}
|
||||
|
||||
private val publishingLoading by lazy {
|
||||
DialogHelper.getProgressDialog(requireContext(), R.string.image_article_publishing.toResString())
|
||||
}
|
||||
|
||||
override fun getInflatedLayout(): View {
|
||||
return View(requireContext())
|
||||
}
|
||||
|
||||
private val onGlobalLayoutListener = OnGlobalLayoutListener {
|
||||
onKeyboardChanged()
|
||||
}
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
private var isKeyBoardShow = false
|
||||
|
||||
private lateinit var chooseForumLauncher: ActivityResultLauncher<String>
|
||||
|
||||
override fun getLayoutId(): Int = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
chooseForumLauncher = registerForActivityResult<String, CommunityEntity?>(object :
|
||||
ActivityResultContract<String, CommunityEntity?>() {
|
||||
|
||||
override fun createIntent(context: Context, input: String): Intent {
|
||||
val intent = Intent(context, ChooseForumActivity::class.java)
|
||||
intent.putExtra(EntranceConsts.KEY_SOURCE_ENTRANCE, input)
|
||||
return intent
|
||||
}
|
||||
|
||||
override fun parseResult(resultCode: Int, intent: Intent?): CommunityEntity? {
|
||||
return intent?.getParcelableExtra(EntranceConsts.KEY_COMMUNITY_DATA)
|
||||
}
|
||||
}
|
||||
) { result -> result?.let(viewModel::changeLinkBbs) }
|
||||
|
||||
activityViewModel.editImageArticle.observe(this, EventObserver {
|
||||
viewModel.setEditImageArticle(it)
|
||||
})
|
||||
|
||||
activityViewModel.community.observe(this, EventObserver {
|
||||
viewModel.changeLinkBbs(it)
|
||||
})
|
||||
}
|
||||
|
||||
override fun initView(view: View?) = Unit
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return FragmentPublishImageArticleBinding.inflate(inflater, container, false)
|
||||
.also {
|
||||
binding = it
|
||||
}.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
view.post {
|
||||
setContentHeight(0)
|
||||
}
|
||||
|
||||
|
||||
binding.rvImages.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
binding.rvImages.addItemDecoration(MyItemDecoration())
|
||||
binding.rvImages.adapter = adapter
|
||||
itemTouchHelper.attachToRecyclerView(binding.rvImages)
|
||||
|
||||
binding.etTitle.addTextChangedListener { text ->
|
||||
if (text != null) {
|
||||
checkMaxLimitReached(binding.etTitle, text, TITLE_MAX_LENGTH, R.string.image_and_text_title_limit)
|
||||
var remainingSize = TITLE_MAX_LENGTH - text.length
|
||||
if (remainingSize < 0) {
|
||||
remainingSize = 0
|
||||
}
|
||||
binding.tvRemainingWords.text = "$remainingSize"
|
||||
}
|
||||
binding.ivClear.visibleIf(!text.isNullOrBlank() && binding.etTitle.hasFocus())
|
||||
}
|
||||
|
||||
binding.etTitle.setOnFocusChangeListener { _, hasFocus ->
|
||||
binding.ivClear.visibleIf(hasFocus && binding.etTitle.text.isNotBlank())
|
||||
binding.tvRemainingWords.visibleIf(hasFocus)
|
||||
}
|
||||
|
||||
binding.tvSelectBbs.setOnClickListener {
|
||||
showSelectBbsDialog()
|
||||
}
|
||||
|
||||
binding.ivClear.setOnClickListener {
|
||||
binding.etTitle.text = null
|
||||
}
|
||||
|
||||
binding.vCloseDragTips.setOnClickListener {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
binding.gDragTips.goneIf(true)
|
||||
}
|
||||
|
||||
binding.etContent.addTextChangedListener { text ->
|
||||
if (text != null) {
|
||||
checkMaxLimitReached(binding.etContent, text, CONTENT_MAX_LENGTH, R.string.image_and_text_content_limit)
|
||||
}
|
||||
}
|
||||
|
||||
binding.tvBbsName.setOnClickListener {
|
||||
showSelectBbsDialog()
|
||||
}
|
||||
|
||||
binding.tvSubSection.setOnClickListener {
|
||||
showSelectSubSectionDialog()
|
||||
}
|
||||
|
||||
binding.vClearBbs.setOnClickListener {
|
||||
if (viewModel.isCreating) {
|
||||
viewModel.changeLinkBbs(null)
|
||||
} else {
|
||||
viewModel.changeLinkSection(null)
|
||||
toast(R.string.cannot_be_modified_after_publishing)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
binding.tvDraftBox.setOnClickListener {
|
||||
activityViewModel.navigateToDraftBox()
|
||||
}
|
||||
|
||||
binding.tvPublish.setOnClickListener {
|
||||
publish()
|
||||
}
|
||||
|
||||
activityViewModel.localImages.observe(viewLifecycleOwner) {
|
||||
adapter.submitList(it)
|
||||
}
|
||||
|
||||
activityViewModel.showDragTipsAction.observe(viewLifecycleOwner, EventObserver {
|
||||
// 倒计时开始,5s 后消失
|
||||
binding.gDragTips.visibleIf(true)
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
handler.postDelayed({
|
||||
binding.gDragTips.goneIf(true)
|
||||
}, DRAG_TIPS_SHOW_DURATION)
|
||||
|
||||
})
|
||||
|
||||
with(viewModel) {
|
||||
|
||||
chooseImageAction.observe(viewLifecycleOwner, EventObserver {
|
||||
activityViewModel.chooseImage()
|
||||
})
|
||||
|
||||
removeImageAction.observe(viewLifecycleOwner, EventObserver {
|
||||
activityViewModel.removeImage(it)
|
||||
})
|
||||
|
||||
linkBbs.observe(viewLifecycleOwner) {
|
||||
updateLinkBbs(it)
|
||||
}
|
||||
|
||||
draftCreated.observe(viewLifecycleOwner, EventObserver {
|
||||
if (savingDraftLoading.isShowing) {
|
||||
savingDraftLoading.dismiss()
|
||||
}
|
||||
val toastText = if (it) {
|
||||
R.string.save_draft_successfully.toResString()
|
||||
} else {
|
||||
R.string.save_draft_failure.toResString()
|
||||
}
|
||||
ToastUtils.showToast(toastText)
|
||||
if (it) {
|
||||
activity?.finish()
|
||||
}
|
||||
})
|
||||
|
||||
imageTextPublished.observe(viewLifecycleOwner, EventObserver { (success, errorString) ->
|
||||
if (publishingLoading.isShowing) {
|
||||
publishingLoading.dismiss()
|
||||
}
|
||||
|
||||
if (success) {
|
||||
ToastUtils.showToast(R.string.publish_image_article_successfully.toResString())
|
||||
activity?.setResult(Activity.RESULT_OK)
|
||||
activity?.finish()
|
||||
} else {
|
||||
ErrorHelper.handleError(requireContext(), errorString, false, "发布图文", "社区实名", "图文") {
|
||||
publish()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
editImageArticle.observe(viewLifecycleOwner, EventObserver {
|
||||
fillUiByDraft(it)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun fillUiByDraft(imageArticle: ImageArticleEntity) {
|
||||
binding.etTitle.setText(imageArticle.title)
|
||||
binding.etContent.setText(imageArticle.content)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内容输入框的高度
|
||||
*/
|
||||
private fun setContentHeight(keyboardHeight: Int) {
|
||||
val rootHeight = binding.root.height
|
||||
val remainHeight =
|
||||
if (keyboardHeight > 0) {
|
||||
rootHeight - 116F.dip2px() - 50F.dip2px() - 50F.dip2px() - keyboardHeight
|
||||
} else {
|
||||
rootHeight - 116F.dip2px() - 50F.dip2px() - 60F.dip2px() - 50F.dip2px()
|
||||
}
|
||||
|
||||
val contentHeight = if (remainHeight > 360F.dip2px()) {
|
||||
360F.dip2px()
|
||||
} else {
|
||||
remainHeight
|
||||
}
|
||||
binding.etContent.updateLayoutParams {
|
||||
height = contentHeight
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDraft() {
|
||||
if (!savingDraftLoading.isShowing) {
|
||||
savingDraftLoading.show()
|
||||
}
|
||||
val title = binding.etTitle.text?.toString() ?: ""
|
||||
val content = binding.etContent.text?.toString() ?: ""
|
||||
val images = activityViewModel.localImages.value ?: emptyList()
|
||||
viewModel.createOrEditDraft(title, content, images)
|
||||
}
|
||||
|
||||
private fun publish() {
|
||||
if (!publishingLoading.isShowing) {
|
||||
publishingLoading.show()
|
||||
}
|
||||
val title = binding.etTitle.text?.toString() ?: ""
|
||||
val content = binding.etContent.text?.toString() ?: ""
|
||||
val images = activityViewModel.localImages.value ?: emptyList()
|
||||
viewModel.publishImageText(title, content, images)
|
||||
}
|
||||
|
||||
private fun updateLinkBbs(linkBbs: PublishImageArticleViewModel.LinkBbs) {
|
||||
if (linkBbs.communityEntity == null) {
|
||||
// 还没有关联论坛
|
||||
binding.tvSelectBbs.visibleIf(true)
|
||||
binding.gBbsSelected.visibleIf(false)
|
||||
} else {
|
||||
// 已关联论坛
|
||||
binding.tvSelectBbs.visibleIf(false)
|
||||
binding.gBbsSelected.visibleIf(true)
|
||||
binding.ivBbsIcon.displayGameIcon(linkBbs.communityEntity.icon, null, null)
|
||||
binding.tvBbsName.text = linkBbs.communityEntity.name
|
||||
if (linkBbs.selectedSection == null) {
|
||||
// 还没有选择子模块
|
||||
|
||||
if (linkBbs.hasSection) {
|
||||
// 有子模块
|
||||
binding.tvSubSection.visibleIf(true)
|
||||
binding.ivBbsArrRight.visibleIf(true)
|
||||
binding.tvSubSection.text = ""
|
||||
} else {
|
||||
// 没有子模块
|
||||
binding.tvSubSection.visibleIf(false)
|
||||
binding.ivBbsArrRight.visibleIf(false)
|
||||
}
|
||||
} else {
|
||||
binding.tvSubSection.text = linkBbs.selectedSection.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkMaxLimitReached(editText: EditText, text: Editable, maxLength: Int, toastResId: Int) {
|
||||
if (text.length > maxLength) {
|
||||
editText.setText(text.subSequence(0, maxLength))
|
||||
editText.setSelection(maxLength) // 将光标移动到文本末尾
|
||||
ToastUtils.showToast(toastResId.toResString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun onKeyboardChanged() {
|
||||
val rect = Rect()
|
||||
rootView?.let {
|
||||
it.getWindowVisibleDisplayFrame(rect)
|
||||
val screenHeight = it.height
|
||||
val keyboardHeight = screenHeight - rect.bottom
|
||||
if (keyboardHeight > screenHeight * 0.15) {
|
||||
// 键盘弹起
|
||||
if (!isKeyBoardShow) {
|
||||
isKeyBoardShow = true
|
||||
|
||||
// 当软键盘弹起时,必须要保证EditText的光标和内容不被挡住
|
||||
setContentHeight(keyboardHeight)
|
||||
}
|
||||
|
||||
} else {
|
||||
// 键盘隐藏
|
||||
if (isKeyBoardShow) {
|
||||
isKeyBoardShow = false
|
||||
setContentHeight(0)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun showSelectBbsDialog() {
|
||||
if (viewModel.isCreating) {
|
||||
val delayTime = if (isKeyBoardShow) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(requireActivity())
|
||||
200L
|
||||
} else 0L
|
||||
AppExecutor.uiExecutor.executeWithDelay({
|
||||
chooseForumLauncher.launch("社区")
|
||||
NewLogUtils.logChooseForumPanelEnter("发图文")
|
||||
}, delayTime)
|
||||
} else {
|
||||
toast(R.string.cannot_be_modified_after_publishing)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSelectSubSectionDialog() {
|
||||
val delayTime = if (isKeyBoardShow) {
|
||||
Util_System_Keyboard.hideSoftKeyboard(requireActivity())
|
||||
200L
|
||||
} else 0L
|
||||
AppExecutor.uiExecutor.executeWithDelay({
|
||||
ChooseSectionDialogFragment.show(
|
||||
requireActivity() as AppCompatActivity,
|
||||
viewModel.linkBbs.value?.communityEntity?.id ?: "",
|
||||
viewModel.linkBbs.value?.selectedSection?.id ?: "",
|
||||
viewModel.isModerator,
|
||||
tag ?: ""
|
||||
)
|
||||
}, delayTime)
|
||||
}
|
||||
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
requireActivity().findViewById<View>(android.R.id.content)?.viewTreeObserver?.addOnGlobalLayoutListener(
|
||||
onGlobalLayoutListener
|
||||
)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
requireActivity().findViewById<View>(android.R.id.content)?.viewTreeObserver?.removeOnGlobalLayoutListener(
|
||||
onGlobalLayoutListener
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
override fun onHandleBackPressed(): Boolean {
|
||||
showSaveDraftDialog()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun showSaveDraftDialog() {
|
||||
SensorsBridge.trackEvent("ArticleCancelDialogShow")
|
||||
DialogHelper.showDialog(
|
||||
requireContext(),
|
||||
com.gh.gamecenter.common.R.string.miui_optimization_warning_dialog_title.toResString(),
|
||||
R.string.save_to_draft_box_and_exit.toResString(),
|
||||
confirmText = R.string.save_and_exit.toResString(),
|
||||
cancelText = R.string.do_not_save.toResString(),
|
||||
confirmClickCallback = {
|
||||
SensorsBridge.trackEvent("ArticleCancelDialogClick", "button_name", "保存并退出")
|
||||
createDraft()
|
||||
},
|
||||
cancelClickCallback = {
|
||||
SensorsBridge.trackEvent("ArticleCancelDialogClick", "button_name", "不保存")
|
||||
activity?.finish()
|
||||
},
|
||||
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == ChooseSectionDialogFragment.REQUEST_CODE) {
|
||||
val section = data?.getParcelableExtra<ForumDetailEntity.Section>(EntranceConsts.KEY_DATA)
|
||||
if (section != null) {
|
||||
viewModel.changeLinkSection(section)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val TITLE_MAX_LENGTH = 20
|
||||
private const val CONTENT_MAX_LENGTH = 1000
|
||||
private const val DRAG_TIPS_SHOW_DURATION = 5000L
|
||||
|
||||
fun newInstance() = PublishImageArticleFragment()
|
||||
}
|
||||
|
||||
private class MyItemTouchCallback(
|
||||
private val viewModel: PublishImageArticleActivityViewModel
|
||||
) : ItemTouchHelper.Callback() {
|
||||
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
|
||||
return makeMovementFlags(ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT, 1)
|
||||
}
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
val adapter = recyclerView.adapter as? ImageAndTextAdapter
|
||||
if (adapter != null) {
|
||||
val position = viewHolder.bindingAdapterPosition
|
||||
val targetPosition = target.bindingAdapterPosition
|
||||
val targetItem = adapter.getItem(targetPosition)
|
||||
if (targetItem.id != ImageAndTextAdapter.INVALID_ID) {
|
||||
viewModel.swap(position, targetPosition)
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun isLongPressDragEnabled(): Boolean = true
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit
|
||||
|
||||
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
||||
super.onSelectedChanged(viewHolder, actionState)
|
||||
if (actionState == ACTION_STATE_IDLE) {
|
||||
// 拖拽完毕,刷新数据:将第一位的图片设为封面
|
||||
viewModel.refreshImages()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyItemDecoration : RecyclerView.ItemDecoration() {
|
||||
|
||||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
outRect.left = if (parent.getChildAdapterPosition(view) == 0) {
|
||||
0
|
||||
} else {
|
||||
4F.dip2px()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,118 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.baselist.LoadType
|
||||
import com.gh.gamecenter.common.baselist.PageLoader
|
||||
import com.gh.gamecenter.common.utils.toArrayList
|
||||
import com.gh.gamecenter.common.utils.toJson
|
||||
import com.gh.gamecenter.core.utils.GsonUtils
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.feature.entity.MeEntity
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleRepository
|
||||
import com.gh.gamecenter.qa.article.detail.CommentItemData
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
||||
class ImageArticleCommentViewModel(
|
||||
application: Application,
|
||||
imageArticleId: String,
|
||||
topCommentId: String
|
||||
) :
|
||||
BaseCommentViewModel(application, "", "", "", "", "", imageArticleId, topCommentId = topCommentId) {
|
||||
|
||||
private val repository = ImageArticleRepository.newInstance()
|
||||
|
||||
override fun provideDataObservable(page: Int): Observable<MutableList<CommentEntity>> {
|
||||
val map = hashMapOf<String, Any>()
|
||||
if (!isHandleTopComment && topCommentId.isNotEmpty()) {
|
||||
map["top_comment_id"] = topCommentId
|
||||
}
|
||||
return RetrofitManager.getInstance().api.getImageArticleComments(
|
||||
imageArticleId,
|
||||
currentSortType.value,
|
||||
page,
|
||||
map
|
||||
).map {
|
||||
mTotal = it.headers().get("total")?.toInt() ?: 0
|
||||
val type = object : TypeToken<List<CommentEntity>>() {}.type
|
||||
GsonUtils.gson.fromJson(it.body()?.toJson() ?: "", type)
|
||||
}
|
||||
}
|
||||
|
||||
override fun mergeResultLiveData() {
|
||||
mResultLiveData.addSource(mListLiveData) {
|
||||
mergeListData(mListLiveData.value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun mergeListData(commentList: List<CommentEntity>?, hasFilter: Boolean) {
|
||||
val mergedList = arrayListOf<CommentItemData>().apply {
|
||||
if (commentList.isNullOrEmpty() && mLoadStatusLiveData.value == LoadStatus.INIT_EMPTY) {
|
||||
add(CommentItemData(errorEmpty = true))
|
||||
} else if (commentList.isNullOrEmpty() && mLoadStatusLiveData.value == LoadStatus.INIT_FAILED) {
|
||||
add(CommentItemData(errorConnection = true))
|
||||
} else {
|
||||
commentList?.forEachIndexed { index, entity ->
|
||||
// 没有 me 会导致不能跨页面更新点赞
|
||||
if (entity.me == null) {
|
||||
entity.me = MeEntity()
|
||||
}
|
||||
handleTopComment(index, entity)
|
||||
add(CommentItemData(commentNormal = entity))
|
||||
}
|
||||
add(CommentItemData(footer = true))
|
||||
}
|
||||
}
|
||||
mResultLiveData.postValue(mergedList)
|
||||
}
|
||||
|
||||
fun insertNewestComment(newComment: CommentEntity) {
|
||||
val data = (mResultLiveData.value ?: emptyList()).toArrayList()
|
||||
val count = data.count { it.commentNormal != null }
|
||||
if (count == 0) {
|
||||
load(LoadType.REFRESH)
|
||||
return
|
||||
}
|
||||
when (currentSortType) {
|
||||
SortType.LATEST -> {
|
||||
val index = data.indexOfFirst { it.commentNormal != null }
|
||||
if (index >= 0) {
|
||||
mTotal++
|
||||
data.add(index, CommentItemData(commentNormal = newComment))
|
||||
mResultLiveData.postValue(data)
|
||||
} else {
|
||||
load(LoadType.REFRESH)
|
||||
}
|
||||
}
|
||||
|
||||
SortType.OLDEST -> {
|
||||
//根据total判断是否插入到最后
|
||||
if (count >= mTotal) {
|
||||
mTotal++
|
||||
val index = data.indexOfLast { it.commentNormal != null }
|
||||
data.add(index + 1, CommentItemData(commentNormal = newComment))
|
||||
mResultLiveData.postValue(data)
|
||||
} else {
|
||||
load(LoadType.REFRESH)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Factory(
|
||||
private val application: Application,
|
||||
private val imageArticleId: String,
|
||||
private val topCommentId: String
|
||||
) : ViewModelProvider.NewInstanceFactory() {
|
||||
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return ImageArticleCommentViewModel(application, imageArticleId, topCommentId) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,334 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.viewmodel
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Transformations
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.entity.ErrorEntity
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.observableToMain
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.common.utils.toObject
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.feature.entity.Permissions
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleRepository
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleUseCase
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel.SortType
|
||||
import io.reactivex.CompletableObserver
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.HttpException
|
||||
|
||||
class ImageArticleDetailViewModel : ViewModel() {
|
||||
|
||||
private val repository = ImageArticleRepository.newInstance()
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
var imageArticleId: String = ""
|
||||
|
||||
private val useCase = ImageArticleUseCase(repository, compositeDisposable)
|
||||
|
||||
private val _imageArticleDetailEntity = MutableLiveData<ImageArticleEntity>()
|
||||
val imageArticleDetailEntity: LiveData<ImageArticleEntity> = _imageArticleDetailEntity
|
||||
|
||||
val isUserFollowed: LiveData<Boolean> =
|
||||
Transformations.distinctUntilChanged(Transformations.map(imageArticleDetailEntity) {
|
||||
it.me.isFollower
|
||||
})
|
||||
|
||||
fun followUser() {
|
||||
val isFollowed = isUserFollowed.value ?: false
|
||||
val userId = imageArticleDetailEntity.value?.user?.id ?: ""
|
||||
SensorsBridge.trackUserFollowClick(
|
||||
userId = userId,
|
||||
userName = imageArticleDetailEntity.value?.user?.name ?: "",
|
||||
buttonName = if (isFollowed) "已关注" else "关注"
|
||||
)
|
||||
repository.followUser(!isFollowed, userId)
|
||||
.compose(observableToMain())
|
||||
.subscribe(object : Response<ResponseBody>() {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
compositeDisposable.add(d)
|
||||
}
|
||||
|
||||
override fun onResponse(response: ResponseBody?) {
|
||||
updateImageArticle {
|
||||
it.me.isFollower = !isFollowed
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
val commentCount: LiveData<Int> =
|
||||
Transformations.distinctUntilChanged(Transformations.map(imageArticleDetailEntity) {
|
||||
it.count.comment
|
||||
})
|
||||
|
||||
fun updateComment(commentId: String, commentCount: Int) {
|
||||
updateImageArticle {
|
||||
it.count.comment = commentCount
|
||||
}
|
||||
ImageArticleUseCase.notifyCommentChanged(imageArticleId, commentCount)
|
||||
if (commentId.isNotEmpty()) {
|
||||
insertNewestComment(commentId)
|
||||
}
|
||||
}
|
||||
|
||||
private val _insertNewestCommentAction = MutableLiveData<Event<CommentEntity>>()
|
||||
val insertNewestCommentAction: LiveData<Event<CommentEntity>> = _insertNewestCommentAction
|
||||
private fun insertNewestComment(commentId: String) {
|
||||
// 将刚刚评论的内容插入到评论列表中
|
||||
repository.getSingleCommentById(commentId)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<CommentEntity>() {
|
||||
override fun onSuccess(data: CommentEntity) {
|
||||
_insertNewestCommentAction.value = Event(data)
|
||||
}
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
val vote: LiveData<Pair<Boolean, Int>> =
|
||||
Transformations.distinctUntilChanged(Transformations.map(imageArticleDetailEntity) {
|
||||
it.me.isCommunityArticleVote to it.count.vote
|
||||
})
|
||||
|
||||
fun vote() {
|
||||
val isVoted = vote.value?.first ?: false
|
||||
useCase.voteImageArticle(imageArticleId, !isVoted)
|
||||
|
||||
val imageArticle = imageArticleDetailEntity.value ?: return
|
||||
SensorsBridge.trackArticleLikeClick(
|
||||
customerType = imageArticle.user.auth?.text ?: "",
|
||||
articleId = imageArticle.id,
|
||||
bbsId = imageArticle.community?.id ?: "",
|
||||
bbsType = imageArticle.community?.typeChinese ?: "综合论坛",
|
||||
activityTag = "",
|
||||
gameForumType = imageArticle.community?.game?.categoryChinese ?: "",
|
||||
articleType = "图文",
|
||||
buttonName = if (isVoted) "取消点赞" else "赞同"
|
||||
)
|
||||
}
|
||||
|
||||
private val _pageStatus = MutableLiveData<LoadStatus>()
|
||||
val pageStatus: LiveData<LoadStatus> = _pageStatus
|
||||
|
||||
fun loadImageArticleDetail(imageArticleId: String, recommendId: String) {
|
||||
_pageStatus.value = LoadStatus.INIT_LOADING
|
||||
this.imageArticleId = imageArticleId
|
||||
repository.loadImageArticleDetail(imageArticleId)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ImageArticleEntity>() {
|
||||
override fun onSuccess(data: ImageArticleEntity) {
|
||||
_pageStatus.value = LoadStatus.INIT_LOADED
|
||||
setImageArticle(data)
|
||||
NewLogUtils.logForumContentBrowser(imageArticleId, "bbs_article", recommendId)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
val error =
|
||||
(exception as? HttpException)?.response()?.errorBody()?.string()?.toObject<ErrorEntity>()
|
||||
if (error != null && error.code == 404001) {
|
||||
_pageStatus.value = LoadStatus.INIT_EMPTY
|
||||
} else {
|
||||
_pageStatus.value = LoadStatus.INIT_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
private val _sortType = MutableLiveData<Event<SortType>>()
|
||||
val sortType: LiveData<Event<SortType>> = _sortType
|
||||
fun changeSort(newSort: SortType) {
|
||||
_sortType.value = Event(newSort)
|
||||
}
|
||||
|
||||
val isBbsFollowed: LiveData<Boolean> =
|
||||
Transformations.distinctUntilChanged(Transformations.map(imageArticleDetailEntity) {
|
||||
it.community?.isFollowed ?: false
|
||||
})
|
||||
|
||||
fun followBbs(communityId: String) {
|
||||
val isFollowed = isBbsFollowed.value ?: false
|
||||
repository.followBbs(communityId, !isFollowed)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
updateImageArticle {
|
||||
it.community?.isFollowed = !isFollowed
|
||||
}
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
val isFavorite: LiveData<Boolean> =
|
||||
Transformations.distinctUntilChanged(Transformations.map(imageArticleDetailEntity) {
|
||||
it.me.isFavorite
|
||||
})
|
||||
|
||||
fun collect() {
|
||||
val imageArticleId = imageArticleId
|
||||
val isCollected = isFavorite.value ?: false
|
||||
repository.collect(imageArticleId, !isCollected)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : CompletableObserver {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
compositeDisposable.add(d)
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
updateImageArticle {
|
||||
it.me.isFavorite = !isCollected
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) = Unit
|
||||
|
||||
})
|
||||
|
||||
val imageArticle = imageArticleDetailEntity.value ?: return
|
||||
SensorsBridge.trackArticleCollectionClick(
|
||||
customerType = imageArticle.user.auth?.text ?: "",
|
||||
articleId = imageArticle.id,
|
||||
bbsId = imageArticle.community?.id ?: "",
|
||||
bbsType = imageArticle.community?.typeChinese ?: "综合论坛",
|
||||
activityTag = "",
|
||||
gameForumType = imageArticle.community?.game?.categoryChinese ?: "",
|
||||
articleType = "图文",
|
||||
buttonName = if (isCollected) "已收藏" else "收藏"
|
||||
)
|
||||
}
|
||||
|
||||
fun setImageArticle(newData: ImageArticleEntity) {
|
||||
_imageArticleDetailEntity.value = newData
|
||||
}
|
||||
|
||||
fun updateImageArticle(block: (ImageArticleEntity) -> Unit) {
|
||||
val data = imageArticleDetailEntity.value ?: return
|
||||
block(data)
|
||||
_imageArticleDetailEntity.value = data
|
||||
}
|
||||
|
||||
private val _applyHighlightAction = MutableLiveData<Event<Boolean>>()
|
||||
val applyHighlightAction: LiveData<Event<Boolean>> = _applyHighlightAction
|
||||
fun applyHighlightForImageArticle() {
|
||||
repository.applyHighlightForImageArticle(imageArticleId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : CompletableObserver {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
compositeDisposable.add(d)
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
imageArticleDetailEntity.value?.choicenessStatus = "apply"
|
||||
_applyHighlightAction.value = Event(true)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
_applyHighlightAction.value = Event(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private val _addHighlightAction = MutableLiveData<Event<Int>>()
|
||||
val addHighlightAction: LiveData<Event<Int>> = _addHighlightAction
|
||||
fun addHighlight(isAdd: Boolean) {
|
||||
repository.addHighlight(isAdd, imageArticleId)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
val imageArticle = imageArticleDetailEntity.value ?: return
|
||||
if (isAdd) {
|
||||
if (imageArticle.me.moderatorPermissions.choicenessImageArticle == Permissions.REPORTER) {
|
||||
_addHighlightAction.value = Event(R.string.apply_successfully)
|
||||
updateImageArticle {
|
||||
it.choicenessStatus = "apply"
|
||||
}
|
||||
} else {
|
||||
_addHighlightAction.value = Event(R.string.operation_successful)
|
||||
updateImageArticle {
|
||||
it.choicenessStatus = "pass"
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
if (imageArticle.me.moderatorPermissions.cancelChoicenessImageArticle == Permissions.REPORTER) {
|
||||
_addHighlightAction.value = Event(R.string.apply_successfully)
|
||||
} else {
|
||||
_addHighlightAction.value = Event(R.string.operation_successful)
|
||||
updateImageArticle {
|
||||
it.choicenessStatus = "cancel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
_addHighlightAction.value = Event(R.string.permission_error)
|
||||
}
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
private val _deleteOrHideImageArticleSuccessfully = MutableLiveData<Event<Pair<Boolean, Int>>>()
|
||||
val deleteOrHideImageArticleSuccessfully: LiveData<Event<Pair<Boolean, Int>>> =
|
||||
_deleteOrHideImageArticleSuccessfully
|
||||
|
||||
fun deleteOrHideImageArticle() {
|
||||
repository.deleteOrHideImageArticle(imageArticleId)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
val imageArticle = imageArticleDetailEntity.value ?: return
|
||||
val toastResId = if (imageArticle.me.isModerator) {
|
||||
if (imageArticle.me.moderatorPermissions.hideImageArticle == Permissions.REPORTER) {
|
||||
R.string.apply_successfully
|
||||
} else {
|
||||
R.string.hidden
|
||||
}
|
||||
} else {
|
||||
R.string.deleted
|
||||
}
|
||||
ImageArticleUseCase.notifyDataDeleted(imageArticleId)
|
||||
_deleteOrHideImageArticleSuccessfully.value = Event(true to toastResId)
|
||||
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
super.onFailure(exception)
|
||||
_deleteOrHideImageArticleSuccessfully.value = Event(false to R.string.permission_error_and_retry)
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
fun imageArticleChanged(changed: EBImageArticleChanged) {
|
||||
when {
|
||||
changed is EBImageArticleChanged.VoteChanged -> {
|
||||
updateImageArticle {
|
||||
it.me.isCommunityArticleVote = changed.isVoted
|
||||
it.count.vote = changed.count
|
||||
}
|
||||
}
|
||||
|
||||
changed is EBImageArticleChanged.DataChanged -> {
|
||||
setImageArticle(changed.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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,77 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.viewmodel
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.gh.gamecenter.common.baselist.PageLoader
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.eventbus.EBImageArticleChanged
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleRepository
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleUseCase
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
||||
class ImageArticleHomeViewModel : ViewModel() {
|
||||
|
||||
private val repository = ImageArticleRepository.newInstance()
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
val useCase = ImageArticleUseCase(repository, compositeDisposable)
|
||||
|
||||
val pageLoader = PageLoader(compositeDisposable = compositeDisposable) { pageNo, _ ->
|
||||
repository.loadRecommends(pageNo)
|
||||
}
|
||||
|
||||
fun initLoad() {
|
||||
pageLoader.loadInit()
|
||||
}
|
||||
|
||||
private val _imageDetailDestination = MutableLiveData<Event<ImageArticleEntity>>()
|
||||
val imageDetailDestination: LiveData<Event<ImageArticleEntity>> = _imageDetailDestination
|
||||
fun navigateToImageArticleDetailPage(imageArticleEntity: ImageArticleEntity) {
|
||||
_imageDetailDestination.value = Event(imageArticleEntity)
|
||||
}
|
||||
|
||||
fun loadMore() {
|
||||
pageLoader.loadMore()
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
fun voteChanged(changed: EBImageArticleChanged.VoteChanged) {
|
||||
val oldData = pageLoader.dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val position = newData.indexOfFirst { it.id == changed.id }
|
||||
if (position != -1) {
|
||||
val oldItem = newData[position]
|
||||
val oldCount = oldItem.count.vote
|
||||
val newCount = if (changed.isVoted) {
|
||||
oldCount + 1
|
||||
} else {
|
||||
oldCount - 1
|
||||
}
|
||||
val newItem = oldItem.copy(
|
||||
_me = oldItem.me.copy(isCommunityArticleVote = changed.isVoted),
|
||||
_count = oldItem.count.copy(vote = newCount)
|
||||
)
|
||||
newData[position] = newItem
|
||||
pageLoader.updateData(newData)
|
||||
}
|
||||
}
|
||||
|
||||
fun itemChanged(changed: EBImageArticleChanged.DataChanged) {
|
||||
val oldData = pageLoader.dataList.value ?: return
|
||||
val newData = oldData.toMutableList()
|
||||
val position = newData.indexOfFirst { it.id == changed.data.id }
|
||||
if (position != -1) {
|
||||
newData[position] = changed.data
|
||||
pageLoader.updateData(newData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -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,234 @@
|
||||
package com.gh.gamecenter.forum.home.recommend.viewmodel
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.observableToMain
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.common.utils.toRequestBody
|
||||
import com.gh.gamecenter.entity.ForumDetailEntity
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.entity.PublishImageTextRequest
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleRepository
|
||||
import com.gh.gamecenter.forum.home.recommend.ImageArticleUseCase
|
||||
import com.gh.gamecenter.forum.home.recommend.adapter.ImageAndTextAdapter
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.HttpException
|
||||
|
||||
class PublishImageArticleViewModel : ViewModel() {
|
||||
|
||||
private val repository = ImageArticleRepository.newInstance()
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
var isModerator: Boolean = false
|
||||
|
||||
private var imageArticle: ImageArticleEntity? = null
|
||||
|
||||
val isCreating: Boolean
|
||||
get() = imageArticle == null || imageArticle!!.isDraft
|
||||
|
||||
private val _chooseImageAction = MutableLiveData<Event<Unit>>()
|
||||
val chooseImageAction: LiveData<Event<Unit>> = _chooseImageAction
|
||||
fun chooseImage() {
|
||||
_chooseImageAction.value = Event(Unit)
|
||||
}
|
||||
|
||||
private val _removeImageAction = MutableLiveData<Event<Int>>()
|
||||
val removeImageAction: LiveData<Event<Int>> = _removeImageAction
|
||||
fun removeImage(position: Int) {
|
||||
_removeImageAction.value = Event(position)
|
||||
}
|
||||
|
||||
private val _linkBbs = MutableLiveData<LinkBbs>()
|
||||
val linkBbs: LiveData<LinkBbs> = _linkBbs
|
||||
fun changeLinkBbs(newCommunity: CommunityEntity?) {
|
||||
if (newCommunity == null) {
|
||||
_linkBbs.value = LinkBbs(null, false, null)
|
||||
return
|
||||
}
|
||||
val oldCommunity = linkBbs.value?.communityEntity
|
||||
if (newCommunity != oldCommunity) {
|
||||
// 用户重新选择了关联论坛
|
||||
_linkBbs.value = LinkBbs(newCommunity, false, null)
|
||||
getForumSections(newCommunity)
|
||||
getModeratorsInfo(newCommunity.id)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getForumSections(newCommunity: CommunityEntity) {
|
||||
repository.checkHasSections(newCommunity.id)
|
||||
.compose(observableToMain())
|
||||
.subscribe(object : Response<Boolean>() {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
compositeDisposable.add(d)
|
||||
}
|
||||
|
||||
override fun onResponse(response: Boolean?) {
|
||||
if (response == true) {
|
||||
// 此论坛有子板块,更新关联论坛ui状态
|
||||
_linkBbs.value = LinkBbs(newCommunity, true, null)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
private fun getModeratorsInfo(bbsId: String) {
|
||||
repository.getModeratorsInfo(bbsId)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<Boolean>() {
|
||||
override fun onSuccess(data: Boolean) {
|
||||
isModerator = data
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
fun changeLinkSection(section: ForumDetailEntity.Section?) {
|
||||
val oldLink = linkBbs.value
|
||||
if (oldLink != null) {
|
||||
_linkBbs.value = oldLink.copy(selectedSection = section)
|
||||
}
|
||||
}
|
||||
|
||||
private val _draftCreated = MutableLiveData<Event<Boolean>>()
|
||||
val draftCreated: LiveData<Event<Boolean>> = _draftCreated
|
||||
fun createOrEditDraft(title: String, content: String, localImages: List<ImageAndTextAdapter.LocalImage>) {
|
||||
val request = createPublishRequest(title, content)
|
||||
repository.createOrEditDraft(request, localImages)
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
_draftCreated.value = Event(true)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
_draftCreated.value = Event(false)
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
private val _imageTextPublished = MutableLiveData<Event<Pair<Boolean, String>>>()
|
||||
val imageTextPublished: LiveData<Event<Pair<Boolean, String>>> = _imageTextPublished
|
||||
fun publishImageText(title: String, content: String, images: List<ImageAndTextAdapter.LocalImage>) {
|
||||
val request = createPublishRequest(title, content)
|
||||
SensorsBridge.trackEvent(
|
||||
"ArticlePostClick",
|
||||
"bbs_id",
|
||||
request.communityId,
|
||||
"bbs_type",
|
||||
request.communityType,
|
||||
"activity_tag",
|
||||
"",
|
||||
"article_type",
|
||||
"图文"
|
||||
)
|
||||
if (isCreating) {
|
||||
repository.publishImageText(request, images)
|
||||
} else {
|
||||
repository.editImageArticle(imageArticle!!.id, request, images)
|
||||
}
|
||||
.compose(singleToMain())
|
||||
.subscribe(object : BiResponse<ImageArticleEntity>() {
|
||||
override fun onSuccess(data: ImageArticleEntity) {
|
||||
if (isCreating) {
|
||||
ImageArticleUseCase.notifyDataCreated(data, request.draftId)
|
||||
} else {
|
||||
ImageArticleUseCase.notifyDataEdited(data)
|
||||
}
|
||||
_imageTextPublished.value = Event(true to "")
|
||||
|
||||
val community = data.community
|
||||
SensorsBridge.trackArticlePostResult(
|
||||
postResult = "成功",
|
||||
bbsId = community?.id ?: "",
|
||||
bbsType = if (community != null) {
|
||||
if (data.community.type == "official_bbs") "综合论坛" else "游戏论坛"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
activityTag = "",
|
||||
articleType = "图文",
|
||||
customerType = UserManager.getInstance().userInfoEntity?.auth?.text ?: "",
|
||||
gameForumType = community?.game?.categoryChinese ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
val errorString = try {
|
||||
(exception as? HttpException)?.response()?.errorBody()?.string() ?: ""
|
||||
} catch (e1: Exception) {
|
||||
e1.printStackTrace()
|
||||
""
|
||||
}
|
||||
_imageTextPublished.value = Event(false to errorString)
|
||||
}
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
private fun createPublishRequest(title: String, content: String): PublishImageTextRequest {
|
||||
val draftId = if (imageArticle?.isDraft == true) {
|
||||
// 发布或者编辑草稿
|
||||
imageArticle?.id ?: ""
|
||||
} else {
|
||||
""
|
||||
}
|
||||
val selectedBbs = linkBbs.value
|
||||
val communityId = selectedBbs?.communityEntity?.id ?: ""
|
||||
val communityType = selectedBbs?.communityEntity?.type ?: ""
|
||||
val sectionId = selectedBbs?.selectedSection?.id ?: ""
|
||||
val sectionIds = if (sectionId.isNotEmpty()) listOf(sectionId) else listOf()
|
||||
return PublishImageTextRequest(title, content, communityType, communityId, sectionIds, emptyList(), draftId)
|
||||
}
|
||||
|
||||
private val _editImageArticle = MutableLiveData<Event<ImageArticleEntity>>()
|
||||
val editImageArticle: LiveData<Event<ImageArticleEntity>> = _editImageArticle
|
||||
fun setEditImageArticle(imageArticleEntity: ImageArticleEntity?) {
|
||||
imageArticleEntity ?: return
|
||||
imageArticle = imageArticleEntity
|
||||
val community = imageArticleEntity.community?.toCommunityEntity()
|
||||
val section = imageArticleEntity.sections.firstOrNull()
|
||||
val game = imageArticleEntity.community?.game
|
||||
val icon = if (game == null) {
|
||||
community?.icon ?: ""
|
||||
} else {
|
||||
game.rawIcon ?: game.icon
|
||||
}
|
||||
community?.icon = icon
|
||||
when {
|
||||
community != null && section != null -> { // 绑定了论坛和子板块
|
||||
val formSection = ForumDetailEntity.Section(section.id, name = section.name)
|
||||
_linkBbs.value = LinkBbs(community, hasSection = true, formSection)
|
||||
}
|
||||
|
||||
community != null -> { // 只绑定了论坛未绑定子板块
|
||||
changeLinkBbs(community)
|
||||
}
|
||||
|
||||
else -> { // 未绑定论坛
|
||||
changeLinkBbs(null)
|
||||
}
|
||||
}
|
||||
|
||||
changeLinkBbs(community)
|
||||
_editImageArticle.value = Event(imageArticleEntity)
|
||||
}
|
||||
|
||||
|
||||
data class LinkBbs(
|
||||
val communityEntity: CommunityEntity?,
|
||||
val hasSection: Boolean,
|
||||
val selectedSection: ForumDetailEntity.Section? = null
|
||||
)
|
||||
}
|
||||
@ -51,7 +51,7 @@ open class GameCollectionDetailViewModel(
|
||||
gameCollectionId: String,
|
||||
topCommentId: String = ""
|
||||
) :
|
||||
BaseCommentViewModel(application, "", "", "", "", gameCollectionId, topCommentId) {
|
||||
BaseCommentViewModel(application, "", "", "", "", gameCollectionId, topCommentId = topCommentId) {
|
||||
|
||||
var firstItemInitOverLiveData = MutableLiveData<Boolean>()
|
||||
var followLiveData = MutableLiveData<Boolean>()
|
||||
|
||||
@ -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,29 +36,42 @@ 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)
|
||||
|
||||
if (historyEntity.community.type == "official_bbs") {
|
||||
forumIcon?.displayGameIcon(historyEntity.community.icon, null)
|
||||
} else {
|
||||
forumIcon?.displayGameIcon(
|
||||
historyEntity.community.game?.getIcon(),
|
||||
historyEntity.community.game?.iconSubscript,
|
||||
historyEntity.community.game?.iconFloat
|
||||
)
|
||||
}
|
||||
|
||||
forumNameContainer?.setOnClickListener {
|
||||
MtaHelper.onEvent(getEventId(entrance), getKey(entrance), historyEntity.community.name)
|
||||
itemView.context.startActivity(
|
||||
ForumDetailActivity.getIntent(
|
||||
itemView.context,
|
||||
historyEntity.community.id,
|
||||
entrance
|
||||
forumNameContainer?.visibleIf(historyEntity.community.id.isNotBlank()) {
|
||||
if (historyEntity.community.type == "official_bbs") {
|
||||
forumIcon?.displayGameIcon(historyEntity.community.icon, null)
|
||||
} else {
|
||||
forumIcon?.displayGameIcon(
|
||||
historyEntity.community.game?.getIcon(),
|
||||
historyEntity.community.game?.iconSubscript,
|
||||
historyEntity.community.game?.iconFloat
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
forumNameContainer?.setOnClickListener {
|
||||
MtaHelper.onEvent(getEventId(entrance), getKey(entrance), historyEntity.community.name)
|
||||
itemView.context.startActivity(
|
||||
ForumDetailActivity.getIntent(
|
||||
itemView.context,
|
||||
historyEntity.community.id,
|
||||
entrance
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val answer = AnswerEntity()
|
||||
|
||||
@ -1,57 +1,55 @@
|
||||
package com.gh.gamecenter.personalhome.home
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.net.Uri
|
||||
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(
|
||||
context: Context,
|
||||
private val mListViewModel: UserHistoryViewModel,
|
||||
private val mEntrance: String,
|
||||
private val itemClickCallback: (historyEntity: PersonalHistoryEntity, position: Int) -> Unit
|
||||
private val itemClickCallback: (historyEntity: PersonalHistoryEntity, position: Int) -> Unit,
|
||||
) : ListAdapter<PersonalHistoryEntity>(context) {
|
||||
|
||||
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 +59,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 +72,20 @@ class UserHistoryAdapter(
|
||||
PersonalHomeRatingViewHolder(PersonalHomeRatingBinding.bind(view))
|
||||
}
|
||||
|
||||
ITEM_TYPE_IMAGE_ARTICLE -> {
|
||||
MyImageArticleViewHolder(parent.toBinding(),
|
||||
object : MyImageArticleViewHolder.OnMyArticleImageListener {
|
||||
override fun navigateToImageArticleDetailPage(item: PersonalHistoryEntity, position: Int) {
|
||||
itemClickCallback(item, position)
|
||||
}
|
||||
|
||||
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 +93,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 +122,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, position, 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) {
|
||||
@ -114,7 +157,10 @@ class UserHistoryAdapter(
|
||||
val m = Pattern.compile(RatingEditActivity.LABEL_REGEX).matcher(historyEntity.comment.content)
|
||||
if (m.find()) {
|
||||
val contents =
|
||||
TextHelper.getCommentLabelSpannableStringBuilder(historyEntity.comment.content, com.gh.gamecenter.common.R.color.text_theme)
|
||||
TextHelper.getCommentLabelSpannableStringBuilder(
|
||||
historyEntity.comment.content,
|
||||
com.gh.gamecenter.common.R.color.text_theme
|
||||
)
|
||||
holder.binding.content.setTextWithHighlightedTextWrappedInsideWrapper(
|
||||
text = contents,
|
||||
highlightedTextClickListener = TextHelper.DirectToWebViewHighlightedTextClick(mContext, mEntrance)
|
||||
@ -159,4 +205,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
|
||||
}
|
||||
}
|
||||
@ -2,26 +2,38 @@ package com.gh.gamecenter.personalhome.home
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
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 +42,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 +93,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 +224,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 +286,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 +374,13 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
104,
|
||||
position
|
||||
)
|
||||
} else if (historyEntity.type == "image_article") {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, historyEntity.id)
|
||||
.appendQueryParameter(EntranceConsts.KEY_SOURCE_ENTRANCE, "个人主页-发布")
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
} else if (!historyEntity.type.contains("question")) {
|
||||
val intent = NewQuestionDetailActivity.getSpecifiedCommentIntent(
|
||||
requireContext(),
|
||||
@ -320,7 +413,7 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
NewFlatLogUtils.logClickSelfPublish(
|
||||
historyEntity.type,
|
||||
historyEntity.id,
|
||||
historyEntity.user?.id ?: "",
|
||||
historyEntity.user.id ?: "",
|
||||
getCurrentTabName()
|
||||
)
|
||||
}
|
||||
@ -329,9 +422,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 +458,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 +524,7 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
me.isVoted = resultData?.me?.isVoted ?: false
|
||||
}
|
||||
}
|
||||
|
||||
101 -> {
|
||||
val resultData =
|
||||
data.getParcelableExtra<ArticleDetailEntity>(ArticleDetailEntity::class.java.simpleName)
|
||||
@ -411,6 +538,7 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
me.isCommunityArticleVote = resultData?.me?.isCommunityArticleVote ?: false
|
||||
}
|
||||
}
|
||||
|
||||
102 -> {
|
||||
val resultData =
|
||||
data.getParcelableExtra<CommentEntity>(CommentEntity::class.java.simpleName)
|
||||
@ -421,6 +549,8 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
me.isAnswerVoted = resultData?.me?.isCommentVoted ?: false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
103 -> {
|
||||
val resultData =
|
||||
data.getParcelableExtra<QuestionsDetailEntity>(QuestionsDetailEntity::class.java.simpleName)
|
||||
@ -431,6 +561,7 @@ class UserHistoryFragment : ListFragment<PersonalHistoryEntity, UserHistoryViewM
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
104 -> {
|
||||
val resultData =
|
||||
data.getParcelableExtra<ForumVideoEntity>(ForumVideoEntity::class.java.simpleName)
|
||||
@ -468,6 +599,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"),
|
||||
|
||||
@ -1,20 +1,25 @@
|
||||
package com.gh.gamecenter.qa.answer
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.net.Uri
|
||||
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 +29,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
|
||||
@ -150,6 +156,7 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
|
||||
open fun bindCommendAndVote(entity: CommunityItemData, entrance: String, position: Int? = null) {
|
||||
binNormalView(entity)
|
||||
|
||||
forumNameContainer?.visibleIf(entity.community.id.isNotBlank())
|
||||
if (entity.community.type == "official_bbs") {
|
||||
forumIcon?.displayGameIcon(entity.community.icon, null)
|
||||
} else {
|
||||
@ -218,6 +225,7 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
|
||||
val commentType = when (entity.type) {
|
||||
"community_article" -> "帖子评论"
|
||||
"video" -> "视频帖评论"
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> "图文"
|
||||
else -> "提问帖评论"
|
||||
}
|
||||
NewLogUtils.logRecommendFeedContentClick(
|
||||
@ -267,6 +275,14 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
|
||||
)
|
||||
}
|
||||
|
||||
ImageArticleEntity.IMAGE_ARTICLE_TYPE -> {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, entity.id)
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
}
|
||||
|
||||
else -> {
|
||||
val communityId = entity.community.id
|
||||
val intent = ArticleDetailActivity.getCommentIntent(
|
||||
@ -398,19 +414,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 +508,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("论坛详情")) {
|
||||
@ -1041,7 +1041,7 @@ class ArticleDetailFragment : BaseCommentFragment<CommentItemData, ArticleDetail
|
||||
"帖子详情页", "slide_article_detail_page", (filterView?.top ?: 0) > 0
|
||||
)
|
||||
if ((filterView?.top ?: 0) > 0) {
|
||||
NewLogUtils.logCommentAreaEnter("帖子")
|
||||
NewLogUtils.logCommentAreaEnter("图文")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.gamecenter.qa.article.detail
|
||||
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.ArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
@ -18,7 +19,8 @@ class CommentItemData(
|
||||
var filter: Boolean? = null,
|
||||
var errorConnection: Boolean? = null,
|
||||
var errorEmpty: Boolean? = null,
|
||||
var footer: Boolean? = null
|
||||
var footer: Boolean? = null,
|
||||
val imageArticleDetail: ImageArticleEntity? = null,
|
||||
) {
|
||||
class CommentPagerData(val totalCommentNum: Int = 0, val showRelatedContent: Boolean = true)
|
||||
}
|
||||
@ -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,19 @@ class CommentActivity : BaseActivity() {
|
||||
commentCallback
|
||||
)
|
||||
}
|
||||
|
||||
imageArticleId.isNotEmpty() -> {
|
||||
NewCommentFragment.getImageArticleCommentInstance(
|
||||
imageArticleId,
|
||||
showKeyboard,
|
||||
commentCount,
|
||||
mShowInputOnly,
|
||||
commentEntity,
|
||||
useReplyApi,
|
||||
commentCallback
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
NewCommentFragment.getVideoCommentInstance(
|
||||
videoId,
|
||||
@ -197,6 +216,8 @@ class CommentActivity : BaseActivity() {
|
||||
|
||||
const val REQUEST_CODE = 8123
|
||||
|
||||
const val IMAGE_ARTICLE_ID = "image_article_id"
|
||||
|
||||
@JvmStatic
|
||||
fun getAnswerCommentIntent(
|
||||
context: Context,
|
||||
@ -280,6 +301,7 @@ class CommentActivity : BaseActivity() {
|
||||
articleId: String,
|
||||
videoId: String,
|
||||
questionId: String,
|
||||
imageArticleId: String,
|
||||
showKeyboard: Boolean = false,
|
||||
position: Int = -1,
|
||||
entrance: String,
|
||||
@ -290,6 +312,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 +469,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 +514,30 @@ 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,
|
||||
commentEntity: CommentEntity? = null,
|
||||
): 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)
|
||||
intent.putExtra(COMMENT_ENTITY, commentEntity)
|
||||
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,
|
||||
@ -230,6 +231,7 @@ class NewCommentAdapter(
|
||||
mCommentOptionClickListener
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
//do nothing
|
||||
}
|
||||
@ -251,6 +253,9 @@ class NewCommentAdapter(
|
||||
|
||||
CommentType.GAME_COLLECTION,
|
||||
CommentType.GAME_COLLECTION_CONVERSATION -> "游戏单详情-评论管理"
|
||||
|
||||
CommentType.IMAGE_ARTICLE,
|
||||
CommentType.IMAGE_ARTICLE_CONVERSATION -> "图文详情-评论管理"
|
||||
}
|
||||
|
||||
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_CONVERSATION
|
||||
else -> CommentType.VIDEO_CONVERSATION
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import com.gh.gamecenter.common.base.activity.ToolBarActivity
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.updateStatusBarColor
|
||||
import com.gh.gamecenter.gamecollection.detail.conversation.GameCollectionCommentConversationFragment
|
||||
import com.gh.gamecenter.qa.comment.CommentActivity.Companion.IMAGE_ARTICLE_ID
|
||||
import com.gh.gamecenter.qa.comment.conversation.CommentConversationFragment
|
||||
|
||||
/**
|
||||
@ -123,6 +124,26 @@ class NewCommentDetailActivity : ToolBarActivity() {
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getImageArticleCommentIntent(
|
||||
context: Context,
|
||||
commentId:String,
|
||||
imageArticleId:String,
|
||||
topCommentId:String,
|
||||
entrance: String,
|
||||
path:String
|
||||
):Intent{
|
||||
val bundle = getCommonBundle(commentId, topCommentId, entrance, path).apply {
|
||||
putString(IMAGE_ARTICLE_ID,imageArticleId)
|
||||
}
|
||||
return getTargetIntent(
|
||||
context,
|
||||
NewCommentDetailActivity::class.java,
|
||||
CommentConversationFragment::class.java,
|
||||
bundle
|
||||
)
|
||||
}
|
||||
|
||||
private fun getCommonBundle(
|
||||
commentId: String,
|
||||
topCommentId: String,
|
||||
|
||||
@ -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,9 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
CommentType.GAME_COLLECTION,
|
||||
CommentType.GAME_COLLECTION_CONVERSATION -> "游戏单评论及回复"
|
||||
|
||||
CommentType.IMAGE_ARTICLE,
|
||||
CommentType.IMAGE_ARTICLE_CONVERSATION-> "图文的评论和回复"
|
||||
|
||||
else -> ""
|
||||
}
|
||||
ErrorHelper.handleError(
|
||||
@ -412,7 +418,8 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
gameCollectionId = mGameCollectionId,
|
||||
rootCommentId = mRootCommentId,
|
||||
commentType = mCommentType,
|
||||
isVideoAuthor = mIsVideoAuthor
|
||||
isVideoAuthor = mIsVideoAuthor,
|
||||
imageArticleId = mImageArticleId
|
||||
)
|
||||
)
|
||||
return mViewModel
|
||||
@ -435,6 +442,9 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
|
||||
CommentType.GAME_COLLECTION,
|
||||
CommentType.GAME_COLLECTION_CONVERSATION -> "(游戏单详情-评论列表)"
|
||||
|
||||
CommentType.IMAGE_ARTICLE,
|
||||
CommentType.IMAGE_ARTICLE_CONVERSATION -> "图文详情-评论列表"
|
||||
}
|
||||
mAdapter = NewCommentAdapter(requireContext(), mViewModel, true, this, this, entrance)
|
||||
}
|
||||
@ -598,6 +608,16 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
"游戏单详情-评论-回复"
|
||||
}
|
||||
}
|
||||
|
||||
CommentType.IMAGE_ARTICLE,
|
||||
CommentType.IMAGE_ARTICLE_CONVERSATION-> {
|
||||
if(mCommentEntity == null){
|
||||
"图文详情-评论-写评论"
|
||||
}else{
|
||||
"图文详情-评论-回复"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -625,7 +645,12 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
mAnswerContent.background =
|
||||
ContextCompat.getDrawable(requireActivity(), R.drawable.bg_shape_white_radius_10_top_only)
|
||||
} else {
|
||||
mAnswerContent.setBackgroundColor(ContextCompat.getColor(requireActivity(), com.gh.gamecenter.common.R.color.white))
|
||||
mAnswerContent.setBackgroundColor(
|
||||
ContextCompat.getColor(
|
||||
requireActivity(),
|
||||
com.gh.gamecenter.common.R.color.white
|
||||
)
|
||||
)
|
||||
}
|
||||
mScrollViewParams.width = if (isPopup) LinearLayout.LayoutParams.MATCH_PARENT else 0
|
||||
mScrollViewParams.height = if (isPopup) 64f.dip2px() else 28f.dip2px()
|
||||
@ -693,7 +718,10 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
if (picturePath != null) {
|
||||
if (File(picturePath).length() > ImageUtils.getUploadFileMaxSize()) {
|
||||
val count = ImageUtils.getUploadFileMaxSize() / 1024 / 1024
|
||||
Utils.toast(requireContext(), requireContext().getString(com.gh.gamecenter.common.R.string.pic_max_hint, count))
|
||||
Utils.toast(
|
||||
requireContext(),
|
||||
requireContext().getString(com.gh.gamecenter.common.R.string.pic_max_hint, count)
|
||||
)
|
||||
continue
|
||||
}
|
||||
Utils.log("picturePath = $picturePath")
|
||||
@ -945,5 +973,35 @@ open class NewCommentFragment : ListFragment<CommentEntity, NewCommentViewModel>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun getImageArticleCommentInstance(
|
||||
imageArticleId: String,
|
||||
showSoftKeyboardOnStartUp: Boolean,
|
||||
commentCount: Int,
|
||||
showInputOnly: Boolean,
|
||||
commentEntity: CommentEntity?,
|
||||
useReplyApi: Boolean,
|
||||
listener: CommentActivity.CommentListener
|
||||
): NewCommentFragment {
|
||||
val commentType = if (useReplyApi) {
|
||||
CommentType.IMAGE_ARTICLE_CONVERSATION
|
||||
} else {
|
||||
CommentType.IMAGE_ARTICLE
|
||||
}
|
||||
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,
|
||||
SHOW_INPUT_ONLY to showInputOnly,
|
||||
COMMENT_ENTITY to commentEntity
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.common.baselist.ListViewModel
|
||||
import com.gh.gamecenter.common.retrofit.ApiResponse
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
@ -16,6 +17,7 @@ import com.gh.gamecenter.common.syncpage.SyncPageRepository
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.GsonUtils
|
||||
import com.gh.gamecenter.entity.CommentDraft
|
||||
import com.gh.gamecenter.entity.ImageArticleEntity
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity
|
||||
import com.gh.gamecenter.feature.entity.ForumVideoEntity
|
||||
import com.gh.gamecenter.qa.entity.ArticleDetailEntity
|
||||
@ -24,12 +26,12 @@ import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.room.AppDatabase
|
||||
import com.gh.gamecenter.room.dao.CommentDraftDao
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import retrofit2.HttpException
|
||||
|
||||
@ -44,7 +46,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>>()
|
||||
@ -60,6 +63,7 @@ open class NewCommentViewModel(
|
||||
var articleDetail: ArticleDetailEntity? = null
|
||||
var questionDetail: QuestionsDetailEntity? = null
|
||||
var videoDetail: ForumVideoEntity? = null
|
||||
private var imageArticleDetail: ImageArticleEntity? = null
|
||||
|
||||
init {
|
||||
commentDraftDao = AppDatabase.getInstance().commentDraftDao()
|
||||
@ -138,6 +142,7 @@ open class NewCommentViewModel(
|
||||
this.articleDetail = it
|
||||
}, {})
|
||||
}
|
||||
|
||||
CommentType.VIDEO,
|
||||
CommentType.VIDEO_CONVERSATION -> {
|
||||
api.getBbsVideoDetail(videoId)
|
||||
@ -147,6 +152,7 @@ open class NewCommentViewModel(
|
||||
this.videoDetail = it
|
||||
}, {})
|
||||
}
|
||||
|
||||
CommentType.COMMUNITY_QUESTION,
|
||||
CommentType.COMMUNITY_QUESTION_CONVERSATION -> {
|
||||
api.getQuestionsById(questionId)
|
||||
@ -156,6 +162,22 @@ open class NewCommentViewModel(
|
||||
this.questionDetail = it
|
||||
}, {})
|
||||
}
|
||||
|
||||
CommentType.IMAGE_ARTICLE,
|
||||
CommentType.GAME_COLLECTION_CONVERSATION -> {
|
||||
api.loadImageArticleDetail(
|
||||
imageArticleId,
|
||||
"detail",
|
||||
BuildConfig.VERSION_NAME,
|
||||
HaloApp.getInstance().channel
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
this.imageArticleDetail = it
|
||||
}, {})
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@ -165,8 +187,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 ?: "",
|
||||
@ -244,6 +265,33 @@ open class NewCommentViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
CommentType.IMAGE_ARTICLE,
|
||||
CommentType.IMAGE_ARTICLE_CONVERSATION -> {
|
||||
imageArticleDetail?.let {
|
||||
if (reply) {
|
||||
SensorsBridge.trackArticleReply(
|
||||
customerType = it.user.auth?.text ?: "",
|
||||
articleId = it.id,
|
||||
bbsId = it.community?.id ?: "",
|
||||
bbsType = it.community?.typeChinese ?: "",
|
||||
activityTag = "",
|
||||
gameForumType = it.community?.game?.categoryChinese ?: "",
|
||||
articleType = "图文"
|
||||
)
|
||||
} else {
|
||||
SensorsBridge.trackArticleComment(
|
||||
customerType = it.user.auth?.text ?: "",
|
||||
articleId = it.id,
|
||||
bbsId = it.community?.id ?: "",
|
||||
bbsType = it.community?.typeChinese ?: "",
|
||||
activityTag = "",
|
||||
gameForumType = it.community?.game?.categoryChinese ?: "",
|
||||
articleType = "图文"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@ -337,6 +385,36 @@ open class NewCommentViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
CommentType.IMAGE_ARTICLE,
|
||||
CommentType.IMAGE_ARTICLE_CONVERSATION -> {
|
||||
imageArticleDetail?.let {
|
||||
if (reply) {
|
||||
SensorsBridge.trackArticleReplyResult(
|
||||
customerType = it.user.auth?.text ?: "",
|
||||
articleId = it.id,
|
||||
bbsId = it.community?.id ?: "",
|
||||
bbsType = it.community?.typeChinese ?: "",
|
||||
activityTag = "",
|
||||
gameForumType = it.community?.game?.categoryChinese ?: "",
|
||||
articleType = "图文",
|
||||
result = result
|
||||
)
|
||||
} else {
|
||||
SensorsBridge.trackArticleCommentResult(
|
||||
customerType = it.user.auth?.text ?: "",
|
||||
articleId = it.id,
|
||||
bbsId = it.community?.id ?: "",
|
||||
bbsType = it.community?.typeChinese ?: "",
|
||||
activityTag = "",
|
||||
gameForumType = it.community?.game?.categoryChinese ?: "",
|
||||
articleType = "图文",
|
||||
result = result
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@ -439,6 +517,15 @@ open class NewCommentViewModel(
|
||||
api.postReplyToGameCollectionComment(gameCollectionId, commentEntity.id, body)
|
||||
}
|
||||
}
|
||||
|
||||
CommentType.IMAGE_ARTICLE, CommentType.IMAGE_ARTICLE_CONVERSATION -> {
|
||||
if (commentEntity == null) {
|
||||
api.postImageArticleComment(imageArticleId, body)
|
||||
} else {
|
||||
api.postReplyToImageArticleComment(commentEntity.id, body)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Remove this apiResponse crap.
|
||||
@ -632,7 +719,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 +735,8 @@ open class NewCommentViewModel(
|
||||
commentId = commentId,
|
||||
rootCommentId = rootCommentId,
|
||||
commentType = commentType,
|
||||
isVideoAuthor = isVideoAuthor
|
||||
isVideoAuthor = isVideoAuthor,
|
||||
imageArticleId = imageArticleId
|
||||
) as T
|
||||
}
|
||||
}
|
||||
@ -667,7 +756,11 @@ enum class CommentType {
|
||||
VIDEO_CONVERSATION,
|
||||
|
||||
GAME_COLLECTION,
|
||||
GAME_COLLECTION_CONVERSATION;
|
||||
GAME_COLLECTION_CONVERSATION,
|
||||
|
||||
IMAGE_ARTICLE,
|
||||
IMAGE_ARTICLE_CONVERSATION;
|
||||
|
||||
|
||||
fun isVideo(): Boolean {
|
||||
return (this == VIDEO || this == VIDEO_CONVERSATION)
|
||||
|
||||
@ -39,6 +39,9 @@ class StairsCommentFragment : NewCommentFragment() {
|
||||
|
||||
CommentType.GAME_COLLECTION,
|
||||
CommentType.GAME_COLLECTION_CONVERSATION -> "(游戏单详情-评论列表)"
|
||||
|
||||
CommentType.IMAGE_ARTICLE,
|
||||
CommentType.IMAGE_ARTICLE_CONVERSATION -> "(图文详情-评论列表)"
|
||||
}
|
||||
mAdapter = StairsCommentAdapter(requireContext(), mViewModel, true, this, this, entrance)
|
||||
}
|
||||
@ -58,7 +61,12 @@ class StairsCommentFragment : NewCommentFragment() {
|
||||
mAnswerContent.background =
|
||||
ContextCompat.getDrawable(requireActivity(), R.drawable.bg_shape_dark_radius_10_top_only)
|
||||
} else {
|
||||
mAnswerContent.setBackgroundColor(ContextCompat.getColor(requireActivity(), com.gh.gamecenter.common.R.color.bg_1F1F23))
|
||||
mAnswerContent.setBackgroundColor(
|
||||
ContextCompat.getColor(
|
||||
requireActivity(),
|
||||
com.gh.gamecenter.common.R.color.bg_1F1F23
|
||||
)
|
||||
)
|
||||
mOffset = abs(height)
|
||||
}
|
||||
|
||||
|
||||
@ -261,6 +261,7 @@ class StairsCommentViewHolder(
|
||||
mViewModel.articleId,
|
||||
mViewModel.communityId,
|
||||
mViewModel.videoId,
|
||||
mViewModel.imageArticleId,
|
||||
commentEntity,
|
||||
holder.binding.commentLikeCount,
|
||||
holder.binding.commentLike,
|
||||
@ -314,6 +315,9 @@ class StairsCommentViewHolder(
|
||||
|
||||
CommentType.GAME_COLLECTION,
|
||||
CommentType.GAME_COLLECTION_CONVERSATION -> "游戏单详情-评论管理"
|
||||
|
||||
CommentType.IMAGE_ARTICLE,
|
||||
CommentType.IMAGE_ARTICLE_CONVERSATION -> "图文详情-评论管理"
|
||||
}
|
||||
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
|
||||
}
|
||||
@ -277,7 +282,10 @@ abstract class BaseCommentAdapter(
|
||||
orderSfv.run {
|
||||
setContainerBackground(com.gh.gamecenter.common.R.drawable.button_round_f5f5f5.toDrawable(mContext))
|
||||
setIndicatorBackground(R.drawable.bg_game_collection_sfv_indicator.toDrawable(mContext))
|
||||
setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(mContext), com.gh.gamecenter.common.R.color.text_tertiary.toColor(mContext))
|
||||
setTextColor(
|
||||
com.gh.gamecenter.common.R.color.text_secondary.toColor(mContext),
|
||||
com.gh.gamecenter.common.R.color.text_tertiary.toColor(mContext)
|
||||
)
|
||||
}
|
||||
|
||||
val commentCount = mViewModel.commentCount
|
||||
@ -285,18 +293,23 @@ abstract class BaseCommentAdapter(
|
||||
article != null -> {
|
||||
"全部评论"
|
||||
}
|
||||
|
||||
questions != null -> {
|
||||
"全部回答"
|
||||
}
|
||||
|
||||
comment != null -> {
|
||||
"全部回复"
|
||||
}
|
||||
|
||||
gameCollection != null -> {
|
||||
"玩家评论"
|
||||
}
|
||||
|
||||
commentDetail != null -> {
|
||||
"全部讨论"
|
||||
}
|
||||
|
||||
else -> {
|
||||
""
|
||||
}
|
||||
@ -325,6 +338,7 @@ abstract class BaseCommentAdapter(
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
1 -> {
|
||||
mViewModel.changeSort(BaseCommentViewModel.SortType.LATEST)
|
||||
|
||||
@ -380,6 +394,7 @@ abstract class BaseCommentAdapter(
|
||||
}
|
||||
MtaHelper.onEvent("帖子详情", "全部评论", "评论正文")
|
||||
}
|
||||
|
||||
viewModel.videoId.isNotEmpty() -> {
|
||||
CommentActivity.getVideoCommentReplyIntent(
|
||||
binding.root.context,
|
||||
@ -396,6 +411,7 @@ abstract class BaseCommentAdapter(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.questionId.isNotEmpty() -> {
|
||||
CommentActivity.getQuestionCommentReplyIntent(
|
||||
binding.root.context,
|
||||
@ -412,6 +428,21 @@ abstract class BaseCommentAdapter(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.imageArticleId.isNotEmpty() ->{
|
||||
CommentActivity.getImageArticleCommentIntent(
|
||||
binding.root.context,
|
||||
viewModel.imageArticleId,
|
||||
bbsId,
|
||||
viewModel.commentCount,
|
||||
comment
|
||||
).apply {
|
||||
(binding.root.context as AppCompatActivity).startActivityForResult(
|
||||
this,
|
||||
CommentActivity.REQUEST_CODE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
NewLogUtils.logCommentClick(
|
||||
"click_comment_area_comment",
|
||||
@ -426,11 +457,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("帖子详情", "全部评论", "回复")
|
||||
@ -466,7 +499,12 @@ abstract class BaseCommentAdapter(
|
||||
com.gh.gamecenter.common.R.color.text_primary
|
||||
).build()
|
||||
val parentUserNameSpan = SpanBuilder(parentUserName)
|
||||
.click(binding.root.context, 0, parentUserName.length, com.gh.gamecenter.common.R.color.text_tertiary) {
|
||||
.click(
|
||||
binding.root.context,
|
||||
0,
|
||||
parentUserName.length,
|
||||
com.gh.gamecenter.common.R.color.text_tertiary
|
||||
) {
|
||||
DirectUtils.directToHomeActivity(
|
||||
binding.root.context,
|
||||
comment.user.id,
|
||||
@ -527,9 +565,11 @@ abstract class BaseCommentAdapter(
|
||||
viewModel.articleId.isNotEmpty() -> {
|
||||
viewModel.topItemData?.articleDetail?.user?.id ?: ""
|
||||
}
|
||||
|
||||
viewModel.questionId.isNotEmpty() -> {
|
||||
viewModel.topItemData?.questionDetail?.user?.id ?: ""
|
||||
}
|
||||
|
||||
else -> {
|
||||
""
|
||||
}
|
||||
@ -577,6 +617,7 @@ abstract class BaseCommentAdapter(
|
||||
viewModel.articleId,
|
||||
viewModel.videoId,
|
||||
viewModel.questionId,
|
||||
viewModel.imageArticleId,
|
||||
false,
|
||||
comment.floor,
|
||||
entrance,
|
||||
@ -597,13 +638,20 @@ abstract class BaseCommentAdapter(
|
||||
val finalName = "$name "
|
||||
val colon = " :"
|
||||
|
||||
val nameSpan = SpanBuilder(finalName).color(context, 0, finalName.length, com.gh.gamecenter.common.R.color.text_tertiary).build()
|
||||
val nameSpan = SpanBuilder(finalName).color(
|
||||
context,
|
||||
0,
|
||||
finalName.length,
|
||||
com.gh.gamecenter.common.R.color.text_tertiary
|
||||
).build()
|
||||
val authorSpan = if (finalAuthor.isNotEmpty()) SpanBuilder(finalAuthor).image(
|
||||
0,
|
||||
finalAuthor.length,
|
||||
R.drawable.ic_hint_author
|
||||
).build() else ""
|
||||
val colonSpan = SpanBuilder(colon).color(context, 0, colon.length, com.gh.gamecenter.common.R.color.text_tertiary).build()
|
||||
val colonSpan =
|
||||
SpanBuilder(colon).color(context, 0, colon.length, com.gh.gamecenter.common.R.color.text_tertiary)
|
||||
.build()
|
||||
return SpannableStringBuilder().append(nameSpan).append(authorSpan).append(colonSpan)
|
||||
.append(content)
|
||||
}
|
||||
@ -665,12 +713,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 "评论详情-全部回复"
|
||||
@ -693,7 +748,13 @@ abstract class BaseCommentAdapter(
|
||||
layoutManager = GridLayoutManager(context, 3)
|
||||
adapter = CommentPictureAdapter(context, comment.images!!, entrance)
|
||||
if (itemDecorationCount == 0) {
|
||||
addItemDecoration(GridSpacingItemColorDecoration(context, 2, com.gh.gamecenter.common.R.color.transparent))
|
||||
addItemDecoration(
|
||||
GridSpacingItemColorDecoration(
|
||||
context,
|
||||
2,
|
||||
com.gh.gamecenter.common.R.color.transparent
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -843,6 +904,7 @@ abstract class BaseCommentAdapter(
|
||||
deleteCallBack
|
||||
)
|
||||
}
|
||||
|
||||
viewModel.videoId.isNotEmpty() -> {
|
||||
showVideoCommentOptions(
|
||||
view,
|
||||
@ -852,6 +914,7 @@ abstract class BaseCommentAdapter(
|
||||
deleteCallBack
|
||||
)
|
||||
}
|
||||
|
||||
viewModel.questionId.isNotEmpty() -> {
|
||||
showQuestionCommentOption(
|
||||
view,
|
||||
@ -861,6 +924,16 @@ abstract class BaseCommentAdapter(
|
||||
deleteCallBack
|
||||
)
|
||||
}
|
||||
|
||||
viewModel.imageArticleId.isNotEmpty() -> {
|
||||
showImageArticleOption(
|
||||
view,
|
||||
comment,
|
||||
viewModel,
|
||||
path,
|
||||
deleteCallBack
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -872,18 +945,34 @@ 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 ?: ""
|
||||
}
|
||||
|
||||
viewModel.imageArticleId.isNotEmpty() -> {
|
||||
bbsId = viewModel.topItemData?.imageArticleDetail?.community?.id ?: ""
|
||||
type = viewModel.topItemData?.imageArticleDetail?.community?.type ?: ""
|
||||
}
|
||||
|
||||
else -> {
|
||||
bbsId = (viewModel as? VideoCommentViewModel)?.videoDetail?.bbs?.id ?: ""
|
||||
type = (viewModel as? VideoCommentViewModel)?.videoDetail?.type ?: ""
|
||||
}
|
||||
}
|
||||
val contentType =
|
||||
if (viewModel.articleId.isNotEmpty()) "帖子评论" else if (viewModel.questionId.isNotEmpty()) "提问帖评论" else "视频帖评论"
|
||||
val bbsType = if (type == "game_bbs") "游戏论坛" else "综合论坛"
|
||||
when {
|
||||
viewModel.articleId.isNotEmpty() -> "帖子评论"
|
||||
viewModel.questionId.isNotEmpty() -> "提问帖评论"
|
||||
viewModel.imageArticleId.isNotEmpty() -> "图文评论"
|
||||
else -> "视频帖评论"
|
||||
}
|
||||
val bbsType = when (type) {
|
||||
"game_bbs" -> "游戏论坛"
|
||||
"official_bbs" -> "综合论坛"
|
||||
else -> ""
|
||||
}
|
||||
return Triple(bbsId, contentType, bbsType)
|
||||
}
|
||||
|
||||
@ -916,6 +1005,7 @@ abstract class BaseCommentAdapter(
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
"采纳" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -929,6 +1019,7 @@ abstract class BaseCommentAdapter(
|
||||
extraConfig = DialogHelper.Config(centerContent = true, centerTitle = true)
|
||||
)
|
||||
}
|
||||
|
||||
"取消采纳" -> {
|
||||
viewModel.acceptQuestionComment(
|
||||
viewModel.questionId,
|
||||
@ -936,12 +1027,15 @@ abstract class BaseCommentAdapter(
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
"加精选" -> {
|
||||
showHighlightQuestionCommentDialog(comment, view.context, viewModel, true)
|
||||
}
|
||||
|
||||
"取消精选" -> {
|
||||
showHighlightQuestionCommentDialog(comment, view.context, viewModel, false)
|
||||
}
|
||||
|
||||
"置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -955,6 +1049,7 @@ abstract class BaseCommentAdapter(
|
||||
extraConfig = DialogHelper.Config(centerContent = true, centerTitle = true)
|
||||
)
|
||||
}
|
||||
|
||||
"取消置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -1048,6 +1143,7 @@ abstract class BaseCommentAdapter(
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
"置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -1061,6 +1157,7 @@ abstract class BaseCommentAdapter(
|
||||
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
"取消置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -1119,6 +1216,7 @@ abstract class BaseCommentAdapter(
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
"置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -1132,6 +1230,7 @@ abstract class BaseCommentAdapter(
|
||||
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
|
||||
"取消置顶" -> {
|
||||
DialogHelper.showDialog(
|
||||
view.context,
|
||||
@ -1166,6 +1265,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 +1383,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 = ""
|
||||
val imageArticleId: String = "",
|
||||
val topCommentId: 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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
package com.gh.gamecenter.qa.comment.conversation
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.gh.common.util.CommentUtils
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.utils.TextHelper
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
@ -83,6 +87,7 @@ class CommentConversationAdapter(
|
||||
(binding.bottomContainer.layoutParams as ConstraintLayout.LayoutParams).apply {
|
||||
leftMargin = 9F.dip2px()
|
||||
binding.bottomContainer.layoutParams = this
|
||||
|
||||
}
|
||||
|
||||
binding.run {
|
||||
@ -123,6 +128,7 @@ class CommentConversationAdapter(
|
||||
path
|
||||
)
|
||||
}
|
||||
|
||||
videoId.isNotEmpty() -> {
|
||||
DirectUtils.directToVideoDetail(
|
||||
mContext,
|
||||
@ -131,6 +137,7 @@ class CommentConversationAdapter(
|
||||
path
|
||||
)
|
||||
}
|
||||
|
||||
questionId.isNotEmpty() -> {
|
||||
DirectUtils.directToQuestionDetail(
|
||||
mContext,
|
||||
@ -139,6 +146,7 @@ class CommentConversationAdapter(
|
||||
path
|
||||
)
|
||||
}
|
||||
|
||||
gameCollectionId.isNotEmpty() -> {
|
||||
DirectUtils.directToGameCollectionDetail(
|
||||
mContext,
|
||||
@ -147,6 +155,14 @@ class CommentConversationAdapter(
|
||||
path
|
||||
)
|
||||
}
|
||||
|
||||
imageArticleId.isNotEmpty() -> {
|
||||
val imageArticleUri = Uri.Builder()
|
||||
.path(RouteConsts.activity.imageArticleDetailActivity)
|
||||
.appendQueryParameter(EntranceConsts.KEY_IMAGE_ARTICLE_ID, imageArticleId)
|
||||
.build()
|
||||
ARouter.getInstance().build(imageArticleUri).navigation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(IMAGE_ARTICLE_ID) ?: "",
|
||||
arguments?.getString(EntranceConsts.KEY_TOP_COMMENT_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,18 @@ class CommentConversationViewModel(
|
||||
communityId: String = "",
|
||||
gameCollectionId: String = "",
|
||||
var commentId: String = "",
|
||||
imageArticleId: String = "",
|
||||
topCommentId: String = ""
|
||||
) : BaseCommentViewModel(application, articleId, videoId, questionId, communityId, topCommentId) {
|
||||
) : BaseCommentViewModel(
|
||||
application,
|
||||
articleId,
|
||||
videoId,
|
||||
questionId,
|
||||
communityId,
|
||||
gameCollectionId,
|
||||
imageArticleId,
|
||||
topCommentId = topCommentId
|
||||
) {
|
||||
var commentDetail: CommentEntity? = null
|
||||
var positionInOriginList = -1
|
||||
|
||||
@ -42,15 +54,31 @@ 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(),
|
||||
map
|
||||
)
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@ -61,15 +89,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 +154,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 +174,8 @@ class CommentConversationViewModel(
|
||||
private val communityId: String = "",
|
||||
private val gameCollectionId: String = "",
|
||||
private val commentId: String,
|
||||
private val topCommentId: String
|
||||
private val imageArticleId: String,
|
||||
private val topCommentId: String,
|
||||
) : ViewModelProvider.NewInstanceFactory() {
|
||||
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
@ -144,7 +187,8 @@ class CommentConversationViewModel(
|
||||
communityId = communityId,
|
||||
gameCollectionId = gameCollectionId,
|
||||
commentId = commentId,
|
||||
topCommentId = topCommentId
|
||||
imageArticleId = imageArticleId,
|
||||
topCommentId = topCommentId,
|
||||
) 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(),
|
||||
|
||||
@ -20,7 +20,7 @@ class VideoCommentViewModel(
|
||||
videoId: String,
|
||||
bbsId: String,
|
||||
topCommentId: String
|
||||
) : BaseCommentViewModel(application, "", videoId, "", bbsId, "", topCommentId) {
|
||||
) : BaseCommentViewModel(application, "", videoId, "", bbsId, "", topCommentId = topCommentId) {
|
||||
var videoDetail: ForumVideoEntity? = null
|
||||
val deleteCommentLiveData = MutableLiveData<Boolean>()
|
||||
|
||||
|
||||
@ -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,196 @@ 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,
|
||||
@QueryMap Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 投诉图文评论
|
||||
*/
|
||||
@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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/community_edit_recommend.webp
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/community_edit_recommend.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:radius="12dp" />
|
||||
<solid android:color="@color/bg_mask_40" />
|
||||
</shape>
|
||||
70
app/src/main/res/drawable/btn_fab_container__1__1.xml
Normal file
70
app/src/main/res/drawable/btn_fab_container__1__1.xml
Normal file
@ -0,0 +1,70 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="64dp"
|
||||
android:height="64dp"
|
||||
android:viewportWidth="64"
|
||||
android:viewportHeight="64">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0,0h64v64h-64z"/>
|
||||
<path
|
||||
android:pathData="M32,56C45.255,56 56,45.255 56,32C56,18.745 45.255,8 32,8C18.745,8 8,18.745 8,32C8,45.255 18.745,56 32,56Z"
|
||||
android:fillColor="#3B4B64"/>
|
||||
<path
|
||||
android:pathData="M32,56C45.255,56 56,45.255 56,32C56,18.745 45.255,8 32,8C18.745,8 8,18.745 8,32C8,45.255 18.745,56 32,56Z"
|
||||
android:fillColor="#2496FF"/>
|
||||
<path
|
||||
android:pathData="M32,56C45.255,56 56,45.255 56,32C56,18.745 45.255,8 32,8C18.745,8 8,18.745 8,32C8,45.255 18.745,56 32,56Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="8.307"
|
||||
android:startY="8"
|
||||
android:endX="55.693"
|
||||
android:endY="56"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#FF44BAFF"/>
|
||||
<item android:offset="1" android:color="#FF378DFF"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="M32,55.75C45.117,55.75 55.75,45.117 55.75,32C55.75,18.883 45.117,8.25 32,8.25C18.883,8.25 8.25,18.883 8.25,32C8.25,45.117 18.883,55.75 32,55.75Z"
|
||||
android:strokeAlpha="0.05"
|
||||
android:strokeWidth="0.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M25.493,45.973H27.059C27.473,45.973 27.536,45.784 27.581,44.731C27.734,44.83 27.986,44.938 28.175,44.974C28.094,46.216 27.896,46.558 27.104,46.558H25.439C24.575,46.558 24.305,46.36 24.305,45.577V41.743H27.563C27.563,41.743 27.563,41.932 27.554,42.013C27.464,43.561 27.383,44.164 27.176,44.389C27.041,44.542 26.888,44.596 26.663,44.623C26.483,44.632 26.141,44.641 25.781,44.614C25.763,44.434 25.7,44.2 25.619,44.038C25.943,44.074 26.249,44.074 26.384,44.074C26.501,44.074 26.573,44.065 26.645,43.993C26.744,43.858 26.834,43.426 26.906,42.337H24.953V45.577C24.953,45.91 25.034,45.973 25.493,45.973ZM25.835,38.485L26.456,38.674C26.402,38.809 26.339,38.926 26.276,39.061C27.014,39.817 27.914,40.816 28.346,41.455L27.869,41.896C27.464,41.293 26.69,40.366 25.979,39.601C25.412,40.573 24.647,41.473 23.765,42.157C23.657,42.031 23.423,41.797 23.279,41.689C24.413,40.879 25.358,39.646 25.835,38.485ZM29.417,39.52V44.479H28.778V39.52H29.417ZM30.524,38.611H31.181V45.802C31.181,46.252 31.055,46.432 30.776,46.54C30.488,46.648 29.993,46.666 29.156,46.657C29.12,46.486 29.021,46.198 28.922,46.018C29.552,46.045 30.119,46.036 30.29,46.027C30.452,46.018 30.524,45.964 30.524,45.802V38.611ZM39.263,39.781H37.913V40.438H39.263V39.781ZM39.263,41.653V40.987H37.913V41.653H39.263ZM37.283,40.438V39.781H35.555V39.25H37.283V38.512H37.913V39.25H39.866V40.438H40.487V40.987H39.866V42.193H37.913V42.868H40.037V43.381H37.913V44.11H40.37V44.659H37.913V45.55H37.283V44.659H35.051V44.11H37.283V43.381H35.429V42.868H37.283V42.193H35.492V41.653H37.283V40.987H34.97V40.438H37.283ZM34.637,41.509L35.015,41.617C34.871,42.895 34.61,43.939 34.241,44.776C35.114,45.658 36.356,45.856 37.886,45.856C38.237,45.856 40.172,45.856 40.631,45.847C40.532,46 40.415,46.288 40.379,46.468H37.868C36.203,46.468 34.898,46.234 33.971,45.325C33.647,45.874 33.278,46.306 32.855,46.639C32.747,46.504 32.513,46.27 32.36,46.18C32.819,45.856 33.215,45.397 33.539,44.83C33.206,44.38 32.945,43.813 32.729,43.102L33.224,42.904C33.377,43.435 33.575,43.876 33.809,44.236C34.052,43.633 34.232,42.931 34.349,42.121H32.891C33.278,41.464 33.773,40.492 34.178,39.628H32.603V39.034H35.132C34.754,39.826 34.277,40.78 33.881,41.527H34.52L34.637,41.509Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M42,16H22V36H42V16Z"/>
|
||||
<path
|
||||
android:pathData="M35.556,17.414C35.947,17.024 36.58,17.024 36.971,17.414L38.385,18.828C38.775,19.219 38.775,19.852 38.385,20.243L36.971,21.657C36.58,22.047 35.947,22.047 35.556,21.657L34.142,20.243C33.752,19.852 33.752,19.219 34.142,18.828L35.556,17.414Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.6"/>
|
||||
<path
|
||||
android:pathData="M38.031,22.01C38.227,21.815 38.227,21.498 38.031,21.303L34.849,18.121C34.459,17.73 33.826,17.73 33.435,18.121L23,28.556C22.437,29.119 22.121,29.882 22.121,30.677V32.677C22.121,33.23 22.569,33.677 23.121,33.677H25.121C25.917,33.677 26.68,33.361 27.243,32.799L38.031,22.01Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="36.263"
|
||||
android:startY="19.535"
|
||||
android:endX="22.121"
|
||||
android:endY="33.677"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#CCFFFFFF"/>
|
||||
<item android:offset="1" android:color="#FFFFFFFF"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="M29.899,17.414C30.29,17.024 30.923,17.024 31.314,17.414L31.667,17.768C31.862,17.963 31.862,18.279 31.667,18.475L27.218,22.924C26.903,23.239 26.364,23.016 26.364,22.571V21.364C26.364,21.099 26.469,20.844 26.657,20.657L29.899,17.414Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.6"/>
|
||||
<path
|
||||
android:pathData="M31.707,32.293C31.895,32.105 32.149,32 32.414,32H41.5C41.776,32 42,32.224 42,32.5V33.5C42,33.776 41.776,34 41.5,34H30.604C30.381,34 30.269,33.731 30.427,33.573L31.707,32.293Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.6"/>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
66
app/src/main/res/drawable/ic_community_float_create.xml
Normal file
66
app/src/main/res/drawable/ic_community_float_create.xml
Normal file
@ -0,0 +1,66 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="60dp"
|
||||
android:height="60dp"
|
||||
android:viewportWidth="60"
|
||||
android:viewportHeight="60">
|
||||
<path
|
||||
android:pathData="M30,26m-24,0a24,24 0,1 1,48 0a24,24 0,1 1,-48 0"
|
||||
android:fillColor="#3B4B64"/>
|
||||
<path
|
||||
android:pathData="M30,26m-24,0a24,24 0,1 1,48 0a24,24 0,1 1,-48 0"
|
||||
android:fillColor="#2496FF"/>
|
||||
<path
|
||||
android:pathData="M30,26m-24,0a24,24 0,1 1,48 0a24,24 0,1 1,-48 0">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="6.307"
|
||||
android:startY="2"
|
||||
android:endX="53.693"
|
||||
android:endY="50"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#FF44BAFF"/>
|
||||
<item android:offset="1" android:color="#FF378DFF"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="M30,26m-23.75,0a23.75,23.75 0,1 1,47.5 0a23.75,23.75 0,1 1,-47.5 0"
|
||||
android:strokeAlpha="0.05"
|
||||
android:strokeWidth="0.5"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M23.493,39.973H25.059C25.473,39.973 25.536,39.784 25.581,38.731C25.734,38.83 25.986,38.938 26.175,38.974C26.094,40.216 25.896,40.558 25.104,40.558H23.439C22.575,40.558 22.305,40.36 22.305,39.577V35.743H25.563C25.563,35.743 25.563,35.932 25.554,36.013C25.464,37.561 25.383,38.164 25.176,38.389C25.041,38.542 24.888,38.596 24.663,38.623C24.483,38.632 24.141,38.641 23.781,38.614C23.763,38.434 23.7,38.2 23.619,38.038C23.943,38.074 24.249,38.074 24.384,38.074C24.501,38.074 24.573,38.065 24.645,37.993C24.744,37.858 24.834,37.426 24.906,36.337H22.953V39.577C22.953,39.91 23.034,39.973 23.493,39.973ZM23.835,32.485L24.456,32.674C24.402,32.809 24.339,32.926 24.276,33.061C25.014,33.817 25.914,34.816 26.346,35.455L25.869,35.896C25.464,35.293 24.69,34.366 23.979,33.601C23.412,34.573 22.647,35.473 21.765,36.157C21.657,36.031 21.423,35.797 21.279,35.689C22.413,34.879 23.358,33.646 23.835,32.485ZM27.417,33.52V38.479H26.778V33.52H27.417ZM28.524,32.611H29.181V39.802C29.181,40.252 29.055,40.432 28.776,40.54C28.488,40.648 27.993,40.666 27.156,40.657C27.12,40.486 27.021,40.198 26.922,40.018C27.552,40.045 28.119,40.036 28.29,40.027C28.452,40.018 28.524,39.964 28.524,39.802V32.611ZM37.263,33.781H35.913V34.438H37.263V33.781ZM37.263,35.653V34.987H35.913V35.653H37.263ZM35.283,34.438V33.781H33.555V33.25H35.283V32.512H35.913V33.25H37.866V34.438H38.487V34.987H37.866V36.193H35.913V36.868H38.037V37.381H35.913V38.11H38.37V38.659H35.913V39.55H35.283V38.659H33.051V38.11H35.283V37.381H33.429V36.868H35.283V36.193H33.492V35.653H35.283V34.987H32.97V34.438H35.283ZM32.637,35.509L33.015,35.617C32.871,36.895 32.61,37.939 32.241,38.776C33.114,39.658 34.356,39.856 35.886,39.856C36.237,39.856 38.172,39.856 38.631,39.847C38.532,40 38.415,40.288 38.379,40.468H35.868C34.203,40.468 32.898,40.234 31.971,39.325C31.647,39.874 31.278,40.306 30.855,40.639C30.747,40.504 30.513,40.27 30.36,40.18C30.819,39.856 31.215,39.397 31.539,38.83C31.206,38.38 30.945,37.813 30.729,37.102L31.224,36.904C31.377,37.435 31.575,37.876 31.809,38.236C32.052,37.633 32.232,36.931 32.349,36.121H30.891C31.278,35.464 31.773,34.492 32.178,33.628H30.603V33.034H33.132C32.754,33.826 32.277,34.78 31.881,35.527H32.52L32.637,35.509Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M20,10h20v20h-20z"/>
|
||||
<path
|
||||
android:pathData="M33.556,11.414C33.947,11.024 34.58,11.024 34.971,11.414L36.385,12.828C36.775,13.219 36.775,13.852 36.385,14.243L34.971,15.657C34.58,16.047 33.947,16.047 33.556,15.657L32.142,14.243C31.752,13.852 31.752,13.219 32.142,12.828L33.556,11.414Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.6"/>
|
||||
<path
|
||||
android:pathData="M36.031,16.01C36.227,15.815 36.227,15.498 36.031,15.303L32.849,12.121C32.459,11.731 31.826,11.731 31.435,12.121L21,22.556C20.437,23.119 20.121,23.882 20.121,24.678V26.678C20.121,27.23 20.569,27.678 21.121,27.678L23.121,27.678C23.917,27.678 24.68,27.361 25.243,26.799L36.031,16.01Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="34.263"
|
||||
android:startY="13.535"
|
||||
android:endX="20.121"
|
||||
android:endY="27.678"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#CCFFFFFF"/>
|
||||
<item android:offset="1" android:color="#FFFFFFFF"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="M27.899,11.414C28.29,11.024 28.923,11.024 29.314,11.414L29.667,11.768C29.862,11.963 29.862,12.28 29.667,12.475L25.218,16.924C24.903,17.24 24.364,17.016 24.364,16.571L24.364,15.364C24.364,15.099 24.469,14.844 24.657,14.657L27.899,11.414Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.6"/>
|
||||
<path
|
||||
android:pathData="M29.707,26.293C29.895,26.105 30.149,26 30.414,26H39.5C39.776,26 40,26.224 40,26.5V27.5C40,27.776 39.776,28 39.5,28H28.604C28.381,28 28.269,27.731 28.427,27.573L29.707,26.293Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.6"/>
|
||||
</group>
|
||||
</vector>
|
||||
107
app/src/main/res/drawable/ic_community_float_publish.xml
Normal file
107
app/src/main/res/drawable/ic_community_float_publish.xml
Normal file
@ -0,0 +1,107 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="60dp"
|
||||
android:height="60dp"
|
||||
android:viewportWidth="60"
|
||||
android:viewportHeight="60">
|
||||
|
||||
<path
|
||||
android:fillColor="#3B4B64"
|
||||
android:pathData="M30,26m-24,0a24,24 0,1 1,48 0a24,24 0,1 1,-48 0" />
|
||||
|
||||
<path
|
||||
android:fillColor="#2496FF"
|
||||
android:pathData="M30,26m-24,0a24,24 0,1 1,48 0a24,24 0,1 1,-48 0" />
|
||||
|
||||
<path android:pathData="M30,26m-24,0a24,24 0,1 1,48 0a24,24 0,1 1,-48 0">
|
||||
|
||||
<aapt:attr name="android:fillColor">
|
||||
|
||||
<gradient
|
||||
android:endX="53.693"
|
||||
android:endY="50"
|
||||
android:startX="6.307"
|
||||
android:startY="2"
|
||||
android:type="linear">
|
||||
|
||||
<item
|
||||
android:color="#FF44BAFF"
|
||||
android:offset="0" />
|
||||
|
||||
<item
|
||||
android:color="#FF378DFF"
|
||||
android:offset="1" />
|
||||
|
||||
</gradient>
|
||||
|
||||
</aapt:attr>
|
||||
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M30,26m-23.75,0a23.75,23.75 0,1 1,47.5 0a23.75,23.75 0,1 1,-47.5 0"
|
||||
android:strokeWidth="0.5"
|
||||
android:strokeAlpha="0.05"
|
||||
android:strokeColor="#000000" />
|
||||
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M28.722,33.871L28.182,34.24C27.939,33.898 27.435,33.331 27.048,32.917L27.561,32.593C27.948,32.989 28.47,33.547 28.722,33.871ZM27.669,36.751H24.852C25.194,37.462 25.68,38.092 26.292,38.605C26.868,38.101 27.345,37.48 27.669,36.751ZM28.119,36.067L28.569,36.292C28.2,37.426 27.597,38.317 26.823,39.01C27.606,39.541 28.551,39.919 29.649,40.126C29.505,40.261 29.325,40.531 29.235,40.72C28.092,40.468 27.111,40.036 26.31,39.433C25.482,40.027 24.537,40.441 23.538,40.711C23.466,40.54 23.304,40.279 23.187,40.135C24.114,39.919 25.014,39.541 25.779,39.001C25.248,38.506 24.798,37.921 24.438,37.246C23.817,38.353 22.971,39.271 21.81,39.991C21.711,39.838 21.477,39.595 21.315,39.478C22.953,38.479 23.943,37.012 24.537,35.149H23.286C22.719,35.149 22.413,35.203 22.332,35.302C22.287,35.158 22.179,34.825 22.107,34.672C22.233,34.636 22.332,34.51 22.431,34.312C22.539,34.132 22.872,33.403 23.034,32.719L23.736,32.854C23.583,33.43 23.322,34.033 23.088,34.501H24.708C24.879,33.853 25.005,33.169 25.086,32.44L25.833,32.548C25.734,33.241 25.617,33.889 25.473,34.501H29.352L29.343,35.149H25.293C25.194,35.473 25.086,35.797 24.978,36.103H27.993L28.119,36.067ZM38.442,34.492H33.573C33.303,35.068 32.988,35.617 32.628,36.13H34.59V34.924H35.256V36.13H37.947V39.01C37.947,39.37 37.866,39.559 37.587,39.658C37.317,39.766 36.84,39.775 36.066,39.766C36.039,39.586 35.94,39.343 35.85,39.163C36.426,39.181 36.948,39.172 37.083,39.172C37.236,39.163 37.281,39.127 37.281,39.001V36.76H35.256V40.702H34.59V36.76H32.682V39.865H32.016V36.913C31.629,37.354 31.197,37.75 30.711,38.083C30.621,37.921 30.45,37.669 30.315,37.525C31.404,36.787 32.232,35.68 32.835,34.492H30.576V33.844H33.123C33.321,33.385 33.474,32.926 33.6,32.467L34.293,32.629C34.167,33.034 34.014,33.439 33.861,33.844H38.442V34.492Z" />
|
||||
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M21.6,13.998C21.6,13.115 22.316,12.398 23.2,12.398H36.8C37.684,12.398 38.4,13.115 38.4,13.998V25.998C38.4,26.882 37.684,27.598 36.8,27.598H23.2C22.316,27.598 21.6,26.882 21.6,25.998V13.998ZM23.2,14.398C23.2,14.177 23.379,13.998 23.6,13.998H36.4C36.621,13.998 36.8,14.177 36.8,14.398L36.8,23.039C36.619,22.647 36.409,22.246 36.168,21.837C35.928,21.428 35.666,21.057 35.38,20.724C35.095,20.392 34.785,20.121 34.45,19.912C34.115,19.703 33.766,19.599 33.404,19.599C32.978,19.599 32.616,19.678 32.317,19.835C32.018,19.993 31.76,20.191 31.542,20.43C31.325,20.669 31.13,20.925 30.958,21.197C30.786,21.47 30.614,21.726 30.442,21.965C30.27,22.203 30.082,22.402 29.878,22.559C29.674,22.717 29.432,22.796 29.151,22.796C28.87,22.796 28.63,22.777 28.431,22.738C28.232,22.7 28.053,22.651 27.894,22.591C27.736,22.532 27.589,22.466 27.453,22.393C27.317,22.321 27.17,22.255 27.011,22.195C26.853,22.135 26.671,22.086 26.468,22.048C26.264,22.01 26.022,21.99 25.741,21.99C25.505,21.99 25.272,22.048 25.041,22.163C24.81,22.278 24.586,22.425 24.369,22.604C24.151,22.783 23.943,22.984 23.744,23.205C23.544,23.427 23.363,23.649 23.2,23.87L23.2,14.398Z">
|
||||
|
||||
<aapt:attr name="android:fillColor">
|
||||
|
||||
<gradient
|
||||
android:endX="30"
|
||||
android:endY="35.5"
|
||||
android:startX="30"
|
||||
android:startY="12.5"
|
||||
android:type="linear">
|
||||
|
||||
<item
|
||||
android:color="#CCFFFFFF"
|
||||
android:offset="0" />
|
||||
|
||||
<item
|
||||
android:color="#FFFFFFFF"
|
||||
android:offset="1" />
|
||||
|
||||
</gradient>
|
||||
|
||||
</aapt:attr>
|
||||
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:pathData="M27.4,18.199m-1.8,0a1.8,1.8 0,1 1,3.6 0a1.8,1.8 0,1 1,-3.6 0"
|
||||
android:strokeAlpha="0.5">
|
||||
|
||||
<aapt:attr name="android:fillColor">
|
||||
|
||||
<gradient
|
||||
android:endX="27.4"
|
||||
android:endY="21.871"
|
||||
android:startX="27.4"
|
||||
android:startY="16.424"
|
||||
android:type="linear">
|
||||
|
||||
<item
|
||||
android:color="#CCFFFFFF"
|
||||
android:offset="0" />
|
||||
|
||||
<item
|
||||
android:color="#FFFFFFFF"
|
||||
android:offset="1" />
|
||||
|
||||
</gradient>
|
||||
|
||||
</aapt:attr>
|
||||
|
||||
</path>
|
||||
|
||||
</vector>
|
||||
13
app/src/main/res/drawable/ic_image_and_text_add.xml
Normal file
13
app/src/main/res/drawable/ic_image_and_text_add.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="100dp"
|
||||
android:height="100dp"
|
||||
android:viewportWidth="100"
|
||||
android:viewportHeight="100">
|
||||
<path
|
||||
android:pathData="M8,0L92,0A8,8 0,0 1,100 8L100,92A8,8 0,0 1,92 100L8,100A8,8 0,0 1,0 92L0,8A8,8 0,0 1,8 0z"
|
||||
android:fillColor="#F5F5F5"/>
|
||||
<path
|
||||
android:pathData="M50,40C49.45,40 49,40.45 49,41V49H41C40.45,49 40,49.45 40,50C40,50.55 40.45,51 41,51H49V59C49,59.55 49.45,60 50,60C50.55,60 51,59.55 51,59V51H59C59.55,51 60,50.55 60,50C60,49.45 59.55,49 59,49H51V41C51,40.45 50.55,40 50,40Z"
|
||||
android:fillColor="#CCCCCC"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user