package com.gh.gamecenter.message; import static com.gh.gamecenter.personal.PersonalFragment.LOGIN_TAG; import android.app.Activity; import android.app.Dialog; import android.content.Intent; import android.os.Bundle; import android.text.Editable; import android.text.InputFilter; import android.text.TextUtils; import android.text.TextWatcher; import android.view.View; import android.widget.LinearLayout; import android.widget.RelativeLayout; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.gh.common.constant.Config; import com.gh.common.util.CheckLoginUtils; import com.gh.common.util.DialogUtils; import com.gh.gamecenter.common.callback.ConfirmListener; import com.gh.gamecenter.core.utils.DisplayUtils; import com.gh.gamecenter.common.constant.EntranceConsts; import com.gh.common.util.ErrorHelper; import com.gh.gamecenter.core.utils.GsonUtils; import com.gh.gamecenter.core.utils.KeyboardHeightObserver; import com.gh.gamecenter.core.utils.KeyboardHeightProvider; import com.gh.common.util.PostCommentUtils; import com.gh.gamecenter.common.utils.TextHelper; import com.gh.gamecenter.common.utils.TimestampUtils; import com.gh.gamecenter.core.utils.UrlFilterUtils; import com.gh.gamecenter.MessageDetailActivity; import com.gh.gamecenter.R; import com.gh.gamecenter.adapter.MessageDetailAdapter; import com.gh.gamecenter.adapter.OnCommentCallBackListener; import com.gh.gamecenter.databinding.FragmentMessageDetailBinding; import com.gh.gamecenter.entity.CommentEntity; import com.gh.gamecenter.entity.CommentnumEntity; import com.gh.gamecenter.entity.ConcernEntity; import com.gh.gamecenter.entity.UserInfoEntity; import com.gh.gamecenter.entity.ViewsEntity; import com.gh.gamecenter.eventbus.EBReuse; import com.gh.gamecenter.manager.CommentManager; import com.gh.gamecenter.manager.UserManager; import com.gh.gamecenter.common.base.fragment.ToolbarFragment; import com.gh.gamecenter.common.retrofit.OkHttpCache; import com.gh.gamecenter.common.retrofit.Response; import com.gh.gamecenter.retrofit.RetrofitManager; import com.halo.assistant.HaloApp; import com.lightgame.listeners.OnBackPressedListener; import com.lightgame.utils.Util_System_Keyboard; import com.lightgame.utils.Utils; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.List; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; import retrofit2.HttpException; /** * Created by CsHeng on 18/12/2017. * 消息详情界面--评论详情--对话详情 */ public class MessageDetailFragment extends ToolbarFragment implements OnCommentCallBackListener, OnBackPressedListener, KeyboardHeightObserver { public static final int REQUEST_UPDATE_COMMENT = 9; // 刷新文章web页面评论数 private FragmentMessageDetailBinding mBinding; private LinearLayoutManager mLayoutManager; private MessageDetailAdapter adapter; private Dialog mSendingDialog; private ConcernEntity mConcernEntity; private CommentEntity mCommentEntity; // 回复评论的实体 用完马上清空 private UserInfoEntity mUserInfo; private String newsId; private int commentNum = -1; //区分来源 -1:资讯关注列表 !=-1 :新闻详情 private KeyboardHeightProvider mKeyboardHeightProvider = null; private int mOffset = 0; private TextWatcher watcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (s.toString().trim().length() > 0) { mBinding.pieceCommentTypingContainer.answerCommentSendBtn.setEnabled(true); } else { mBinding.pieceCommentTypingContainer.answerCommentSendBtn.setEnabled(false); } } @Override public void afterTextChanged(Editable s) { } }; @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(CommentEntity.TAG, adapter.getConcernEntity()); } @Override protected int getLayoutId() { return 0; } @Override protected View getInflatedLayout() { mBinding = FragmentMessageDetailBinding.inflate(getLayoutInflater()); return mBinding.getRoot(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle args = getArguments(); // mConcernEntity = args.getParcelable(ConcernEntity.TAG); mConcernEntity = (ConcernEntity) HaloApp.get(ConcernEntity.TAG, true); mCommentEntity = args.getParcelable(CommentEntity.TAG); newsId = args.getString(EntranceConsts.KEY_NEWSID); commentNum = args.getInt("commentNum", -1); //复用问题 mConcernEntity对应的文章有可能和跳转之前的文章不一致 if (mConcernEntity != null && newsId != null && !newsId.equals(mConcernEntity.getId())) { mConcernEntity = null; } setNavigationTitle(getString(R.string.title_message_detail)); adapter = new MessageDetailAdapter(getActivity(), this, mBinding.messageDetailRv, mConcernEntity, mEntrance); mLayoutManager = new LinearLayoutManager(getContext()); mBinding.messageDetailRv.setLayoutManager(mLayoutManager); mBinding.messageDetailRv.setAdapter(adapter); mBinding.pieceCommentTypingContainer.answerCommentEt.addTextChangedListener(watcher); mBinding.pieceCommentTypingContainer.answerCommentEt.setFilters(new InputFilter[]{TextHelper.getFilter(140, "评论不能多于140字")}); mBinding.pieceCommentTypingContainer.answerCommentSendBtn.setEnabled(false); mKeyboardHeightProvider = new KeyboardHeightProvider(requireActivity()); mBinding.messageDetailRv.post(mKeyboardHeightProvider::start); mBinding.pieceCommentTypingContainer.answerCommentEt.setOnFocusChangeListener((v, hasFocus) -> { if (hasFocus) { mBinding.pieceCommentTypingContainer.answerCommentEt.setHintTextColor(ContextCompat.getColor(getContext(), R.color.hint)); } else { mBinding.pieceCommentTypingContainer.answerCommentEt.setHintTextColor(ContextCompat.getColor(getContext(), R.color.theme_font)); } }); mBinding.messageDetailRv.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { if (newState == RecyclerView.SCROLL_STATE_IDLE && !adapter.isOver() && !adapter.isLoading() && mConcernEntity != null && mLayoutManager.findLastVisibleItemPosition() == adapter.getItemCount() - 1) { int offset = adapter.getItemCount() - adapter.getHotCommentListSize() - 3; if (offset >= 10) { // 防止自动上滑时触发 adapter.addNormalComment(); } } } }); mUserInfo = UserManager.getInstance().getUserInfoEntity(); if (newsId != null && mConcernEntity == null) { getConcernDigest(); } if (args.getBoolean("openSoftInput", false)) {//新闻详情的发表评论 setSoftInput(true); } mBinding.reuseNoConnection.getRoot().setOnClickListener(v -> { if (newsId != null && mConcernEntity == null) { showNoConnection(false); } }); mBinding.pieceCommentTypingContainer.answerCommentSendBtn.setOnClickListener(this); mBinding.shadowView.setOnClickListener(this); } public void getCommentNum() { RetrofitManager.getInstance().getApi() .getNewsCommentnum(newsId, Utils.getTime(getContext())) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Response>() { @Override public void onResponse(List response) { super.onResponse(response); if (response.size() > 0) { if (!TextUtils.isEmpty(mConcernEntity.getId())) { commentNum = response.get(0).getNum(); mConcernEntity.setCommentnum(commentNum); adapter.notifyItemChanged(0); } } } }); } private void getConcernDigest() { RetrofitManager.getInstance().getApi().getNewsRichDigest(newsId) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Response() { @Override public void onResponse(ConcernEntity response) { mConcernEntity = response; if (commentNum == -1) { getCommentNum(); } else { mConcernEntity.setCommentnum(commentNum); } adapter.addConcernEntity(mConcernEntity); adapter.notifyDataSetChanged(); adapter.addHotComment(); getNewsViews(); if (commentNum == 0) { setSoftInput(true); } } @Override public void onFailure(HttpException e) { showNoConnection(true); } }); } private void getNewsViews() { RetrofitManager.getInstance().getApi() .getArticlesVisits(UrlFilterUtils.getFilterQuery("article_ids", newsId)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Response>() { @Override public void onResponse(List viewsEntities) { if (viewsEntities.size() > 0) { mConcernEntity.setViews(viewsEntities.get(0).getViews()); adapter.notifyItemChanged(0); } } }); } //软键盘控制 private void setSoftInput(boolean isShow) { if (isShow) { String entrance = "资讯文章详情-评论详情-回复"; if (mCommentEntity == null) { entrance = "资讯文章详情-评论详情-评论数"; } CheckLoginUtils.checkLogin(getContext(), entrance, () -> { Util_System_Keyboard.showSoftKeyboard(getContext(), mBinding.pieceCommentTypingContainer.answerCommentEt); mBinding.pieceCommentTypingContainer.answerCommentEt.setFocusable(true); mBinding.pieceCommentTypingContainer.answerCommentEt.setFocusableInTouchMode(true); mBinding.pieceCommentTypingContainer.answerCommentEt.requestFocus(); if (mCommentEntity != null && mCommentEntity.getUser() != null) { mBinding.pieceCommentTypingContainer.answerCommentEt.setHint(getString(R.string.comment_repty_hint, mCommentEntity.getUser().getName())); } else { mBinding.pieceCommentTypingContainer.answerCommentEt.setHint(getString(R.string.message_detail_comment_hint)); } }); } else { Util_System_Keyboard.hideSoftKeyboard(getActivity()); if (mCommentEntity != null) { mCommentEntity = null; // 清空当前评论实体 mBinding.pieceCommentTypingContainer.answerCommentEt.setHint(getString(R.string.message_detail_comment_hint)); mBinding.pieceCommentTypingContainer.answerCommentEt.setText(""); } } } @Override public void onClick(View view) { switch (view.getId()) { case R.id.answer_comment_send_btn: final String content = mBinding.pieceCommentTypingContainer.answerCommentEt.getText().toString(); if (content.length() == 0) { Utils.toast(getContext(), "评论内容不能为空!"); return; } CheckLoginUtils.checkLogin(requireContext(), "资讯文章详情-评论详情-写评论", () -> { mSendingDialog = DialogUtils.showWaitDialog(getActivity(), getString(R.string.post_dialog_hint)); JSONObject jsonObject = new JSONObject(); try { jsonObject.put("content", content); } catch (JSONException e) { e.printStackTrace(); } if (newsId == null && mConcernEntity == null || newsId == null && mConcernEntity.getId() == null) { Utils.toast(getContext(), "评论异常 id null"); mSendingDialog.cancel(); return; } else if (newsId == null) { newsId = mConcernEntity.getId(); } PostCommentUtils.addCommentData(getContext(), newsId, jsonObject, mCommentEntity, new PostCommentUtils.PostCommentListener() { @Override public void postSuccess(JSONObject response) { mSendingDialog.dismiss(); toast("发表成功"); mBinding.pieceCommentTypingContainer.answerCommentEt.setText(""); try { JSONObject cacheObject = new JSONObject(); JSONObject cacheUser = new JSONObject(); JSONObject userData = new JSONObject(); JSONObject badgeData = new JSONObject(); cacheUser.put("_id", mUserInfo.getUserId()); cacheUser.put("icon", mUserInfo.getIcon()); cacheUser.put("name", mUserInfo.getName()); if (mUserInfo.getBadge() != null) { badgeData.put("name", mUserInfo.getBadge().getName()); badgeData.put("icon", mUserInfo.getBadge().getIcon()); cacheUser.put("badge", badgeData); } userData.put("is_comment_own", true); cacheObject.put("_id", response.getString("_id")); cacheObject.put("content", content); cacheObject.put("time", System.currentTimeMillis() / 1000); cacheObject.put("vote", 0); cacheObject.put("user", cacheUser); cacheObject.put("me", userData); if (mCommentEntity != null) { JSONObject cacheParent = new JSONObject(); cacheParent.put("user", new JSONObject(GsonUtils.toJson(mCommentEntity.getUser()))); cacheParent.put("comment", mCommentEntity.getContent()); cacheObject.put("parent", cacheParent); } CommentEntity commentEntity = GsonUtils.fromJson(cacheObject.toString(), CommentEntity.class); if (mConcernEntity != null) { adapter.addNormalComment(commentEntity); } modifyNewsCommentOkhttpCache(adapter.findTheLastPriorComment(), cacheObject, newsId); } catch (JSONException e) { e.printStackTrace(); } if (mConcernEntity != null) { // 完成评论操作,添加评论数 adapter.addCommentCount(); //修改评论缓存 CommentManager.updateOkhttpCacheForId(getContext(), newsId); CommentManager.updateOkhttpCache(getContext(), newsId); adapter.notifyItemInserted(adapter.getHotCommentListSize() + 2); adapter.notifyItemChanged(adapter.getItemCount() - 1); //刷新脚布局高度 } else { showNoConnection(false); } setSoftInput(false); } @Override public void postFailed(Throwable e) { mSendingDialog.dismiss(); String errorString = null; if (e instanceof HttpException) { try { errorString = ((HttpException) e).response().errorBody().string(); } catch (Exception e1) { e1.printStackTrace(); } } ErrorHelper.handleError(requireContext(), errorString, false, () -> mBinding.pieceCommentTypingContainer.answerCommentSendBtn.performClick()); } }); }); break; case R.id.shadowView: Util_System_Keyboard.hideSoftKeyboard(getActivity()); break; } } private void modifyNewsCommentOkhttpCache(int offset, JSONObject commentData, String id) { String key = TimestampUtils.addTimestamp(Config.API_HOST + "article/" + id + "/comment?limit=10&offset=" + offset); byte[] data = OkHttpCache.getCache(getContext(), key); if (data != null) { try { JSONArray jsonArray = new JSONArray(new String(data)); JSONArray newComment = new JSONArray(); newComment.put(commentData); for (int i = 0, size = jsonArray.length() > 9 ? 9 : jsonArray.length(); i < size; i++) { newComment.put(jsonArray.get(i)); } OkHttpCache.updateCache(getContext(), key, newComment.toString().getBytes()); if (jsonArray.length() == 10) { modifyNewsCommentOkhttpCache(offset + 10, jsonArray.getJSONObject(9), id); } } catch (JSONException e) { e.printStackTrace(); } } } private void showNoConnection(boolean isShow) { if (isShow) { mBinding.reuseNoConnection.getRoot().setVisibility(View.VISIBLE); mBinding.messageDetailRv.setVisibility(View.GONE); } else { mBinding.reuseNoConnection.getRoot().setVisibility(View.GONE); mBinding.messageDetailRv.setVisibility(View.VISIBLE); if (newsId != null) { getConcernDigest(); } } } // 登录事件 @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(EBReuse reuse) { if (reuse.getType().equals(LOGIN_TAG)) { // 登入 mUserInfo = UserManager.getInstance().getUserInfoEntity(); } } @Override public void onCommentCallback(CommentEntity entity) { mCommentEntity = entity; setSoftInput(true); } @Override public void onResume() { super.onResume(); mKeyboardHeightProvider.setKeyboardHeightObserver(this); } @Override public void onPause() { super.onPause(); mKeyboardHeightProvider.setKeyboardHeightObserver(null); } @Override public void onDestroy() { super.onDestroy(); mKeyboardHeightProvider.close(); } @Override public void onKeyboardHeightChanged(int height, int orientation) { popInputLayout(height > 0, height); } private void popInputLayout(boolean isPopup, int height) { if (requireActivity() instanceof MessageDetailActivity) { View shadowView = ((MessageDetailActivity) requireActivity()).getShadowView(); shadowView.setVisibility(isPopup ? View.VISIBLE : View.GONE); shadowView.setOnClickListener(v -> Util_System_Keyboard.hideSoftKeyboard(getActivity())); } mBinding.pieceCommentTypingContainer.commentLine.setVisibility(isPopup ? View.GONE : View.VISIBLE); mBinding.shadowView.setVisibility(isPopup ? View.VISIBLE : View.GONE); mBinding.pieceCommentTypingContainer.answerContent.setOrientation(isPopup ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL); if (isPopup) { mBinding.pieceCommentTypingContainer.answerContent.setBackground(ContextCompat.getDrawable(requireActivity(), R.drawable.bg_shape_white_radius_10_top_only)); } else { mBinding.pieceCommentTypingContainer.answerContent.setBackgroundColor(ContextCompat.getColor(requireActivity(), R.color.white)); mOffset = Math.abs(height); } DisplayUtils.setLightStatusBar(requireActivity(), !isPopup); mBinding.pieceCommentTypingContainer.placeholderView.setVisibility(isPopup ? View.VISIBLE : View.GONE); LinearLayout.LayoutParams mScrollViewParams = (LinearLayout.LayoutParams) mBinding.pieceCommentTypingContainer.scrollView.getLayoutParams(); mScrollViewParams.width = isPopup ? LinearLayout.LayoutParams.MATCH_PARENT : 0; mScrollViewParams.height = isPopup ? DisplayUtils.dip2px(76f) : DisplayUtils.dip2px(28f); mScrollViewParams.topMargin = isPopup ? DisplayUtils.dip2px(8f) : 0; mBinding.pieceCommentTypingContainer.scrollView.setLayoutParams(mScrollViewParams); RelativeLayout.LayoutParams mLayoutParams = (RelativeLayout.LayoutParams) mBinding.pieceCommentTypingContainer.answerCommentContentContainer.getLayoutParams(); mLayoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT; mLayoutParams.bottomMargin = isPopup ? height + mOffset : 0; mBinding.pieceCommentTypingContainer.answerCommentContentContainer.setLayoutParams(mLayoutParams); } @Override public boolean onHandleBackPressed() { if (commentNum != -1 && adapter.getConcernEntity() != null && commentNum != adapter.getConcernEntity().getCommentnum()) { Intent intent = new Intent(); intent.putExtra("commentNum", adapter.getConcernEntity().getCommentnum()); if (getActivity() != null) { getActivity().setResult(Activity.RESULT_OK, intent); getActivity().finish(); } return true; } return false; } @Override protected void onNightModeChange() { super.onNightModeChange(); if (adapter != null) { adapter.notifyItemRangeChanged(0, adapter.getItemCount()); } } }