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 0000000000..9f36d91fc6 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_comment_bottom_bar.png differ 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 0000000000..54b0ce020c Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_comment_list.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_article_detail_comment_more_list.png b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_comment_more_list.png new file mode 100644 index 0000000000..9b88fd9038 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_comment_more_list.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_article_detail_dislike.png b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_dislike.png new file mode 100644 index 0000000000..171c0fe3c7 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_dislike.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_article_detail_disliked.png b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_disliked.png new file mode 100644 index 0000000000..9e90a40ab7 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_disliked.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_article_detail_forum_tag.png b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_forum_tag.png new file mode 100644 index 0000000000..089f885ab6 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_forum_tag.png differ 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 0000000000..9f5557e902 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_like.png differ 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 0000000000..5f38eb40ac Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_like_bottom_bar.png differ 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 0000000000..a006f08afa Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_liked.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_article_detail_share.png b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_share.png new file mode 100644 index 0000000000..1cb471e125 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_share.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_article_detail_star.png b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_star.png new file mode 100644 index 0000000000..2f2e450826 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_star.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_article_detail_stared.png b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_stared.png new file mode 100644 index 0000000000..e6fd4f3bb9 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_article_detail_stared.png differ 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