From fbd3a42e81202854e40a75da8c42c552c78a42b2 Mon Sep 17 00:00:00 2001 From: juntao Date: Tue, 11 Aug 2020 18:25:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=B2=97=E7=B3=99=E7=9A=84?= =?UTF-8?q?=E5=B8=96=E5=AD=90=E8=AF=A6=E6=83=85=E6=A1=86=E6=9E=B6=EF=BC=8C?= =?UTF-8?q?=E7=BB=86=E8=8A=82=E5=BE=85=E8=A1=A5=E5=85=85=20https://gitlab.?= =?UTF-8?q?ghzs.com/pm/halo-app-issues/-/issues/967?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 2 + app/src/main/AndroidManifest.xml | 8 +- .../java/com/gh/common/util/CommentUtils.java | 26 +- .../java/com/gh/common/util/Extensions.kt | 31 +- .../com/gh/gamecenter/entity/CommentEntity.kt | 10 +- .../article/detail/ArticleDetailActivity.kt | 682 ++++++++---------- .../detail/ArticleDetailCommentAdapter.kt | 127 ++++ .../detail/ArticleDetailCommentFragment.kt | 65 ++ .../detail/ArticleDetailCommentViewModel.kt | 79 ++ .../article/detail/ArticleDetailViewModel.kt | 42 +- .../gamecenter/qa/comment/CommentActivity.kt | 17 +- .../qa/comment/NewCommentFragment.kt | 26 +- .../qa/comment/NewCommentViewModel.kt | 16 +- .../ic_article_detail_comment_bottom_bar.png | Bin 0 -> 2274 bytes .../ic_article_detail_comment_list.png | Bin 0 -> 2190 bytes .../ic_article_detail_comment_more_list.png | Bin 0 -> 251 bytes .../ic_article_detail_dislike.png | Bin 0 -> 3394 bytes .../ic_article_detail_disliked.png | Bin 0 -> 2418 bytes .../ic_article_detail_forum_tag.png | Bin 0 -> 603 bytes .../ic_article_detail_like.png | Bin 0 -> 3377 bytes .../ic_article_detail_like_bottom_bar.png | Bin 0 -> 2428 bytes .../ic_article_detail_liked.png | Bin 0 -> 2400 bytes .../ic_article_detail_share.png | Bin 0 -> 3736 bytes .../ic_article_detail_star.png | Bin 0 -> 3530 bytes .../ic_article_detail_stared.png | Bin 0 -> 2403 bytes .../divider_article_detail_comment.xml | 6 + .../res/layout/activity_article_detail.xml | 660 ++++++++++++----- .../fragment_article_detail_comment.xml | 25 + .../layout/item_article_detail_comment.xml | 305 ++++++++ .../res/layout/menu_answer_detail_more.xml | 30 + app/src/main/res/values/colors.xml | 1 + 31 files changed, 1551 insertions(+), 607 deletions(-) create mode 100644 app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailCommentAdapter.kt create mode 100644 app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailCommentFragment.kt create mode 100644 app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailCommentViewModel.kt create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_detail_comment_bottom_bar.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_detail_comment_list.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_detail_comment_more_list.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_detail_dislike.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_detail_disliked.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_detail_forum_tag.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_detail_like.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_detail_like_bottom_bar.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_detail_liked.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_detail_share.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_detail_star.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_article_detail_stared.png create mode 100644 app/src/main/res/drawable/divider_article_detail_comment.xml create mode 100644 app/src/main/res/layout/fragment_article_detail_comment.xml create mode 100644 app/src/main/res/layout/item_article_detail_comment.xml diff --git a/app/build.gradle b/app/build.gradle index c7c534837e..4df6b73cd8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -296,6 +296,8 @@ dependencies { }) implementation "com.github.PhilJay:MPAndroidChart:${chart}" + implementation "com.github.donkingliang:ConsecutiveScroller:${consecutiveScroller}" + implementation project(':libraries:LGLibrary') implementation project(':libraries:MTA') implementation project(':libraries:QQShare') diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4f90b50f78..83d42d3d00 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -52,14 +52,8 @@ com.shuyu.gsy.base, com.google.android.exoplayer2, tv.danmaku.ijk.media.exo2, - shuyu.com.androidvideocache, pl.droidsonroids.gif, - com.ledong.lib.minigame, - com.ledong.lib.leto, - com.leto.game.base.glide4, - com.leto.game.ad.gdt, - com.leto.game.fcm, - com.leto.game.ad.toutiao" /> + com.donkingliang.consecutivescroller" /> = today - 86400 * 1000 && day < today) { format.applyPattern("HH:mm"); - textView.setText("昨天 "); + return "昨天 "; } else if (day >= today - 86400 * 1000 * 7 && day < today - 86400 * 1000) { format.applyPattern("HH:mm"); long days = (today - day) / 86400000 + 1; - textView.setText(String.format(Locale.getDefault(), "%d天前 ", days)); + return String.format(Locale.getDefault(), "%d天前 ", days); } else if (day < today - 86400 * 1000 * 7 && year.equals(currentYear)) { format.applyPattern("MM-dd"); - textView.setText(format.format(day)); + return format.format(day); } else { format.applyPattern("yyyy-MM-dd"); - textView.setText(format.format(day)); + return format.format(day); } } catch (ParseException e) { e.printStackTrace(); format.applyPattern("yyyy-MM-dd"); - textView.setText(format.format(time * 1000)); + return format.format(timestamp * 1000); } } - public static void showReportDialog(final CommentEntity commentEntity, final Context context, final boolean showConversation, diff --git a/app/src/main/java/com/gh/common/util/Extensions.kt b/app/src/main/java/com/gh/common/util/Extensions.kt index 67a828f4fd..61fa266556 100644 --- a/app/src/main/java/com/gh/common/util/Extensions.kt +++ b/app/src/main/java/com/gh/common/util/Extensions.kt @@ -3,6 +3,7 @@ package com.gh.common.util import android.animation.Animator import android.content.ClipboardManager import android.content.Context +import android.graphics.drawable.GradientDrawable import android.os.Build import android.text.* import android.text.style.ClickableSpan @@ -64,6 +65,14 @@ inline fun Fragment.viewModelProviderFromParent( ) = ViewModelProviders.of(requireActivity(), provider).get(VM::class.java) +/** + * 创建以 activity 为观察者上下文的 viewModel + */ +inline fun FragmentActivity.viewModelProviderFromParent( + provider: ViewModelProvider.Factory? = null +) = + ViewModelProviders.of(this, provider).get(VM::class.java) + /** * 创建以 fragment 为观察者上下文的 viewModel */ @@ -162,6 +171,17 @@ fun View.removeSelectableItemBackground() { background = null } +fun View.setRoundedColorBackground(@ColorRes color: Int, radius: Float) { + val shape = GradientDrawable() + shape.cornerRadius = radius.dip2px().toFloat() + shape.setColor(ContextCompat.getColor(context, color)) + background = shape +} + +fun View.setDebouncedClickListener(action: () -> Unit) { + setOnClickListener { debounceActionWithInterval(interval = 1000L) { action.invoke() } } +} + /** * LiveData Extensions */ @@ -460,6 +480,15 @@ fun FragmentActivity.checkStoragePermissionBeforeAction(action: (() -> Unit)) { }) } +/** + * List related. + */ + +// Returns the second element, or `null` if the list is empty. +fun List.secondOrNull(): T? { + return if (isEmpty() || size == 1) null else this[1] +} + /** * TextView related. */ @@ -589,7 +618,7 @@ fun DownloadEntity.addMetaExtra(key: String, value: String?) { value?.let { meta[key] = value } } -fun DownloadEntity.getMetaExtra(key: String) : String { +fun DownloadEntity.getMetaExtra(key: String): String { return meta[key] ?: "" } diff --git a/app/src/main/java/com/gh/gamecenter/entity/CommentEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/CommentEntity.kt index 026e0f0944..2c4a4b9d02 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/CommentEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/CommentEntity.kt @@ -13,10 +13,18 @@ data class CommentEntity(@SerializedName("_id") var parentUser: CommentParentEntity? = null, var content: String? = null, var vote: Int = 0, + var reply: Int = 0, var time: Long = 0, var priority: Int = 0, @SerializedName("me") - var me: MeEntity? = null) : Parcelable { + var me: MeEntity? = null, + @SerializedName("attached") // 楼中楼 + var subCommentList: ArrayList? = null) : Parcelable { + + fun clone() : CommentEntity { + return CommentEntity(id, user, parent, parentUser, content, vote, reply, time, priority, me, subCommentList) + } + companion object { const val TAG = "CommentEntity" } diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailActivity.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailActivity.kt index 98be727d64..b9a04b1a13 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailActivity.kt @@ -8,7 +8,6 @@ import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.text.TextUtils import android.view.LayoutInflater -import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.view.animation.LinearInterpolator @@ -17,24 +16,18 @@ import android.widget.ImageView import android.widget.LinearLayout import android.widget.PopupWindow import android.widget.TextView -import androidx.core.app.ActivityCompat -import androidx.core.app.ActivityOptionsCompat import androidx.core.content.ContextCompat import androidx.lifecycle.Lifecycle import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders -import butterknife.OnClick -import com.gh.base.ToolBarActivity -import com.gh.common.AppExecutor +import com.gh.base.BaseActivity import com.gh.common.TimeElapsedHelper -import com.gh.common.constant.Constants.GAME_DETAIL_COME_IN import com.gh.common.history.HistoryHelper import com.gh.common.util.* -import com.gh.common.view.DrawableView import com.gh.common.view.RichEditor import com.gh.gamecenter.ImageViewerActivity import com.gh.gamecenter.R import com.gh.gamecenter.SuggestionActivity +import com.gh.gamecenter.baselist.LoadStatus import com.gh.gamecenter.databinding.ActivityArticleDetailBinding import com.gh.gamecenter.entity.CommunityEntity import com.gh.gamecenter.entity.Permissions @@ -50,25 +43,26 @@ import com.gh.gamecenter.qa.editor.OnLinkClickListener import com.gh.gamecenter.qa.entity.ArticleDetailEntity import com.gh.gamecenter.suggest.SuggestType import com.google.android.flexbox.FlexboxLayout -import com.halo.assistant.HaloApp import com.qq.gdt.action.ActionType +import kotlinx.android.synthetic.main.activity_article_detail.* +import kotlinx.android.synthetic.main.reuse_no_connection.* import kotterknife.bindView import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import java.util.* -class ArticleDetailActivity : ToolBarActivity() { +class ArticleDetailActivity : BaseActivity() { private lateinit var mBinding: ActivityArticleDetailBinding private lateinit var mViewModel: ArticleDetailViewModel + private lateinit var mCommentListViewModel: ArticleDetailCommentViewModel private val mNoneData by bindView(R.id.reuse_none_data) private val mNoConn by bindView(R.id.reuse_no_connection) private val mNoDataText by bindView(R.id.reuse_tv_none_data) private val mLoading by bindView(R.id.reuse_ll_loading) - private val mArticleImgs = ArrayList() - + private val mArticleImgUrlList = ArrayList() private var mElapsedHelper: TimeElapsedHelper? = null private var mIsShowCommentManager: Boolean = false @@ -76,31 +70,49 @@ class ArticleDetailActivity : ToolBarActivity() { private var mSpecialColumn: SpecialColumn? = null - override fun showToolbarAtLeft(): Boolean { - return if (HaloApp.get(GAME_DETAIL_COME_IN, false) != null) { - true - } else super.showToolbarAtLeft() + override fun getLayoutId() = R.layout.activity_article_detail + + @SuppressLint("AddJavascriptInterface") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + mIsShowCommentManager = intent.getBooleanExtra(EntranceUtils.KEY_SHOW_ARTICLE_COMMENT, false) + mIsRecommendsContent = intent.getBooleanExtra(EntranceUtils.KEY_RECOMMENDS_CONTENTS, false) + + mViewModel = viewModelProvider() + mCommentListViewModel = viewModelProviderFromParent() + mViewModel.initData(intent.getParcelableExtra(EntranceUtils.KEY_COMMUNITY_DATA) + , intent.getStringExtra(EntranceUtils.KEY_COMMUNITY_ARTICLE_ID)) + mCommentListViewModel.articleId = mViewModel.articleId ?: "" + mCommentListViewModel.communityId = mViewModel.getCommunityId() ?: "" + + initView() + initToolbar() + initObserver() + + mViewModel.getArticleDetail() + + mElapsedHelper = TimeElapsedHelper(this) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == ARTICLE_PATCH_REQUEST && resultCode == Activity.RESULT_OK) { - val entity = data?.getParcelableExtra(ArticleDetailEntity::class.java.simpleName) - if (entity != null) { - mViewModel.detailEntity = entity + data?.getParcelableExtra(ArticleDetailEntity::class.java.simpleName)?.let { + mViewModel.detailEntity = it updateView() } mNoConn.performClick() //重新刷新 } else if (requestCode == ImageViewerActivity.REQUEST_FOR_VIEWED_IMAGE && resultCode == Activity.RESULT_OK) { val imageSet = data?.extras?.get(ImageViewerActivity.VIEWED_IMAGE) as HashSet // 返回时把点过的图片变为大图 - if (mArticleImgs.size > 0) { - if (imageSet.size == mArticleImgs.size) { - mBinding.articleDetailRd.replaceAllDfImage() + if (mArticleImgUrlList.size > 0) { + if (imageSet.size == mArticleImgUrlList.size) { + richEditor.replaceAllDfImage() } else { for (i in imageSet) { - val url = mArticleImgs[i.toInt()] - mBinding.articleDetailRd.replaceDfImageByUrl(url) + val url = mArticleImgUrlList[i.toInt()] + richEditor.replaceDfImageByUrl(url) } } } @@ -108,40 +120,159 @@ class ArticleDetailActivity : ToolBarActivity() { val commentCount = data?.getIntExtra(CommentActivity.COMMENT_COUNT, 0) if (commentCount != 0) { mViewModel.detailEntity?.count?.comment = commentCount!! - mBinding.includedLayout.tvCommentCount.text = String.format("评论 %s", NumberUtils.transSimpleCount(mViewModel.detailEntity?.count?.comment!!)) +// includedLayout.tvCommentCount.text = String.format("评论 %s", NumberUtils.transSimpleCount(mViewModel.detailEntity?.count?.comment!!)) if (EntranceUtils.ENTRANCE_WELCOME == mEntrance) { LogUtils.uploadCommentFromWelcomeDialog() } } } - } - - override fun getLayoutId(): Int { - return R.layout.activity_article_detail + // TODO 获取评论返回时的文字 } @SuppressLint("AddJavascriptInterface") - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setToolbarMenu(R.menu.menu_answer) - - val itemMenu = getMenuItem(R.id.menu_question_and_answer) - itemMenu.isVisible = HaloApp.get(GAME_DETAIL_COME_IN, false) != null - - setNavigationTitle(getString(R.string.community_article_detail_title)) + private fun initView() { mNoDataText.setText(R.string.content_delete_hint) - - mIsShowCommentManager = intent.getBooleanExtra(EntranceUtils.KEY_SHOW_ARTICLE_COMMENT, false) - mIsRecommendsContent = intent.getBooleanExtra(EntranceUtils.KEY_RECOMMENDS_CONTENTS, false) - mBinding = ActivityArticleDetailBinding.bind(mContentView) - mBinding.articleDetailRd.setInputEnabled(false) - mBinding.articleDetailRd.setPadding(20, 15, 20, 15) - mViewModel = ViewModelProviders.of(this).get(ArticleDetailViewModel::class.java) - mViewModel.initData(intent.getParcelableExtra(EntranceUtils.KEY_COMMUNITY_DATA) - , intent.getStringExtra(EntranceUtils.KEY_COMMUNITY_ARTICLE_ID)) - mViewModel.getArticleDetail() + richEditor.setInputEnabled(false) + richEditor.setPadding(20, 15, 20, 15) + richEditor.addJavascriptInterface(JsInterface(), "imagelistener") + richEditor.addJavascriptInterface(OnLinkClickListener(this, mEntrance, "社区文章详情"), "OnLinkClickListener") + + window.decorView.postDelayed({ + // TODO 复用 fragment + // TODO ConsecutiveLayout 滑动卡顿,得放弃 + val transaction = supportFragmentManager.beginTransaction() + transaction.replace( + R.id.fragmentPlaceholder, + ArticleDetailCommentFragment.getInstance(mViewModel.articleId + ?: "", mViewModel.getCommunityId() ?: ""), + ArticleDetailCommentFragment::class.java.simpleName) + transaction.commitAllowingStateLoss() + }, 500) + + likeContainer.setDebouncedClickListener { + mViewModel.detailEntity?.let { + ifLogin("社区文章详情-赞同") { + if (!it.me.isCommunityArticleVote) { + mViewModel.likeArticle() + if (EntranceUtils.ENTRANCE_WELCOME == mEntrance) { + LogUtils.uploadLikeFromWelcomeDialog() + } + } else { + mViewModel.cancelLikeArticle() + } + } + } + } + bottomLikeContainer.setOnClickListener { likeIv.performClick() } + + shareContainer.setOnClickListener { + mViewModel.detailEntity?.let { + GdtHelper.logAction(ActionType.SHARE, + GdtHelper.CONTENT_TYPE, "QA_ARTICLE", + GdtHelper.CONTENT_ID, mViewModel.articleId) + + var shareSummary = richEditor.text + val shareIcon: String = if (mArticleImgUrlList.size > 0) { + mArticleImgUrlList[0] + } else { + getString(R.string.share_ghzs_logo) + } + if (TextUtils.isEmpty(shareSummary)) { + shareSummary = getString(R.string.ask_share_default_summary) + } + ShareUtils.getInstance(this).showShareWindows(this, mContentView, + getString(R.string.share_community_article_url, it.community.id, it.id), + shareIcon, getString(R.string.share_community_article_title, it.user.name, + it.title, it.count.vote), shareSummary, ShareUtils.ShareEntrance.communityArticle, + it.id) + } + } + + starContainer.setDebouncedClickListener { + mViewModel.detailEntity?.let { + ifLogin(entrance = "社区文章详情-收藏") { + mViewModel.collectionCommand(!it.me.isCommunityArticleFavorite, callback = { + mViewModel.detailEntity?.me?.isCommunityArticleFavorite = it + if (it) { + GdtHelper.logAction(ActionType.ADD_TO_WISHLIST, + GdtHelper.CONTENT_TYPE, "QA_ARTICLE", + GdtHelper.CONTENT_ID, mViewModel.articleId) + } + updateCollectView(it) + }) + } + } + } + + dislikeContainer.setDebouncedClickListener { + mViewModel.detailEntity?.let { + ifLogin("社区文章详情-反对") { + if (!it.me.isCommunityArticleOppose) { + mViewModel.dislikeArticle() + } else { + mViewModel.cancelDislikeArticle() + } + } + } + } + + followBtn.setOnClickListener { + mViewModel.detailEntity?.let { + ifLogin("社区文章详情-[关注]用户") { + if (followBtn.text == "关注") { + mViewModel.follow() + } else { + DialogUtils.showAlertDialog(this, + "取消关注", + "确定要取消关注 ${it.user.name} 吗?", + "确定取消", + "暂不取消", + DialogUtils.ConfirmListener { + mViewModel.unfollow() + }, null) + } + } + } + } + + userNameTv.setOnClickListener { + mViewModel.detailEntity?.let { + DirectUtils.directToHomeActivity(this, it.user.id, mEntrance, "社区文章详情") + } + } + userIconContainer.setOnClickListener { userNameTv.performClick() } + + replyTv.text = "说点什么吧" + replyTv.setRoundedColorBackground(R.color.text_F0F0F0, 19F) + replyTv.setOnClickListener { + mViewModel.detailEntity?.let { + val intent = CommentActivity.getArticleCommentIntent( + this, + mViewModel.articleId!!, + it.count.comment, + true, + it.community.id, + true) + startActivityForResult(intent, CommentActivity.REQUEST_CODE) + } + } + + reuse_no_connection.setOnClickListener { + mNoConn.visibility = View.GONE + mLoading.visibility = View.VISIBLE + mViewModel.getArticleDetail() + } + + bottomCommentContainer.setOnClickListener { consecutiveScrollerView.smoothScrollToChild(filterView) } + + if (mIsShowCommentManager) { + mBaseHandler.postDelayed({ replyTv.performClick() }, 500) + } + } + + private fun initObserver() { mViewModel.articleLiveData.observe(this, Observer { when (it?.status) { Status.SUCCESS -> { @@ -168,10 +299,9 @@ class ArticleDetailActivity : ToolBarActivity() { toast(R.string.content_delete_toast) } - val menu = menu - if (menu != null) { - for (i in 0 until menu.size()) { - menu.getItem(i).isVisible = false + toolbar.menu?.run { + for (i in 0 until size()) { + getItem(i).isVisible = false } } } else { @@ -180,9 +310,10 @@ class ArticleDetailActivity : ToolBarActivity() { } mLoading.visibility = View.GONE - mBinding.articleDetailContent.visibility = View.GONE - mBinding.includedLayout.containerControl.visibility = View.GONE - mBinding.articleDetailLine3.visibility = View.GONE + consecutiveScrollerView.visibility = View.GONE + // TODO 显示底部阴影 +// includedLayout.containerControl.visibility = View.GONE +// articleDetailLine3.visibility = View.GONE } } }) @@ -206,9 +337,6 @@ class ArticleDetailActivity : ToolBarActivity() { toast("取消赞同") } updateLikeView(mViewModel.detailEntity!!.me.isCommunityArticleVote, mViewModel.detailEntity!!.count.vote) - if (it.isGuideFollow) { - showFollowHint() - } } mViewModel.highlight.observeNonNull(this) { isHighlighted -> @@ -247,214 +375,61 @@ class ArticleDetailActivity : ToolBarActivity() { updateDislikeView(disliked) } - mViewModel.commentable.observeNonNull(this) { enable -> - mViewModel.detailEntity?.commentable = enable - updateCommentable(enable) - } - - mBinding.articleDetailRd.addJavascriptInterface(JsInterface(), "imagelistener") - mBinding.articleDetailRd.addJavascriptInterface(OnLinkClickListener(this, mEntrance, "社区文章详情"), "OnLinkClickListener") - - if (mIsShowCommentManager) { - mBaseHandler.postDelayed({ mBinding.includedLayout.ivComment.performClick() }, 500) - } - - mElapsedHelper = TimeElapsedHelper(this) - } - - private fun updateCommentable(commentable: Boolean) { - if (commentable) { - mBinding.includedLayout.tvCommentCount.text = String.format("评论 %d", - mViewModel.detailEntity?.count?.comment ?: 0) - mBinding.includedLayout.ivComment.setImageResource(R.drawable.community_content_detail_comment_open) - mBinding.includedLayout.tvCommentCount.setTextColor(ContextCompat.getColor(this, R.color.text_242529)) - } else { - mBinding.includedLayout.tvCommentCount.text = "评论已关闭" - mBinding.includedLayout.ivComment.setImageResource(R.drawable.community_content_detail_comment_close) - mBinding.includedLayout.tvCommentCount.setTextColor(ContextCompat.getColor(this, R.color.text_b3b3b3)) + mCommentListViewModel.loadStatusLiveData.observeNonNull(this) { status -> + when (status) { + LoadStatus.INIT, + LoadStatus.INIT_LOADING, + LoadStatus.INIT_LOADED, + LoadStatus.LIST_LOADING, + LoadStatus.LIST_LOADED, + LoadStatus.LIST_OVER, + LoadStatus.INIT_OVER, + LoadStatus.LIST_FAILED -> { + // Do nothing + } + LoadStatus.INIT_FAILED -> { + // TODO 处理评论加载失败 + toast("评论加载失败") + } + LoadStatus.INIT_EMPTY -> { + // TODO 处理评论为空 + toast("评论为空") + } + } } } - override fun onMenuItemClick(item: MenuItem?): Boolean { - mViewModel.detailEntity?.let { - when (item?.itemId) { - R.id.menu_more -> showMoreItemDialog() - R.id.menu_question_and_answer -> { - HaloApp.remove(GAME_DETAIL_COME_IN) - DirectUtils.directToCommunity(this, it.community) - - LogUtils.qaAccess("文章详情-进入问答", it.community) - MtaHelper.onEvent("进入问答", "文章详情", it.community.name + "+" + StringUtils.combineTwoString(it.title, it.id)) - } - } - } - return super.onMenuItemClick(item) - } - - @OnClick(R.id.rl_comment, - R.id.container_like, - R.id.iv_share, - R.id.tv_share, - R.id.tv_collect, - R.id.iv_collect, - R.id.container_dislike, - R.id.article_detail_follow, - R.id.reuse_no_connection, - R.id.article_detail_usericon_container, - R.id.article_detail_username) - fun onClick(v: View) { - when (v.id) { - R.id.rl_comment -> { - if (mViewModel.detailEntity != null) { - if (mViewModel.detailEntity?.commentable == true) { - val intent = CommentActivity.getArticleCommentIntent(this, mViewModel.articleId!! - , mViewModel.detailEntity?.count?.comment - , mViewModel.detailEntity?.count?.comment == 0 - , mViewModel.detailEntity?.community?.id!!) - startActivityForResult(intent, CommentActivity.REQUEST_CODE) - } else { - toast("作者已关闭评论") - } - } - } - R.id.tv_collect, R.id.iv_collect -> { - if (mViewModel.detailEntity != null) { - debounceActionWithInterval(R.id.tv_collect, 1000) { - ifLogin(entrance = "社区文章详情-收藏") { - mViewModel.collectionCommand(!mViewModel.detailEntity?.me?.isCommunityArticleFavorite!!, callback = { - mViewModel.detailEntity?.me?.isCommunityArticleFavorite = it - if (it) { - GdtHelper.logAction(ActionType.ADD_TO_WISHLIST, - GdtHelper.CONTENT_TYPE, "QA_ARTICLE", - GdtHelper.CONTENT_ID, mViewModel.articleId) - } - updateCollectView(it) - }) - } - } - } - } - R.id.container_dislike -> { - if (mViewModel.detailEntity != null) { - debounceActionWithInterval(R.id.container_like, 1000) { - ifLogin("社区文章详情-反对") { - if (!mViewModel.detailEntity!!.me.isCommunityArticleOppose) { - mViewModel.dislikeArticle() - } else { - mViewModel.cancelDislikeArticle() - } - } - } - } - } - R.id.tv_share, R.id.iv_share -> { - if (mViewModel.detailEntity != null) { - GdtHelper.logAction(ActionType.SHARE, - GdtHelper.CONTENT_TYPE, "QA_ARTICLE", - GdtHelper.CONTENT_ID, mViewModel.articleId) - - var shareSummary = mBinding.articleDetailRd.text - val shareIcon: String = if (mArticleImgs.size > 0) { - mArticleImgs[0] - } else { - getString(R.string.share_ghzs_logo) - } - if (TextUtils.isEmpty(shareSummary)) { - shareSummary = getString(R.string.ask_share_default_summary) - } - ShareUtils.getInstance(this).showShareWindows(this, mContentView, - getString(R.string.share_community_article_url, mViewModel.detailEntity?.community?.id, mViewModel.detailEntity?.id), - shareIcon, getString(R.string.share_community_article_title, mViewModel.detailEntity?.user?.name, - mViewModel.detailEntity?.title, mViewModel.detailEntity?.count?.vote), shareSummary, ShareUtils.ShareEntrance.communityArticle, - mViewModel.detailEntity?.id ?: "") - } - } - R.id.container_like -> { - if (mViewModel.detailEntity != null) { - debounceActionWithInterval(R.id.container_like, 1000) { - ifLogin("社区文章详情-赞同") { - if (!mViewModel.detailEntity?.me?.isCommunityArticleVote!!) { - mViewModel.likeArticle() - if (EntranceUtils.ENTRANCE_WELCOME == mEntrance) { - LogUtils.uploadLikeFromWelcomeDialog() - } - } else { - mViewModel.cancelLikeArticle() - } - } - } - } - } - R.id.reuse_no_connection -> { - mNoConn.visibility = View.GONE - mLoading.visibility = View.VISIBLE - mViewModel.getArticleDetail() - } - R.id.article_detail_follow -> { - if (mViewModel.detailEntity != null) { - ifLogin("社区文章详情-[关注]用户") { - if (mBinding.articleDetailFollow.text == "关注") { - mViewModel.follow() - } else { - DialogUtils.showAlertDialog(this, - "取消关注", - "确定要取消关注 ${mViewModel.detailEntity?.user?.name} 吗?", - "确定取消", - "暂不取消", - DialogUtils.ConfirmListener { - mViewModel.unfollow() - }, null) - } - } - } - } - R.id.article_detail_usericon_container, - R.id.article_detail_username -> { - if (mViewModel.detailEntity != null) { - DirectUtils.directToHomeActivity(this, - mViewModel.detailEntity?.user?.id, mEntrance, "社区文章详情") - } - } + private fun initToolbar() { + toolbar.inflateMenu(R.menu.menu_answer) + toolbar.setNavigationOnClickListener { onBackPressed() } + toolbar.menu.findItem(R.id.menu_more).setOnMenuItemClickListener { + consume { mViewModel.detailEntity?.let { showMoreItemDialog() } } } + toolbar.menu.findItem(R.id.menu_question_and_answer).isVisible = false } private fun updateFollowBtn(isFollowed: Boolean) { if (isFollowed) { - if (mBinding.articleDetailFollow.visibility == View.GONE) return - - mBinding.articleDetailFollow.text = "已关注" - mBinding.articleDetailFollow.background = null - mBinding.articleDetailFollow.setTextColor(ContextCompat.getColor(this, R.color.text_999999)) - mBinding.articleDetailFollow.postDelayed({ - mBinding.articleDetailFollow.animate() + if (followBtn.visibility == View.GONE) return + followBtn.text = "已关注" + followBtn.background = null + followBtn.setTextColor(ContextCompat.getColor(this, R.color.text_999999)) + followBtn.postDelayed({ + followBtn.animate() .alpha(0f) .setInterpolator(LinearInterpolator()) .doOnEnd { if (this != null && !this.isFinishing) { - mBinding.articleDetailFollow.visibility = View.GONE + followBtn.visibility = View.GONE } } .setDuration(500L) .start() }, 2000L) } else { - mBinding.articleDetailFollow.background = ContextCompat.getDrawable(this, R.drawable.questions_detail_tag_bg) - mBinding.articleDetailFollow.setTextColor(ContextCompat.getColor(this, R.color.theme_font)) - mBinding.articleDetailFollow.setText(R.string.concern) - } - } - - private fun showFollowHint() { - if (mBinding.articleDetailFollow.visibility == View.VISIBLE - && mViewModel.detailEntity != null - && !mViewModel.detailEntity!!.me.isContentOwner) { - mBinding.tvFollowHint.visibility = View.VISIBLE - mBinding.tvFollowHint.animate().alpha(1.0f).setDuration(750).start() - AppExecutor.uiExecutor.executeWithDelay(Runnable { - if (this != null && !this!!.isFinishing) { - mBinding.tvFollowHint.visibility = View.GONE - } - }, 3000L) + followBtn.setRoundedColorBackground(R.color.text_EEF5FB, 14F) + followBtn.setTextColor(ContextCompat.getColor(this, R.color.theme_font)) + followBtn.setText(R.string.concern) } } @@ -462,21 +437,21 @@ class ArticleDetailActivity : ToolBarActivity() { @JavascriptInterface fun imageClick(url: String) { if (url.contains("web_load_dfimg_icon.png")) { - mBaseHandler.post { mBinding.articleDetailRd.replaceAllDfImageExcludeGif() } + mBaseHandler.post { richEditor.replaceAllDfImageExcludeGif() } } else if (url.contains(RichEditor.IMAGE_FLAG_THUMBNAIL)) { - mBaseHandler.post { mBinding.articleDetailRd.replaceDfImageByUrl(url) } + mBaseHandler.post { richEditor.replaceDfImageByUrl(url) } } else { var current = 0 var i = 0 - val size = mArticleImgs.size + val size = mArticleImgUrlList.size while (i < size) { - if (url.contains(mArticleImgs.get(i))) { + if (url.contains(mArticleImgUrlList.get(i))) { current = i } i++ } - val intent = ImageViewerActivity.getIntent(baseContext, mArticleImgs, current, - mEntrance + "+(社区文章详情[" + mBinding.articleDetailTitle.text.toString() + "])") + val intent = ImageViewerActivity.getIntent(baseContext, mArticleImgUrlList, current, + mEntrance + "+(社区文章详情[" + titleTv.text.toString() + "])") startActivityForResult(intent, ImageViewerActivity.REQUEST_FOR_VIEWED_IMAGE) } } @@ -484,33 +459,29 @@ class ArticleDetailActivity : ToolBarActivity() { @JavascriptInterface fun imageArr(url: String) { val defUrl = url.split("\\?".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0] - if (!mArticleImgs.contains(defUrl) && !url.contains("web_load_dfimg_icon.png")) { - mArticleImgs.add(defUrl) + if (!mArticleImgUrlList.contains(defUrl) && !url.contains("web_load_dfimg_icon.png")) { + mArticleImgUrlList.add(defUrl) } } } private fun updateCollectView(isCollected: Boolean) { if (isCollected) { - mBinding.includedLayout.tvCollect.text = "已收藏" - mBinding.includedLayout.ivCollect.setImageResource(R.drawable.community_content_detail_collect_select) - mBinding.includedLayout.tvCollect.setTextColor(ContextCompat.getColor(this, R.color.theme_font)) + starTv.text = "已收藏" + starIv.setImageResource(R.drawable.ic_article_detail_stared) } else { - mBinding.includedLayout.tvCollect.text = "收藏" - mBinding.includedLayout.ivCollect.setImageResource(R.drawable.community_content_detail_collect_unselect) - mBinding.includedLayout.tvCollect.setTextColor(ContextCompat.getColor(this, R.color.text_242529)) + starTv.text = "收藏" + starIv.setImageResource(R.drawable.ic_article_detail_star) } } private fun showMoreItemDialog() { if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) || mViewModel.detailEntity != null) { val view = LayoutInflater.from(this).inflate(R.layout.menu_answer_detail_more, null) - val popupWindow = PopupWindow( - view, + val popupWindow = PopupWindow(view, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT - ) - popupWindow.apply { + ).apply { setBackgroundDrawable(ColorDrawable(0)) isTouchable = true isFocusable = true @@ -518,14 +489,14 @@ class ArticleDetailActivity : ToolBarActivity() { } view.measure(0, 0) val viewWidth = view.measuredWidth - popupWindow.showAsDropDown(mToolbar.menu.getItem(2).actionView, -viewWidth - 10, 10) + popupWindow.showAsDropDown(toolbar.menu.getItem(2).actionView, -viewWidth - 10, 10) val homeContainer = view.findViewById(R.id.container_home) val reportContainer = view.findViewById(R.id.container_report) + val shareContainer = view.findViewById(R.id.container_share) val reportTv = view.findViewById(R.id.tv_report) val reportIv = view.findViewById(R.id.iv_report) - val commentControlContainer = view.findViewById(R.id.container_comment_control) if (mViewModel.detailEntity?.me!!.isModerator) { val controlView = view.findViewById(R.id.container_control) controlView.visibility = View.VISIBLE @@ -540,39 +511,6 @@ class ArticleDetailActivity : ToolBarActivity() { reportIv.setImageResource(R.drawable.menu_more_edit) } - if (mViewModel.detailEntity?.me!!.isContentOwner) { - commentControlContainer.visibility = View.VISIBLE - val commentControlTv = commentControlContainer.findViewById(R.id.tv_comment_control) - val commentControlIv = commentControlContainer.findViewById(R.id.iv_comment_control) - if (mViewModel.detailEntity?.commentable!!) { - commentControlIv.setImageResource(R.drawable.ic_close_comment) - commentControlTv.text = "关闭评论" - } else { - commentControlTv.text = "恢复评论" - commentControlIv.setImageResource(R.drawable.ic_open_comment) - } - commentControlContainer.setOnClickListener { - popupWindow.dismiss() - - if (mViewModel.detailEntity?.commentable!!) { - DialogUtils.showAlertDialog(this, "提示", "关闭评论之后,该回答将无法查看和发表评论,确定关闭吗?", - "确定", "取消", { - mViewModel.toggleComment( - mViewModel.detailEntity?.community!!.id, - mViewModel.articleId!!, - false) - }, null) - } else { - DialogUtils.showAlertDialog(this, "提示", "确定恢复评论吗?", - "确定", "取消", { - mViewModel.toggleComment( - mViewModel.detailEntity?.community!!.id, - mViewModel.articleId!!, - true) - }, null) - } - } - } homeContainer.setOnClickListener { val community = mViewModel.detailEntity?.community DirectUtils.directToCommunity(this, community) @@ -588,6 +526,12 @@ class ArticleDetailActivity : ToolBarActivity() { "文章投诉(" + mViewModel.articleId + "):") } } + + shareContainer.visibility = View.VISIBLE + shareContainer.setOnClickListener { + shareIv.performClick() + popupWindow.dismiss() + } } } @@ -649,127 +593,124 @@ class ArticleDetailActivity : ToolBarActivity() { private fun updateView() { val detailEntity = mViewModel.detailEntity ?: return - - mBinding.includedLayout.run { - if (detailEntity.me.isCommunityArticleFavorite) { - ivCollect.setImageResource(R.drawable.community_content_detail_collect_select) - tvCollect.text = "已收藏" - tvCollect.setTextColor(ContextCompat.getColor(this@ArticleDetailActivity, R.color.theme_font)) - } else { - ivCollect.setImageResource(R.drawable.community_content_detail_collect_unselect) - tvCollect.text = "收藏" - tvCollect.setTextColor(ContextCompat.getColor(this@ArticleDetailActivity, R.color.text_242529)) - } + if (detailEntity.me.isCommunityArticleFavorite) { + starIv.setImageResource(R.drawable.ic_article_detail_stared) + starTv.text = "已收藏" + } else { + starIv.setImageResource(R.drawable.ic_article_detail_star) + starTv.text = "收藏" } mBinding.detail = detailEntity - mBinding.articleDetailRd.setContentOwner(detailEntity.me.isContentOwner) - mBinding.articleDetailRd.setHtml(detailEntity.content, true) - mBinding.includedLayout.tvCommentCount.text = String.format("评论 %s", - NumberUtils.transSimpleCount(detailEntity.count.comment)) + richEditor.setContentOwner(detailEntity.me.isContentOwner) + richEditor.setHtml(detailEntity.content, true) + + commentCountTv.text = NumberUtils.transSimpleCount(detailEntity.count.comment) + if (detailEntity.count.comment == 0) { + bottomCommentTv.text = "评论" + } else { + bottomCommentTv.text = NumberUtils.transSimpleCount(detailEntity.count.comment) + } if (detailEntity.time.create == detailEntity.time.edit) { - mBinding.articleDetailTime.text = String.format("发布于 %s", NewsUtils.getFormattedTime(detailEntity.time.create)) + releaseTimeTv.text = String.format("发布于 %s", NewsUtils.getFormattedTime(detailEntity.time.create)) } else { - mBinding.articleDetailTime.text = String.format("编辑于 %s", NewsUtils.getFormattedTime(detailEntity.time.edit)) + releaseTimeTv.text = String.format("编辑于 %s", NewsUtils.getFormattedTime(detailEntity.time.edit)) } mNoConn.visibility = View.GONE mLoading.visibility = View.GONE - mBinding.articleDetailContent.visibility = View.VISIBLE - mBinding.includedLayout.containerControl.visibility = View.VISIBLE - mBinding.articleDetailLine3.visibility = View.VISIBLE + richEditor.visibility = View.VISIBLE +// includedLayout.containerControl.visibility = View.VISIBLE +// articleDetailLine3.visibility = View.VISIBLE - mBinding.articleDetailContent.viewTreeObserver.addOnScrollChangedListener { - if (mBinding.articleDetailContent.scrollY > mBinding.articleDetailTitle.bottom) { - var title = detailEntity.title - if (title.length > 10) { - title = title.substring(0, 10) + "..." - } - setNavigationTitle(title) - } else { - setNavigationTitle(getString(R.string.community_article_detail_title)) + consecutiveScrollerView.setOnVerticalScrollChangeListener { _, _, _, _ -> + if (consecutiveScrollerView.ownScrollY > 54F.dip2px() + && forumGameIv.visibility != View.VISIBLE) { + forumGameIv.visibility = View.VISIBLE + ImageUtils.display(forumGameIv.getIconIv(), detailEntity.community.icon) + ImageUtils.display(forumGameIv.getIconDecoratorIv(), detailEntity.community.iconSubscript) + + forumTitleTv.text = detailEntity.community.name + } else if (consecutiveScrollerView.ownScrollY < 54F.dip2px() && + forumGameIv.visibility == View.VISIBLE) { + forumGameIv.visibility = View.GONE + forumTitleTv.text = "" } } - mBinding.articleDetailTags.removeAllViews() + tagsFlexbox.removeAllViews() addTag(detailEntity.community.name, true) for (tag in detailEntity.tags) { addTag(tag) } - mBinding.articleDetailFollow.visibility = View.VISIBLE + followBtn.visibility = View.VISIBLE if (detailEntity.user.id == UserManager.getInstance().userId) { - mBinding.articleDetailFollow.isEnabled = false - mBinding.articleDetailFollow.setText(R.string.myself) - mBinding.articleDetailFollow.setTextColor(ContextCompat.getColor(this, R.color.button_gray)) - mBinding.articleDetailFollow.setBackgroundResource(R.drawable.button_border_gray) + followBtn.isEnabled = false + followBtn.setText(R.string.myself) + followBtn.setTextColor(ContextCompat.getColor(this, R.color.button_gray)) + followBtn.setBackgroundResource(R.drawable.button_border_gray) } else { - mBinding.articleDetailFollow.isEnabled = true + followBtn.isEnabled = true if (detailEntity.me.isFollower) { - mBinding.articleDetailFollow.visibility = View.GONE + followBtn.visibility = View.GONE } else { updateFollowBtn(false) } } - if (detailEntity.user.badge != null) { - mBinding.sdvUserBadge.visibility = View.VISIBLE - mBinding.tvBadgeName.visibility = View.VISIBLE - ImageUtils.display(mBinding.sdvUserBadge, detailEntity.user.badge?.icon) - mBinding.tvBadgeName.text = detailEntity.user.badge?.name - } else { - mBinding.sdvUserBadge.visibility = View.GONE - mBinding.tvBadgeName.visibility = View.GONE - } - mBinding.sdvUserBadge.setOnClickListener { + badgeIv.goneIf(detailEntity.user.badge == null) + badgeTv.goneIf(detailEntity.user.badge == null) + badgeTv.text = detailEntity.user.badge?.name + ImageUtils.display(badgeIv, detailEntity.user.badge?.icon) + badgeIv.setOnClickListener { MtaHelper.onEvent("进入徽章墙_用户记录", "社区文章详情", "${detailEntity.user.name}(${detailEntity.user.id})") MtaHelper.onEvent("徽章中心", "进入徽章中心", "社区文章详情") DirectUtils.directToBadgeWall(this, mViewModel.detailEntity?.user?.id, detailEntity.user.name, detailEntity.user.icon) } - mBinding.tvBadgeName.setOnClickListener { mBinding.sdvUserBadge.performClick() } + badgeTv.setOnClickListener { badgeIv.performClick() } - updateCommentable(detailEntity.commentable!!) updateLikeView(detailEntity.me.isCommunityArticleVote, detailEntity.count.vote) updateDislikeView(detailEntity.me.isCommunityArticleOppose) } @SuppressLint("SetTextI18n") - private fun updateLikeView(alreadyVoted: Boolean, voteCount: Int) { - mBinding.includedLayout.tvLike.text = "赞同 ${NumberUtils.transSimpleCount(voteCount)}" - if (alreadyVoted) { - mBinding.includedLayout.ivLike.setImageResource(R.drawable.community_content_detail_vote_select) - mBinding.includedLayout.tvLike.setTextColor(ContextCompat.getColor(this, R.color.theme_font)) + private fun updateLikeView(alreadyLiked: Boolean, likeCount: Int) { + likeTv.text = if (likeCount == 0) "赞同" else likeCount.toString() + if (alreadyLiked) { + likeIv.setImageResource(R.drawable.ic_article_detail_liked) + bottomLikeIv.setImageResource(R.drawable.ic_article_detail_liked) } else { - mBinding.includedLayout.ivLike.setImageResource(R.drawable.community_content_detail_vote_unselect) - mBinding.includedLayout.tvLike.setTextColor(ContextCompat.getColor(this, R.color.text_242529)) + likeIv.setImageResource(R.drawable.ic_article_detail_like) + bottomLikeIv.setImageResource(R.drawable.ic_article_detail_like_bottom_bar) } } private fun updateDislikeView(disliked: Boolean) { if (disliked) { - mBinding.includedLayout.ivDislike.setImageResource(R.drawable.community_content_detail_oppose_select) + dislikeIv.setImageResource(R.drawable.ic_article_detail_disliked) } else { - mBinding.includedLayout.ivDislike.setImageResource(R.drawable.community_content_detail_oppose_unselect) + dislikeIv.setImageResource(R.drawable.ic_article_detail_dislike) } } private fun addTag(tag: String, isCommunityName: Boolean = false) { val view = LayoutInflater.from(this).inflate(R.layout.questionsdedit_tag_item, null) val tagTv = view as TextView + val params = FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) + params.setMargins(0, 5F.dip2px(), 8F.dip2px(), 5F.dip2px()) + tagTv.text = tag - tagTv.background = DrawableView.getOvalDrawable(R.color.text_EEF5FB, 2F) - tagTv.setTextColor(if (!isCommunityName) R.color.theme_font.toColor() else R.color.text_333333.toColor()) + tagTv.setTextColor(if (!isCommunityName) R.color.theme_font.toColor() else R.color.text_666666.toColor()) + tagTv.setPadding(14F.dip2px(), 5F.dip2px(), 14F.dip2px(), 5F.dip2px()) if (isCommunityName) { - tagTv.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(this, R.drawable.ic_video_detail_game), null, null, null) + // TODO 水平padding不对 + tagTv.setRoundedColorBackground(R.color.text_F5F5F5, 5F) + tagTv.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(this, R.drawable.ic_article_detail_forum_tag), null, null, null) tagTv.compoundDrawablePadding = 4F.dip2px() - } - val params = FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT) - params.setMargins(0, DisplayUtils.dip2px(this, 5f), DisplayUtils.dip2px(this, 8f), - DisplayUtils.dip2px(this, 5f)) - tagTv.layoutParams = params - if (!isCommunityName) { + } else { + tagTv.setRoundedColorBackground(R.color.text_EEF5FB, 5F) tagTv.setOnClickListener { MtaHelper.onEvent("问题标签", mViewModel.detailEntity?.community?.name, mViewModel.detailEntity!!.title + "-" + tag) startActivity(AskColumnDetailActivity.getIntentByTag(this, tag, @@ -777,7 +718,8 @@ class ArticleDetailActivity : ToolBarActivity() { mViewModel.detailEntity!!.community.name), mEntrance, "问题详情")) } } - mBinding.articleDetailTags.addView(view) + tagTv.layoutParams = params + tagsFlexbox.addView(view) } override fun onDestroy() { diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailCommentAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailCommentAdapter.kt new file mode 100644 index 0000000000..88b9875416 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailCommentAdapter.kt @@ -0,0 +1,127 @@ +package com.gh.gamecenter.qa.article.detail + +import android.annotation.SuppressLint +import android.content.Context +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.constant.ItemViewType +import com.gh.common.util.* +import com.gh.gamecenter.R +import com.gh.gamecenter.adapter.viewholder.FooterViewHolder +import com.gh.gamecenter.baselist.ListAdapter +import com.gh.gamecenter.databinding.ItemArticleDetailCommentBinding +import com.gh.gamecenter.entity.CommentEntity +import com.halo.assistant.HaloApp +import com.lightgame.utils.Utils + +class ArticleDetailCommentAdapter(context: Context, var viewModel: ArticleDetailCommentViewModel) : ListAdapter(context) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return when (viewType) { + ItemViewType.ITEM_FOOTER -> { + val view = mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false) + FooterViewHolder(view) + } + else -> { + val binding: ItemArticleDetailCommentBinding = DataBindingUtil.inflate(mLayoutInflater, R.layout.item_article_detail_comment, parent, false) + ArticleDetailCommentViewHolder(binding) + } + } + } + + override fun getItemViewType(position: Int): Int { + if (position == itemCount - 1) return ItemViewType.ITEM_FOOTER + return ItemViewType.ITEM_BODY + } + + override fun getItemCount() = if (mEntityList.isNotEmpty()) mEntityList.size + FOOTER_ITEM_COUNT else 0 + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (holder) { + is ArticleDetailCommentViewHolder -> { + holder.bindComment(mEntityList[position], viewModel) + } + + is FooterViewHolder -> { + holder.initItemPadding() + holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_hint) + } + } + } + + class ArticleDetailCommentViewHolder(var binding: ItemArticleDetailCommentBinding) : RecyclerView.ViewHolder(binding.root) { + @SuppressLint("SetTextI18n") + fun bindComment(comment: CommentEntity, viewModel: ArticleDetailCommentViewModel) { + binding.comment = comment + + binding.floorHintTv.text = "${adapterPosition + 1}F" + binding.iconContainer.setOnClickListener { + // TODO 补全路径 + DirectUtils.directToHomeActivity(binding.root.context, comment.user.id, 2, "", "") + } + binding.userNameTv.setOnClickListener { binding.iconContainer.performClick() } + + updateSubComment(comment.subCommentList) + + binding.likeCountTv.text = viewModel.getLikeText(comment.vote) + binding.commentCountTv.text = viewModel.getCommentText(comment.reply) + + if (comment.me?.isCommentVoted == true) { + binding.likeCountTv.setCompoundDrawablesWithIntrinsicBounds(R.drawable.comment_vote_select, 0, 0, 0) + } else { + binding.likeCountTv.setCompoundDrawablesWithIntrinsicBounds(R.drawable.comment_vote_unselect, 0, 0, 0) + } + + binding.likeCountTv.setDebouncedClickListener { + if (comment.me?.isCommentVoted != true) { + viewModel.like(comment) + } else { + Utils.toast(HaloApp.getInstance().application, "已点过赞了") + } + } + binding.commentCountTv.setOnClickListener { + // TODO 弹起软键盘输入框记录回复对象 + } + + binding.badgeTv.setOnClickListener { + MtaHelper.onEvent("进入徽章墙_用户记录", "社区文章详情-评论管理", comment.user.name + "(" + comment.user.id + ")") + MtaHelper.onEvent("徽章中心", "进入徽章中心", "社区文章详情-评论管理") + DirectUtils.directToBadgeWall(binding.root.context, comment.user.id, comment.user.name, comment.user.icon) + } + binding.badgeIv.setOnClickListener { binding.badgeTv.performClick() } + + binding.moreIv.setOnClickListener { + CommentHelper.showCommunityArticleCommentOptions( + it, + comment, + false, + viewModel.articleId, + viewModel.communityId, + null) + } + } + + + @SuppressLint("SetTextI18n") + fun updateSubComment(subCommentList: ArrayList?) { + binding.subCommentContainer.goneIf(subCommentList.isNullOrEmpty()) + binding.firstSubCommentTv.goneIf(subCommentList?.firstOrNull() == null) + binding.secondSubCommentTv.goneIf(subCommentList?.secondOrNull() == null) + binding.moreSubCommentBtn.goneIf(subCommentList == null || subCommentList.size < 3) + + subCommentList?.firstOrNull()?.let { + binding.firstSubCommentTv.text = "${it.user.name}:${it.content}" + } + subCommentList?.secondOrNull()?.let { + binding.secondSubCommentTv.text = "${it.user.name}:${it.content}" + } + + binding.moreSubCommentBtn.setOnClickListener { + // 调到回复详情页 + } + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailCommentFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailCommentFragment.kt new file mode 100644 index 0000000000..f4f99016cc --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailCommentFragment.kt @@ -0,0 +1,65 @@ +package com.gh.gamecenter.qa.article.detail + +import android.graphics.drawable.InsetDrawable +import android.os.Bundle +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.util.DisplayUtils +import com.gh.common.util.viewModelProviderFromParent +import com.gh.common.view.CustomDividerItemDecoration +import com.gh.gamecenter.R +import com.gh.gamecenter.baselist.ListAdapter +import com.gh.gamecenter.baselist.ListFragment +import com.gh.gamecenter.entity.CommentEntity +import com.gh.gamecenter.qa.comment.CommentType +import com.gh.gamecenter.qa.comment.NewCommentViewModel +import com.halo.assistant.HaloApp + +class ArticleDetailCommentFragment : ListFragment() { + + private var mAdapter: ArticleDetailCommentAdapter? = null + private lateinit var mViewModel: ArticleDetailCommentViewModel + + override fun getLayoutId() = R.layout.fragment_article_detail_comment + + override fun onCreate(savedInstanceState: Bundle?) { + mViewModel = provideListViewModel() + super.onCreate(savedInstanceState) + } + + override fun provideListViewModel(): ArticleDetailCommentViewModel { + return viewModelProviderFromParent(NewCommentViewModel.Factory( + application = HaloApp.getInstance().application, + articleId = arguments?.getString(ARTICLE_ID) ?: "", + communityId = arguments?.getString(COMMUNITY_ID) ?: "", + commentType = CommentType.COMMUNITY_ARTICLE)) + } + + override fun provideListAdapter(): ListAdapter<*> { + return mAdapter + ?: ArticleDetailCommentAdapter(requireContext(), mViewModel).apply { mAdapter = this } + } + + override fun getItemDecoration(): RecyclerView.ItemDecoration { + val insetDivider = InsetDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.divider_article_detail_comment), DisplayUtils.dip2px(20F), 0, DisplayUtils.dip2px(20F), 0) + val itemDecoration = CustomDividerItemDecoration(requireContext(), notDecorateTheLastItem = true) + itemDecoration.setDrawable(insetDivider) + return itemDecoration + } + + companion object { + const val ARTICLE_ID = "article_id" + const val COMMUNITY_ID = "community_id" + + fun getInstance(articleId: String, communityId: String): Fragment { + return ArticleDetailCommentFragment().apply { + arguments = Bundle().apply { + putString(ARTICLE_ID, articleId) + putString(COMMUNITY_ID, communityId) + } + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailCommentViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailCommentViewModel.kt new file mode 100644 index 0000000000..2744532123 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailCommentViewModel.kt @@ -0,0 +1,79 @@ +package com.gh.gamecenter.qa.article.detail + +import android.app.Application +import com.gh.common.util.PostCommentUtils +import com.gh.common.util.PostCommentUtils.PostCommentListener +import com.gh.common.util.ToastUtils.showToast +import com.gh.gamecenter.entity.CommentEntity +import com.gh.gamecenter.qa.comment.CommentType +import com.gh.gamecenter.qa.comment.NewCommentViewModel +import com.gh.gamecenter.retrofit.RetrofitManager +import com.lightgame.utils.Utils +import io.reactivex.Observable +import org.json.JSONObject +import retrofit2.HttpException + +class ArticleDetailCommentViewModel(application: Application) : NewCommentViewModel(application, commentType = CommentType.COMMUNITY_ARTICLE) { + + override fun provideDataObservable(page: Int): Observable> { + return RetrofitManager.getInstance(getApplication()).api.getCommunityArticleCommentList(communityId, articleId, page) + } + + override fun mergeResultLiveData() { + mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) } + } + + fun getLikeText(likeCount: Int): String { + return if (likeCount == 0) "赞同" else "$likeCount" + } + + fun getCommentText(commentCount: Int): String { + return if (commentCount == 0) "评论" else "$commentCount" + } + + fun like(comment: CommentEntity) { + PostCommentUtils.likeComment(getApplication(), null, articleId, communityId, null, comment.id, + object : PostCommentListener { + override fun postSuccess(response: JSONObject?) { + updateLike(comment.id ?: "", true) + } + + override fun postFailed(e: Throwable) { + if (e is HttpException) { + if (e.code() == 403) { + try { + val detail = JSONObject(e.response().errorBody()!!.string()).getString("detail") + if ("voted" == detail) { + showToast("已经点过赞啦!") + } + } catch (ex: Exception) { + ex.printStackTrace() + } + return + } + } + Utils.toast(getApplication(), "网络异常,点赞失败") + } + }) + } + + private fun updateLike(commentId: String, isLiked: Boolean = false) { + mResultLiveData.value?.let { + for ((i, item) in it.withIndex()) { + if (item != null) { + if (item.id == commentId) { + if (isLiked) { + item.me?.isCommentVoted = true + item.vote++ + } + + it[i] = item.clone() + break + } + } + } + mResultLiveData.postValue(it) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailViewModel.kt index cb8dc7a344..7a8ab73a1f 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailViewModel.kt @@ -21,13 +21,9 @@ import com.gh.gamecenter.retrofit.RetrofitManager import com.lightgame.utils.Utils import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers -import okhttp3.MediaType -import okhttp3.RequestBody import okhttp3.ResponseBody import org.greenrobot.eventbus.EventBus -import org.json.JSONObject import retrofit2.HttpException -import java.util.* class ArticleDetailViewModel(application: Application) : AndroidViewModel(application) { @@ -55,6 +51,8 @@ class ArticleDetailViewModel(application: Application) : AndroidViewModel(applic this.community = community } + fun getCommunityId() = community?.id + fun getArticleDetail() { mApi .getCommunityArticleDetail(community?.id, articleId) @@ -270,22 +268,22 @@ class ArticleDetailViewModel(application: Application) : AndroidViewModel(applic }) } - fun toggleComment(communityId: String, articleId: String, isCommentable: Boolean) { - val params = HashMap() - params["commentable"] = isCommentable - val body = RequestBody.create(MediaType.parse("application/json"), - JSONObject(params).toString()) - - mApi.postCommunityArticleCommentable(communityId, articleId, body) - .subscribeOn(Schedulers.io()) - .subscribe(object : Response() { - override fun onResponse(response: ResponseBody?) { - commentable.postValue(isCommentable) - } - - override fun onFailure(e: HttpException?) { - Utils.toast(getApplication(), e?.message()) - } - }) - } +// fun toggleComment(communityId: String, articleId: String, isCommentable: Boolean) { +// val params = HashMap() +// params["commentable"] = isCommentable +// val body = RequestBody.create(MediaType.parse("application/json"), +// JSONObject(params).toString()) +// +// mApi.postCommunityArticleCommentable(communityId, articleId, body) +// .subscribeOn(Schedulers.io()) +// .subscribe(object : Response() { +// override fun onResponse(response: ResponseBody?) { +// commentable.postValue(isCommentable) +// } +// +// override fun onFailure(e: HttpException?) { +// Utils.toast(getApplication(), e?.message()) +// } +// }) +// } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/CommentActivity.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/CommentActivity.kt index e9eadd3bc9..acfcd1624d 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/comment/CommentActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/comment/CommentActivity.kt @@ -3,17 +3,14 @@ package com.gh.gamecenter.qa.comment import android.app.Activity import android.content.Context import android.content.Intent -import android.graphics.Color import android.os.Bundle import android.view.View -import androidx.core.app.ActivityCompat import butterknife.OnClick import com.gh.base.BaseActivity import com.gh.common.util.DisplayUtils import com.gh.common.util.doOnEnd import com.gh.gamecenter.R import com.gh.gamecenter.qa.answer.detail.AnswerDetailFragment -import com.lightgame.config.CommonDebug import com.lightgame.utils.Util_System_Keyboard import kotlinx.android.synthetic.main.activity_comment.* @@ -21,6 +18,7 @@ import kotlinx.android.synthetic.main.activity_comment.* class CommentActivity : BaseActivity() { val resultIntent = Intent() + private var mShowInputOnly = false override fun getLayoutId(): Int { return R.layout.activity_comment @@ -39,6 +37,8 @@ class CommentActivity : BaseActivity() { val videoId = intent.getStringExtra(VIDEO_ID) val isVideoAuthor = intent.getBooleanExtra(IS_VIDEO_AUTHOR, false) + mShowInputOnly = intent.getBooleanExtra(SHOW_INPUT_ONLY, false) + val commentCallback = object : AnswerDetailFragment.CommentListener { override fun onCountChange(count: Int) { resultIntent.putExtra(COMMENT_COUNT, count) @@ -63,6 +63,7 @@ class CommentActivity : BaseActivity() { communityId, showKeyboard, commentCount, + mShowInputOnly, commentCallback) } else { NewCommentFragment.getVideoCommentInstance( @@ -112,6 +113,8 @@ class CommentActivity : BaseActivity() { const val ARTICLE_ID = "article_id" const val COMMUNITY_ID = "community_id" + const val SHOW_INPUT_ONLY = "show_input_only" + const val VIDEO_ID = "video_id" const val REQUEST_CODE = 8123 @@ -142,14 +145,18 @@ class CommentActivity : BaseActivity() { } @JvmStatic - fun getArticleCommentIntent(context: Context, articleId: String, commentCount: Int? = 0, + fun getArticleCommentIntent(context: Context, + articleId: String, + commentCount: Int? = 0, showKeyboard: Boolean, - communityId: String): Intent { + communityId: String, + showInputOnly: Boolean = false): Intent { val intent = Intent(context, CommentActivity::class.java) intent.putExtra(ARTICLE_ID, articleId) intent.putExtra(COMMENT_COUNT, commentCount) intent.putExtra(SHOW_KEYBOARD, showKeyboard) intent.putExtra(COMMUNITY_ID, communityId) + intent.putExtra(SHOW_INPUT_ONLY, showInputOnly) if (context is Activity) { context.overridePendingTransition(0, 0) } diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt index fd02453f33..e0954d4db2 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt @@ -10,7 +10,6 @@ import android.view.View import android.view.inputmethod.InputMethodManager import android.widget.* import androidx.annotation.Nullable -import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.lifecycle.Observer import androidx.recyclerview.widget.RecyclerView @@ -38,7 +37,6 @@ import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode - open class NewCommentFragment : ListFragment(), OnCommentCallBackListener, KeyboardHeightObserver, OnCommentOptionClickListener { @Nullable @@ -81,6 +79,7 @@ open class NewCommentFragment : ListFragment protected var mCommunityId: String = "" protected var mVideoId: String = "" protected var mCommentId: String = "" + protected var mShowInputOnly: Boolean = false // 是否只显示输入框,不显示列表 protected var mIsVideoAuthor: Boolean = false//是否是视频作者 protected var mCommentType = CommentType.ANSWER @@ -106,6 +105,11 @@ open class NewCommentFragment : ListFragment mSendingDialog?.dismiss() toast("发表成功") + if (mShowInputOnly) { + requireActivity().finish() + return@Observer + } + if (mCommentEntity != null) { // 补充默认草稿 mCommentEntity = null // 清空当前评论实体 commentEt.hint = getString(R.string.message_detail_comment_hint) @@ -159,7 +163,7 @@ open class NewCommentFragment : ListFragment if (this is NewCommentConversationFragment) { onLoadRefresh() EventBus.getDefault().post(EBDeleteComment(it)) - }else { + } else { val indexOf = mAdapter?.getEntityList()?.indexOf(it) ?: 0 mAdapter?.getEntityList()?.remove(it) mAdapter?.notifyItemRemoved(indexOf) @@ -178,6 +182,10 @@ open class NewCommentFragment : ListFragment override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + if (mShowInputOnly) { + commentContainer.visibility = View.GONE + } + commentEt.isFocusable = true commentEt.isFocusableInTouchMode = true commentEt.setTextChangedListener { s, _, _, _ -> @@ -254,6 +262,8 @@ open class NewCommentFragment : ListFragment return VerticalItemDecoration(context, 0f, true) } + override fun isAutomaticLoad() = !mShowInputOnly + override fun provideListViewModel(): NewCommentViewModel { mViewModel = viewModelProvider( NewCommentViewModel.Factory( @@ -326,6 +336,9 @@ open class NewCommentFragment : ListFragment } R.id.shadowView -> { Util_System_Keyboard.hideSoftKeyboard(context, commentEt) + if (mShowInputOnly && activity is CommentActivity) { + requireActivity().finish() + } } } } @@ -418,7 +431,7 @@ open class NewCommentFragment : ListFragment mShadowView.goneIf(!isPopup) if (requireActivity() is CommentDetailActivity) { val shadowView = (requireActivity() as CommentDetailActivity).shadowView - shadowView.visibility = if (isPopup) View.VISIBLE else View.GONE + shadowView.visibility = if (isPopup && !mShowInputOnly) View.VISIBLE else View.GONE DisplayUtils.setLightStatusBar(requireActivity(), !isPopup) shadowView.setOnClickListener { Util_System_Keyboard.hideSoftKeyboard(activity) } } @@ -461,7 +474,7 @@ open class NewCommentFragment : ListFragment @Subscribe(threadMode = ThreadMode.MAIN) fun onEvent(entity: EBDeleteComment) { //查看对话页面删除评论需同步评论列表 - if(this !is NewCommentConversationFragment) { + if (this !is NewCommentConversationFragment) { val currentEntity = mAdapter?.getEntityList()?.find { it.id == entity.commentEntity.id } val indexOf = mAdapter?.getEntityList()?.indexOf(currentEntity) ?: 0 mAdapter?.getEntityList()?.remove(currentEntity) @@ -480,6 +493,7 @@ open class NewCommentFragment : ListFragment const val COMMENT_PAUSE = "comment_pause" const val COMMENT_RESUME = "comment_resume" + // TODO 改成 argument 形式的入参 fun getAnswerCommentInstance(answerId: String, showSoftKeyboardOnStartUp: Boolean, commentCount: Int, @@ -498,6 +512,7 @@ open class NewCommentFragment : ListFragment communityId: String, showSoftKeyboardOnStartUp: Boolean, commentCount: Int, + showInputOnly: Boolean, listener: AnswerDetailFragment.CommentListener) : NewCommentFragment { return NewCommentFragment().apply { @@ -506,6 +521,7 @@ open class NewCommentFragment : ListFragment mCommentCount = commentCount mCommentListener = listener mCommunityId = communityId + mShowInputOnly = showInputOnly mCommentType = CommentType.COMMUNITY_ARTICLE } } diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentViewModel.kt index db3b7f21ec..318d5ef677 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentViewModel.kt @@ -23,14 +23,14 @@ import okhttp3.ResponseBody import org.json.JSONObject import retrofit2.HttpException -class NewCommentViewModel(application: Application, +open class NewCommentViewModel(application: Application, var answerId: String = "", var commentId: String = "", var articleId: String = "", var communityId: String = "", var videoId: String = "", var commentType: CommentType = CommentType.ANSWER, - var isVideoAuthor: Boolean) + var isVideoAuthor: Boolean = false) : ListViewModel(application) { private val mPostCommentLiveData = MutableLiveData>() @@ -201,12 +201,12 @@ class NewCommentViewModel(application: Application, } class Factory(private val application: Application, - private val answerId: String, - private val commentId: String, - private val articleId: String, - private val communityId: String, - private val videoId: String, - private val isVideoAuthor: Boolean, + private val answerId: String = "", + private val commentId: String = "", + private val articleId: String = "", + private val communityId: String = "", + private val videoId: String = "", + private val isVideoAuthor: Boolean = false, private val commentType: CommentType) : ViewModelProvider.NewInstanceFactory() { override fun create(modelClass: Class): T { diff --git a/app/src/main/res/drawable-xxxhdpi/ic_article_detail_comment_bottom_bar.png b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_comment_bottom_bar.png new file mode 100644 index 0000000000000000000000000000000000000000..9f36d91fc63e82517863597edc9230cbfd2c7f2b GIT binary patch literal 2274 zcma);cTiL58pZ=sLQ4c`(p=CL2#b^~U<6!HLRkq21PCP%AOt~*(vh}dC<{nkm!{}l z5dvJ4P^I?{1{Ktx5Q=aK;?j{S-p|QQW@o)SbHADMp5ODl&->2#_GtRE^E-s%L_Q*u;G6)YY?>9z{<1bxA5&kR_1Sm{}lWB zO#k0uZD8*Kz~X|TjcsVxy>h&8sed6uA$*Jj?x%cx6i_E1D%OC$-SzTM-*xcIQ+1=Ye zIQ)D>?CS7Y=%w`2Meh|$a;nC&e$fq)yyT6z2dpx;+RO#EB>IY3)vNnZ6wU3vmCU(;4Y@nC9eB#V=)eVHb<8hs&_U?keA@ z+vn)BL#qn|n!NAlyjyGc+mtkow!>;aP&|s0+>%$gO-!ebJYkx~E4tVfN##(7c*<60 z!L;3XYB%?d5$$r~#MH1&=1!=(M8xd_<{C~#kCYlzsAKy0Nz^>5{ELF0ICG|W3ni*> z%F0Aaws2rjd^socCk8$~s#i*3byhC1H~rVoM1<{rkkvJKR)BS9-J>Y24e6r6lvjnl z19n3~(P^o0ba14iGd6}_Ct5NwKv89Wp+xm0!mrmaQqxAuhB}rY@IY&I%U~~`=%SUf zHnSQuXlKWq<>DCsb@uhN!P=Durl)1UT%+-)fQAUq>QE6HihKp3Crg1ui21i=CGo~K zi%HZ*>QXoYHS%NJ_!#K|KKf0+Op?helRW1>9>%p_2vw94md)^xk$i#V+BFnZlbBUH z+Qpa5-R^hXx>=}hMqLvZfFDJDf3&-fZRJz#%Ny#1F>dV}HE7qBWaoJ&E^gu(X~|KD z<{KxD?l`CokF1SAsJCc5ZludnE&+kkrw{44_~b})bt#va5b(XILp*5=j#p=vYgCOu zulK3z6;M3plD9f4oKupwmy#6S+*5VVuf=ZD;m+h_#WA?+u&Vg2^E15u9XxL*NSb5k56<6pmCrqh7gfJNIlLrK zOI6AcyE{;KSGQSys=7?_nS0@-z`@c@?$dC^r>gT&_tvKgjeWqnHe~op5w_K_H{?J`qgEQxf%(%QvS$rcvq+Me)MWwrnmJnWAb_0M{%h3bY#x?j6$HwDoyTSVOq{cymz`X48;i8C?==&jy{KkI Ya`*bnOz*hFuYW3LXbYn!mk4qH1&7E9=l}o! literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_article_detail_comment_list.png b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_comment_list.png new file mode 100644 index 0000000000000000000000000000000000000000..54b0ce020cea8e4411560c6bd4ba1b78cbd77859 GIT binary patch literal 2190 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_article_detail_like.png b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_like.png new file mode 100644 index 0000000000000000000000000000000000000000..9f5557e902e980a386a24a09faebd4c34f5cf789 GIT binary patch literal 3377 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 Hu0mjffaX;u literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_article_detail_like_bottom_bar.png b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_like_bottom_bar.png new file mode 100644 index 0000000000000000000000000000000000000000..5f38eb40ac94c2fd1644a3bb58e07547be4b6b6a GIT binary patch literal 2428 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 BR$u@C literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_article_detail_liked.png b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_liked.png new file mode 100644 index 0000000000000000000000000000000000000000..a006f08afae11eb8c48d1477845b7f0fa635a3d0 GIT binary patch literal 2400 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 HLX7?|e_T19 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/divider_article_detail_comment.xml b/app/src/main/res/drawable/divider_article_detail_comment.xml new file mode 100644 index 0000000000..57ffd4abfe --- /dev/null +++ b/app/src/main/res/drawable/divider_article_detail_comment.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_article_detail.xml b/app/src/main/res/layout/activity_article_detail.xml index 49f3ee5afc..c6f53a781e 100644 --- a/app/src/main/res/layout/activity_article_detail.xml +++ b/app/src/main/res/layout/activity_article_detail.xml @@ -13,241 +13,547 @@ + android:layout_height="match_parent" + android:background="@color/white"> - + - + + + + + + + + + android:layout_above="@+id/bottomContainer" + android:layout_below="@+id/toolbar" + android:background="@android:color/white"> + + - - - - - - + android:layout_height="wrap_content"> + app:layout_constraintTop_toTopOf="parent"> - + app:layout_constraintLeft_toRightOf="@id/userIconContainer" + app:layout_constraintRight_toLeftOf="@+id/followBtn" + app:layout_constraintTop_toTopOf="@+id/userIconContainer"> - + + + + + + + + + + - - - - - - - - - - - - - + app:layout_constraintTop_toTopOf="@id/userIconContainer" + tools:text="关注" + tools:visibility="visible" /> - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + android:layout_height="50dp" + android:layout_alignParentBottom="true"> - + + + + + + + + + + + + + + + + + + + android:layout_below="@+id/toolbar" /> + android:layout_below="@+id/toolbar" /> + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_article_detail_comment.xml b/app/src/main/res/layout/item_article_detail_comment.xml new file mode 100644 index 0000000000..d470c382e9 --- /dev/null +++ b/app/src/main/res/layout/item_article_detail_comment.xml @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/menu_answer_detail_more.xml b/app/src/main/res/layout/menu_answer_detail_more.xml index 5bc7fb50ab..06873be633 100644 --- a/app/src/main/res/layout/menu_answer_detail_more.xml +++ b/app/src/main/res/layout/menu_answer_detail_more.xml @@ -132,6 +132,36 @@ android:textSize="15sp" /> + + + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index ea5b08db3c..a6c5c8fc7c 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -128,6 +128,7 @@ #f67722 #989898 #333333 + #444444 #eeeeee #cccccc #f2f2f2