From de08d4d32dff90d7e62cb98df113f1bd169b73ad Mon Sep 17 00:00:00 2001 From: chenjuntao Date: Thu, 22 Mar 2018 18:32:09 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E4=B8=BA=E5=9B=9E=E7=AD=94=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E6=B7=BB=E5=8A=A0=E8=AF=84=E8=AE=BA(=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E9=83=A8=E5=88=86UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 4 + .../gh/base/fragment/BaseDialogFragment.java | 22 + .../fragment/BaseDialogWrapperFragment.java | 46 ++ .../com/gh/base/fragment/BaseFragment.java | 16 +- .../java/com/gh/common/view/RichEditor.java | 2 +- .../com/gh/gamecenter/NormalActivity.java | 4 +- .../gamecenter/ask/AnswerCommentAdapter.java | 95 +++++ .../ask/AnswerCommentDialogFragment.java | 240 +++++++++++ .../gamecenter/ask/AnswerDetailFragment.java | 347 +++++++-------- .../ask/viewmodel/AnswerCommentViewModel.java | 71 ++++ .../ask/viewmodel/AnswerDetailViewModel.java | 83 ++++ .../ic_answer_comment_close.png | Bin 0 -> 348 bytes .../drawable-xhdpi/ic_answer_detail_arrow.png | Bin 0 -> 422 bytes .../ic_answer_detail_check_comment.png | Bin 0 -> 1309 bytes .../ic_answer_detail_edit_empty.png | Bin 0 -> 429 bytes .../ic_answer_detail_edit_full.png | Bin 0 -> 542 bytes .../ic_answer_detail_write_comment.png | Bin 0 -> 1260 bytes .../res/layout/fragment_answer_comment.xml | 85 ++++ .../res/layout/fragment_answer_detail.xml | 399 ++++++++++++------ .../res/layout/fragment_comment_detail.xml | 12 +- .../res/layout/fragment_dialog_wrapper.xml | 11 + app/src/main/res/menu/menu_answer_author.xml | 21 + app/src/main/res/menu/menu_answer_visitor.xml | 21 + app/src/main/res/values/strings.xml | 5 + 24 files changed, 1173 insertions(+), 311 deletions(-) create mode 100644 app/src/main/java/com/gh/base/fragment/BaseDialogWrapperFragment.java create mode 100644 app/src/main/java/com/gh/gamecenter/ask/AnswerCommentAdapter.java create mode 100644 app/src/main/java/com/gh/gamecenter/ask/AnswerCommentDialogFragment.java create mode 100644 app/src/main/java/com/gh/gamecenter/ask/viewmodel/AnswerCommentViewModel.java create mode 100644 app/src/main/java/com/gh/gamecenter/ask/viewmodel/AnswerDetailViewModel.java create mode 100644 app/src/main/res/drawable-xhdpi/ic_answer_comment_close.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_answer_detail_arrow.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_answer_detail_check_comment.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_answer_detail_edit_empty.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_answer_detail_edit_full.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_answer_detail_write_comment.png create mode 100644 app/src/main/res/layout/fragment_answer_comment.xml create mode 100644 app/src/main/res/layout/fragment_dialog_wrapper.xml create mode 100644 app/src/main/res/menu/menu_answer_author.xml create mode 100644 app/src/main/res/menu/menu_answer_visitor.xml diff --git a/app/build.gradle b/app/build.gradle index 13773b7972..292da128e6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -140,6 +140,10 @@ android { } } + dataBinding { + enabled = true + } + // productFlavors.all { flavor -> // flavor.manifestPlaceholders = [CHANNEL_VALUE: name]//命令 gradlew assembleRelease // } diff --git a/app/src/main/java/com/gh/base/fragment/BaseDialogFragment.java b/app/src/main/java/com/gh/base/fragment/BaseDialogFragment.java index ed640715ec..f47b320de4 100644 --- a/app/src/main/java/com/gh/base/fragment/BaseDialogFragment.java +++ b/app/src/main/java/com/gh/base/fragment/BaseDialogFragment.java @@ -1,11 +1,15 @@ package com.gh.base.fragment; import android.app.Dialog; +import android.arch.lifecycle.Lifecycle; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.annotation.StringRes; import android.support.v4.app.DialogFragment; import com.gh.gamecenter.R; +import com.lightgame.utils.RuntimeUtils; +import com.lightgame.utils.Utils; /** * @author CsHeng @@ -24,6 +28,24 @@ public class BaseDialogFragment extends DialogFragment { return dialog; } + public void toast(@StringRes int res) { + if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) + toast(getString(res)); + } + + public void toast(String msg) { + if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) + Utils.toast(getContext(), msg); + } + + public void toastLong(@StringRes int msg) { + toastLong(getString(msg)); + } + + public void toastLong(String msg) { + RuntimeUtils.getInstance().toastLong(getContext(), msg); + } + } diff --git a/app/src/main/java/com/gh/base/fragment/BaseDialogWrapperFragment.java b/app/src/main/java/com/gh/base/fragment/BaseDialogWrapperFragment.java new file mode 100644 index 0000000000..8dd7a98233 --- /dev/null +++ b/app/src/main/java/com/gh/base/fragment/BaseDialogWrapperFragment.java @@ -0,0 +1,46 @@ +package com.gh.base.fragment; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.gh.gamecenter.R; + +/** + * Wrap another fragment with dialog fragment. + */ +public class BaseDialogWrapperFragment extends BaseDialogFragment { + + private Fragment mFragmentToWrap; + + public static BaseDialogWrapperFragment getInstance(Fragment fragmentToWrap) { + BaseDialogWrapperFragment fragment = new BaseDialogWrapperFragment(); + fragment.mFragmentToWrap = fragmentToWrap; + return fragment; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_dialog_wrapper, null); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getChildFragmentManager().beginTransaction().replace(R.id.fragment_placeholder, mFragmentToWrap).commitNowAllowingStateLoss(); + } + + @Override + public void onStart() { + super.onStart(); + + getDialog().getWindow().setGravity(Gravity.BOTTOM); + getDialog().getWindow().setLayout(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + } +} diff --git a/app/src/main/java/com/gh/base/fragment/BaseFragment.java b/app/src/main/java/com/gh/base/fragment/BaseFragment.java index 714826f064..329915e138 100644 --- a/app/src/main/java/com/gh/base/fragment/BaseFragment.java +++ b/app/src/main/java/com/gh/base/fragment/BaseFragment.java @@ -71,6 +71,13 @@ public abstract class BaseFragment extends Fragment implements OnRequestCallB @LayoutRes protected abstract int getLayoutId(); + /** + * 提供 Inflated 的 view ,可用于 data binding. + */ + protected View getInflatedLayout() { + return null; + } + /** * 责任链,谁处理了就返回true,否则返回super.handleOnClick(View view) * @@ -106,8 +113,15 @@ public abstract class BaseFragment extends Fragment implements OnRequestCallB isEverPause = false; EventBus.getDefault().register(this); - mCachedView = View.inflate(getContext(), getLayoutId(), null); + + // For data binding. + if (getInflatedLayout() != null) { + mCachedView = getInflatedLayout(); + } else { + mCachedView = View.inflate(getContext(), getLayoutId(), null); + } ButterKnife.bind(this, mCachedView); + initView(mCachedView); } diff --git a/app/src/main/java/com/gh/common/view/RichEditor.java b/app/src/main/java/com/gh/common/view/RichEditor.java index 6bdb00ae31..2116041900 100644 --- a/app/src/main/java/com/gh/common/view/RichEditor.java +++ b/app/src/main/java/com/gh/common/view/RichEditor.java @@ -189,7 +189,7 @@ public class RichEditor extends WebView { try { exec("javascript:RE.setHtml('" + URLEncoder.encode(contents, "UTF-8") + "');"); - if (isLoadTbImage && !NetworkUtils.isWifiConnected(getContext())) { + if (isLoadTbImage && NetworkUtils.isWifiConnected(getContext())) { exec("javascript:RE.replaceTbImage()"); } diff --git a/app/src/main/java/com/gh/gamecenter/NormalActivity.java b/app/src/main/java/com/gh/gamecenter/NormalActivity.java index 6d7e00d8e1..2bf13b7333 100644 --- a/app/src/main/java/com/gh/gamecenter/NormalActivity.java +++ b/app/src/main/java/com/gh/gamecenter/NormalActivity.java @@ -161,7 +161,9 @@ public class NormalActivity extends BaseActivity implements ToolbarController, T MenuItem menuItem = menu.getItem(i); // menu设置actionLayout后,无法捕捉点击事件,以icon为tag,如果icon is null 手动设置menuItem点击事件 if (menuItem != null && menuItem.getIcon() == null) { - menuItem.getActionView().setOnClickListener((v) -> this.onMenuItemClick(menuItem)); + if (menuItem.getActionView() != null) { + menuItem.getActionView().setOnClickListener((v) -> this.onMenuItemClick(menuItem)); + } } } } diff --git a/app/src/main/java/com/gh/gamecenter/ask/AnswerCommentAdapter.java b/app/src/main/java/com/gh/gamecenter/ask/AnswerCommentAdapter.java new file mode 100644 index 0000000000..9744ae0faf --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/ask/AnswerCommentAdapter.java @@ -0,0 +1,95 @@ +package com.gh.gamecenter.ask; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.view.ViewGroup; + +import com.gh.common.constant.ItemViewType; +import com.gh.common.util.CommentUtils; +import com.gh.gamecenter.R; +import com.gh.gamecenter.adapter.OnCommentCallBackListener; +import com.gh.gamecenter.adapter.viewholder.CommentViewHolder; +import com.gh.gamecenter.adapter.viewholder.FooterViewHolder; +import com.gh.gamecenter.baselist.ListAdapter; +import com.gh.gamecenter.entity.CommentEntity; + +public class AnswerCommentAdapter extends ListAdapter { + + private OnCommentCallBackListener mOnCommentCallBackListener; + + public AnswerCommentAdapter(Context context, OnCommentCallBackListener commentCallBackListener) { + super(context); + mOnCommentCallBackListener = commentCallBackListener; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if (viewType == ItemViewType.LOADING) { + View view = mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false); + return new FooterViewHolder(view); + } else { + View view = mLayoutInflater.inflate(R.layout.comment_item, parent, false); + return new CommentViewHolder(view); + } + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + if (holder instanceof CommentViewHolder) { + initCommentViewHolder((CommentViewHolder) holder, position); + } else if (holder instanceof FooterViewHolder) { + initFooterViewHolder((FooterViewHolder) holder); + } + } + + @Override + public int getItemViewType(int position) { + if (position == getItemCount() - 1) { + return ItemViewType.LOADING; + } + + return 100; + } + + @Override + public int getItemCount() { + return mEntityList == null || mEntityList.isEmpty() ? 0 : mEntityList.size() + FOOTER_ITEM_COUNT; + } + + private void initCommentViewHolder(final CommentViewHolder holder, int position) { + final CommentEntity commentEntity = mEntityList.get(position); + + holder.commentLine.setVisibility(View.GONE); + holder.commentLineBottom.setVisibility(View.VISIBLE); + + CommentUtils.setCommentUserView(mContext, holder, commentEntity); + + CommentUtils.setCommentTime(holder.commentTimeTv, commentEntity.getTime()); + if (commentEntity.getParent() != null) { + holder.commentContentTv.setText("@" + commentEntity.getParent().getUser().getName() + ": " + commentEntity.getContent()); + } else { + holder.commentContentTv.setText(commentEntity.getContent()); + } + + holder.commentLikeIv.setOnClickListener(v -> CommentUtils.postVote(mContext, commentEntity, holder.commentLikeCountTv, holder.commentLikeIv, null)); + + holder.itemView.setOnClickListener(v -> CommentUtils.showReportDialog(commentEntity, mContext, mOnCommentCallBackListener, null)); + } + + private void initFooterViewHolder(FooterViewHolder holder) { + if (mIsNetworkError) { + holder.loading.setVisibility(View.GONE); + holder.hint.setText(R.string.loading_error_network); + } else if (!mIsOver) { + holder.hint.setText(R.string.loading); + holder.loading.setVisibility(View.VISIBLE); + } else if (mEntityList.size() == 0) { + holder.loading.setVisibility(View.GONE); + holder.hint.setText(R.string.comment_empty); + } else { + holder.hint.setText(R.string.comment_nomore); + holder.loading.setVisibility(View.GONE); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/ask/AnswerCommentDialogFragment.java b/app/src/main/java/com/gh/gamecenter/ask/AnswerCommentDialogFragment.java new file mode 100644 index 0000000000..27fb3bd32e --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/ask/AnswerCommentDialogFragment.java @@ -0,0 +1,240 @@ +package com.gh.gamecenter.ask; + +import android.app.Dialog; +import android.arch.lifecycle.ViewModelProviders; +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v7.widget.RecyclerView; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.TextView; + +import com.gh.base.fragment.BaseDialogWrapperFragment; +import com.gh.common.util.CheckLoginUtils; +import com.gh.common.util.DialogUtils; +import com.gh.common.view.VerticalItemDecoration; +import com.gh.gamecenter.R; +import com.gh.gamecenter.adapter.OnCommentCallBackListener; +import com.gh.gamecenter.ask.viewmodel.AnswerCommentViewModel; +import com.gh.gamecenter.baselist.ListAdapter; +import com.gh.gamecenter.baselist.ListFragment; +import com.gh.gamecenter.entity.CommentEntity; +import com.lightgame.utils.Util_System_Keyboard; +import com.lightgame.utils.Utils; + +import org.json.JSONObject; + +import butterknife.BindView; +import butterknife.OnClick; +import retrofit2.HttpException; + +public class AnswerCommentDialogFragment extends ListFragment implements OnCommentCallBackListener { + + @BindView(R.id.answer_comment_et) + EditText mCommentDetailCommentEt; + @BindView(R.id.answer_comment_send_btn) + TextView mCommentSend; + + private Dialog mSendingDialog; + + private CommentEntity mCommentEntity; // 回复评论的实体 用完马上清空 + + private AnswerCommentAdapter mAdapter; + + private boolean mShowSoftKeyboard; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mListViewModel.getPostCommentLiveData().observe(this, apiResponse -> { + if (apiResponse == null) return; + + if (apiResponse.getData() != null) { + mSendingDialog.dismiss(); + toast("发表成功"); + mCommentDetailCommentEt.setText(""); + + setSoftInput(false); + } else if (apiResponse.getHttpException() != null) { + mSendingDialog.dismiss(); + + HttpException exception = apiResponse.getHttpException(); + if (exception.code() == 403) { + try { + JSONObject errorJson = new JSONObject(exception.response().errorBody().string()); + String detail = errorJson.getString("detail"); + switch (detail) { + case "too frequent": + toast(R.string.comment_failed_toofrequent); + break; + case "user blocked": + toast(R.string.comment_failed_userblocked); + break; + case "article blocked": + toast(R.string.comment_failed_articleblocked); + setSoftInput(false); + break; + case "illegal": + toast(R.string.comment_failed_illegal); + break; + default: + toast(R.string.comment_failed_unknown); + break; + } + } catch (Exception ex) { + ex.printStackTrace(); + toast("评论异常"); + } + } + } else { + toast(R.string.post_failure_hint); + } + }); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + if (mShowSoftKeyboard) { + mCommentDetailCommentEt.postDelayed(() -> { + mCommentDetailCommentEt.setFocusable(true); + mCommentDetailCommentEt.setFocusableInTouchMode(true); + mCommentDetailCommentEt.requestFocus(); + InputMethodManager keyboard = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + keyboard.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + }, 200); + } + + mCommentDetailCommentEt.addTextChangedListener(watcher); + } + + @Override + protected RecyclerView.ItemDecoration getItemDecoration() { + return new VerticalItemDecoration(getContext(), 0, true); + } + + @Override + protected AnswerCommentViewModel provideListViewModel() { + return ViewModelProviders.of(this).get(AnswerCommentViewModel.class); + } + + @Override + protected ListAdapter provideListAdapter() { + return mAdapter == null ? mAdapter = new AnswerCommentAdapter(getContext(), this) : mAdapter; + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_answer_comment; + } + + public static AnswerCommentDialogFragment getInstance(boolean showSoftKeyboard) { + AnswerCommentDialogFragment fragment = new AnswerCommentDialogFragment(); + fragment.mShowSoftKeyboard = showSoftKeyboard; + return fragment; + } + + 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) { + mCommentSend.setEnabled(true); + + if (s.length() > 140) { + mCommentDetailCommentEt.setText(""); + String newText = s.toString().substring(0, 140); + mCommentDetailCommentEt.setText(newText); + mCommentDetailCommentEt.setSelection(mCommentDetailCommentEt.getText().length()); + Utils.toast(getContext(), "评论不能多于140字"); + + } + } else { + mCommentSend.setEnabled(false); + } + } + + @Override + public void afterTextChanged(Editable s) { + } + }; + + @Override + public void onCommentCallback(CommentEntity entity) { + mCommentEntity = entity; + setSoftInput(true); + } + + @OnClick({R.id.answer_comment_send_btn, R.id.answer_comment_close_iv}) + public void onClick(View view) { + switch (view.getId()) { + case R.id.answer_comment_send_btn: + postComment(); + break; + case R.id.answer_comment_close_iv: + setSoftInput(false); + Fragment fragment = getParentFragment(); + if (fragment instanceof BaseDialogWrapperFragment) { + ((BaseDialogWrapperFragment) fragment).dismiss(); + } + break; + } + } + + private void postComment() { + final String content = mCommentDetailCommentEt.getText().toString(); + + if (content.length() == 0) { + toast("评论内容不能为空!"); + return; + } + + mSendingDialog = DialogUtils.showWaitDialog(getContext(), getString(R.string.post_dialog_hint)); + + if (mCommentEntity != null && mCommentEntity.getId() == null) { + toast("评论异常 id null"); + mSendingDialog.cancel(); + return; + } + + mListViewModel.postComment(content, mCommentEntity); + } + + //软键盘控制 + private void setSoftInput(boolean isShow) { + if (isShow) { + CheckLoginUtils.checkLogin(getContext(), () -> { + Util_System_Keyboard.showSoftKeyboard(getContext(), mCommentDetailCommentEt); + mCommentDetailCommentEt.setFocusable(true); + mCommentDetailCommentEt.setFocusableInTouchMode(true); + mCommentDetailCommentEt.requestFocus(); + + if (mCommentEntity != null && mCommentEntity.getUser() != null) { + mCommentDetailCommentEt.setHint(getString(R.string.comment_repty_hint, mCommentEntity.getUser().getName())); + } else { + mCommentDetailCommentEt.setHint(getString(R.string.message_detail_comment_hint)); + } + }); + } else { + Util_System_Keyboard.hideSoftKeyboard(getContext(), mCommentDetailCommentEt); + + if (mCommentEntity != null) { + mCommentEntity = null; // 清空当前评论实体 + mCommentDetailCommentEt.setHint(getString(R.string.message_detail_comment_hint)); + mCommentDetailCommentEt.setText(""); + } + } + } +} diff --git a/app/src/main/java/com/gh/gamecenter/ask/AnswerDetailFragment.java b/app/src/main/java/com/gh/gamecenter/ask/AnswerDetailFragment.java index 4f0749d857..976973a7f7 100644 --- a/app/src/main/java/com/gh/gamecenter/ask/AnswerDetailFragment.java +++ b/app/src/main/java/com/gh/gamecenter/ask/AnswerDetailFragment.java @@ -1,7 +1,10 @@ package com.gh.gamecenter.ask; import android.app.Activity; +import android.arch.lifecycle.ViewModelProviders; import android.content.Intent; +import android.databinding.BindingAdapter; +import android.databinding.DataBindingUtil; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -14,7 +17,7 @@ import android.widget.ImageView; import android.widget.TextView; import com.facebook.drawee.view.SimpleDraweeView; -import com.gh.common.util.AskLogUtils; +import com.gh.base.fragment.BaseDialogWrapperFragment; import com.gh.common.util.AskUtils; import com.gh.common.util.CheckLoginUtils; import com.gh.common.util.CollectionUtils; @@ -26,14 +29,15 @@ import com.gh.common.view.RichEditor; import com.gh.gamecenter.NormalActivity; import com.gh.gamecenter.QuestionsDetailActivity; import com.gh.gamecenter.R; +import com.gh.gamecenter.SuggestionActivity; import com.gh.gamecenter.ViewImageActivity; import com.gh.gamecenter.ask.entity.AnswerDetailEntity; import com.gh.gamecenter.ask.entity.MeEntity; import com.gh.gamecenter.ask.questionsdetail.AnswerEditFragment; +import com.gh.gamecenter.ask.viewmodel.AnswerDetailViewModel; +import com.gh.gamecenter.databinding.FragmentAnswerDetailBinding; import com.gh.gamecenter.entity.UserEntity; import com.gh.gamecenter.normal.NormalFragment; -import com.gh.gamecenter.retrofit.Response; -import com.gh.gamecenter.retrofit.RetrofitManager; import com.lightgame.utils.Utils; import org.json.JSONObject; @@ -43,15 +47,12 @@ import java.util.ArrayList; import butterknife.BindView; import butterknife.OnClick; -import okhttp3.ResponseBody; import retrofit2.HttpException; -import rx.android.schedulers.AndroidSchedulers; -import rx.schedulers.Schedulers; /** * Created by khy on 17/12/17. + * Modified by juntao on 18/3/21. */ - public class AnswerDetailFragment extends NormalFragment { @BindView(R.id.answer_detail_title) @@ -60,8 +61,6 @@ public class AnswerDetailFragment extends NormalFragment { RichEditor mRichEditor; @BindView(R.id.answer_detail_time) TextView mTime; - @BindView(R.id.answer_detail_edit) - TextView mEditBtn; @BindView(R.id.answer_detail_vote) ImageView mVote; @BindView(R.id.answer_detail_vote_count) @@ -80,10 +79,9 @@ public class AnswerDetailFragment extends NormalFragment { View mNoData; @BindView(R.id.reuse_tv_none_data) TextView mNoDataTv; - MenuItem mMenuCollect; - public static final String TAG = "ask.AnswerDetailFragment"; private static final int ANSWER_PATCH_REQUEST = 100; + public static final String TAG = "ask.AnswerDetailFragment"; private ArrayList mAnswersImgs = new ArrayList<>(); @@ -91,9 +89,48 @@ public class AnswerDetailFragment extends NormalFragment { private String mAnswerId; + private MenuItem mCollectMenuItem; + + private AnswerDetailViewModel mViewModel; + + private FragmentAnswerDetailBinding mBinding; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mViewModel = ViewModelProviders.of(this).get(AnswerDetailViewModel.class); + + initObserver(); + + if (getArguments() != null) { + mAnswerId = getArguments().getString(EntranceUtils.KEY_ANSWER_ID); + mViewModel.getAnswerDetail(mAnswerId, mEntrance); + } + + mRichEditor.setInputEnabled(false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + mRichEditor.addJavascriptInterface(new JsInterface(), "imagelistener"); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + setNavigationTitle(getString(R.string.answer_detail_title)); + } + @Override protected int getLayoutId() { - return R.layout.fragment_answer_detail; + return 0; + } + + @Override + protected View getInflatedLayout() { + mBinding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.fragment_answer_detail, null, false); + return mBinding.getRoot(); } @Override @@ -102,65 +139,73 @@ public class AnswerDetailFragment extends NormalFragment { if (resultCode == Activity.RESULT_OK && requestCode == ANSWER_PATCH_REQUEST && data != null && getActivity() != null) { if (mDetailEntity != null) { mDetailEntity.setContent(data.getStringExtra(EntranceUtils.KEY_ANSWER_CONTENT)); - initView(); + updateView(); } getActivity().setResult(Activity.RESULT_OK, new Intent()); // 编辑答案问题详情页面已存在Id,只需要一个空Intent } } - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - setNavigationTitle(getString(R.string.answer_detail_title)); - initMenu(R.menu.menu_web); - mMenuCollect = getItemMenu(R.id.menu_collect); - } + private void initObserver() { + mViewModel.getAnswerLiveData().observe(this, apiResponse -> { + if (apiResponse == null) return; - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getArguments() != null) { - mAnswerId = getArguments().getString(EntranceUtils.KEY_ANSWER_ID); - initData(); - } - } + if (apiResponse.getData() != null) { + mDetailEntity = apiResponse.getData(); + mBinding.setDetail(mDetailEntity); + updateView(); + } else if (apiResponse.getHttpException() != null) { + HttpException e = apiResponse.getHttpException(); + try { + if (e != null && e.code() == 404 && e.response().errorBody().string().length() > 0) { + mNoDataTv.setText(R.string.content_delete_hint); + mNoData.setVisibility(View.VISIBLE); + mNoConn.setVisibility(View.GONE); + mLoading.setVisibility(View.GONE); + mContent.setVisibility(View.GONE); + Utils.toast(getContext(), R.string.content_delete_toast); + } else { + mNoConn.setVisibility(View.VISIBLE); + mLoading.setVisibility(View.GONE); + mContent.setVisibility(View.GONE); + } + } catch (IOException e1) { + e1.printStackTrace(); + } + } + }); - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - mRichEditor.addJavascriptInterface(new JsInterface(), "imagelistener"); - } + mViewModel.getVoteLiveData().observe(this, apiResponse -> { + if (apiResponse == null) return; - public class JsInterface { - - @JavascriptInterface - public void imageClick(String url) { - if (url.contains("web_load_dfimg_icon.png")) { - mBaseHandler.post(() -> mRichEditor.replaceAllDfImage()); - } else if (url.contains("/tb/")) { - mBaseHandler.post(() -> mRichEditor.replaceDfImageByUrl(url)); - } else { - int current = 0; - for (int i = 0, size = mAnswersImgs.size(); i < size; i++) { - if (url.equals(mAnswersImgs.get(i))) { - current = i; + if (apiResponse.getData() != null) { + MeEntity me = mDetailEntity.getMe(); + me.setAnswerVoted(true); + mDetailEntity.setMe(me); + int vote = mDetailEntity.getVote() + 1; + mDetailEntity.setVote(vote); + updateVote(); + } else if (apiResponse.getHttpException() != null) { + HttpException e = apiResponse.getHttpException(); + if (e == null || e.code() != 403) { + toast(R.string.request_failure_normal_hint); + } else { + try { + JSONObject object = new JSONObject(e.response().errorBody().string()); + int errorCode = object.getInt("code"); + if (errorCode == 403008) { + toast(R.string.ask_vote_hint); + MeEntity me = mDetailEntity.getMe(); + me.setAnswerVoted(true); + updateVote(); + } + } catch (Exception e1) { + e1.printStackTrace(); } } - Intent intent = ViewImageActivity.getViewImageIntent(getContext(), mAnswersImgs, current, - mEntrance + "+(回答详情[" + mTitle.getText().toString() + "])"); - startActivity(intent); } - } - - @JavascriptInterface - public void imageArr(String url) { - String defUrl = url.replace("/tb/", "/"); - if (!mAnswersImgs.contains(defUrl) && !url.contains("web_load_dfimg_icon.png")) { - mAnswersImgs.add(defUrl); - } - } + }); } - @Override public void onMenuItemClick(MenuItem menuItem) { switch (menuItem.getItemId()) { @@ -191,7 +236,7 @@ public class AnswerDetailFragment extends NormalFragment { , CollectionUtils.CollectionType.answer, new CollectionUtils.OnCollectionListener() { @Override public void onSuccess() { - mMenuCollect.setIcon(R.drawable.menu_ic_collect_select); + mCollectMenuItem.setIcon(R.drawable.menu_ic_collect_select); toast(R.string.collection_success); MeEntity me = mDetailEntity.getMe(); me.setAnswerFavorite(true); @@ -208,7 +253,7 @@ public class AnswerDetailFragment extends NormalFragment { , CollectionUtils.CollectionType.answer, new CollectionUtils.OnCollectionListener() { @Override public void onSuccess() { - mMenuCollect.setIcon(R.drawable.menu_ic_collect_unselect); + mCollectMenuItem.setIcon(R.drawable.menu_ic_collect_unselect); MeEntity me = mDetailEntity.getMe(); me.setAnswerFavorite(false); mDetailEntity.setMe(me); @@ -223,26 +268,22 @@ public class AnswerDetailFragment extends NormalFragment { }); } }); + case R.id.menu_report: + SuggestionActivity.startSuggestionActivity(getContext(), 1, null, mDetailEntity.getQuestion().getTitle() + "回答详情举报:" + mDetailEntity.getUser().getName()); + break; + case R.id.menu_edit: + editContent(); break; } } - @OnClick({R.id.answer_detail_edit, R.id.answer_detail_vote, R.id.reuse_no_connection, R.id.answer_detail_title}) + @OnClick({R.id.answer_detail_vote, R.id.reuse_no_connection, R.id.answer_detail_title, R.id.answer_detail_do_comment_container, R.id.answer_detail_comment_count_container}) public void onClick(View view) { switch (view.getId()) { - case R.id.answer_detail_edit: - if (mDetailEntity != null) { - Bundle bundle = new Bundle(); - bundle.putString(EntranceUtils.KEY_ANSWER_ID, mAnswerId); - bundle.putString(EntranceUtils.KEY_QUESTIONS_TITLE, mDetailEntity.getQuestion().getTitle()); - bundle.putString(EntranceUtils.KEY_ANSWER_CONTENT, mDetailEntity.getContent()); - NormalActivity.startFragmentForResult(getContext(), AnswerEditFragment.class, bundle, ANSWER_PATCH_REQUEST); - } - break; case R.id.answer_detail_vote: CheckLoginUtils.checkLogin(getContext(), () -> { if (mDetailEntity != null && !mDetailEntity.getMe().isAnswerVoted()) { - postVote(); + mViewModel.postVote(mAnswerId); } else { toast(R.string.ask_vote_hint); } @@ -251,7 +292,7 @@ public class AnswerDetailFragment extends NormalFragment { case R.id.reuse_no_connection: mNoConn.setVisibility(View.GONE); mLoading.setVisibility(View.VISIBLE); - initData(); + mViewModel.getAnswerDetail(mAnswerId, mEntrance); break; case R.id.answer_detail_title: if (mDetailEntity != null) { @@ -259,81 +300,59 @@ public class AnswerDetailFragment extends NormalFragment { startActivity(intent); } break; + case R.id.answer_detail_do_comment_container: + BaseDialogWrapperFragment dialog = BaseDialogWrapperFragment.getInstance(AnswerCommentDialogFragment.getInstance(true)); + dialog.show(getFragmentManager(),"CommentDialog"); + break; + case R.id.answer_detail_comment_count_container: + BaseDialogWrapperFragment dialogFragment = BaseDialogWrapperFragment.getInstance(AnswerCommentDialogFragment.getInstance(false)); + dialogFragment.show(getFragmentManager(),"CommentDialog"); + // TODO Display count in it's textview. + break; } } - private void initData() { - RetrofitManager.getInstance(getContext()).getApi() - .getAnswerDetail(mAnswerId, Utils.getTime(getContext())) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Response() { - @Override - public void onResponse(AnswerDetailEntity response) { - super.onResponse(response); - mDetailEntity = response; - initView(); - - AskLogUtils.uploadAnswers(getContext(), mEntrance, response.getQuestion(), mAnswerId); - } - - @Override - public void onFailure(HttpException e) { - super.onFailure(e); - - try { - if (e != null && e.code() == 404 && e.response().errorBody().string().length() > 0) { - mNoDataTv.setText(R.string.content_delete_hint); - mNoData.setVisibility(View.VISIBLE); - mNoConn.setVisibility(View.GONE); - mLoading.setVisibility(View.GONE); - mContent.setVisibility(View.GONE); - Utils.toast(getContext(), R.string.content_delete_toast); - } else { - mNoConn.setVisibility(View.VISIBLE); - mLoading.setVisibility(View.GONE); - mContent.setVisibility(View.GONE); - } - } catch (IOException e1) { - e1.printStackTrace(); - } - } - }); + private void editContent() { + if (mDetailEntity != null) { + Bundle bundle = new Bundle(); + bundle.putString(EntranceUtils.KEY_ANSWER_ID, mAnswerId); + bundle.putString(EntranceUtils.KEY_QUESTIONS_TITLE, mDetailEntity.getQuestion().getTitle()); + bundle.putString(EntranceUtils.KEY_ANSWER_CONTENT, mDetailEntity.getContent()); + NormalActivity.startFragmentForResult(getContext(), AnswerEditFragment.class, bundle, ANSWER_PATCH_REQUEST); + } } - private void initView() { + private void updateView() { + if (mDetailEntity.getMe().isAnswerOwn()) { + initMenu(R.menu.menu_answer_author); + } else { + initMenu(R.menu.menu_answer_visitor); + } + + mCollectMenuItem = getItemMenu(R.id.menu_collect); + + if (mDetailEntity.getMe().isAnswerFavorite()) { + mCollectMenuItem.setIcon(R.drawable.menu_ic_collect_select); + } else { + mCollectMenuItem.setIcon(R.drawable.menu_ic_collect_unselect); + } + UserEntity user = mDetailEntity.getUser(); if (user != null) { ImageUtils.Companion.display(mUsericon, user.getIcon()); mUsername.setText(user.getName()); } - if (mDetailEntity.getMe().isAnswerOwn()) { - mEditBtn.setVisibility(View.VISIBLE); - } else { - mEditBtn.setVisibility(View.GONE); - } - - if (mDetailEntity.getMe().isAnswerFavorite()) { - mMenuCollect.setIcon(R.drawable.menu_ic_collect_select); - } else { - mMenuCollect.setIcon(R.drawable.menu_ic_collect_unselect); - } - - mTitle.setText(mDetailEntity.getQuestion().getTitle()); NewsUtils.setNewsDetailTime(mTime, mDetailEntity.getTime()); - mRichEditor.setHtml(mDetailEntity.getContent(), true); - mRichEditor.setInputEnabled(false); - mNoConn.setVisibility(View.GONE); mLoading.setVisibility(View.GONE); mContent.setVisibility(View.VISIBLE); - initVote(); + updateVote(); } - private void initVote() { + private void updateVote() { mVoteCount.setText(getString(R.string.ask_vote_count, AskUtils.voteCountFormat(mDetailEntity.getVote()))); if (getContext() == null) return; @@ -346,44 +365,42 @@ public class AnswerDetailFragment extends NormalFragment { } } - private void postVote() { - RetrofitManager.getInstance(getContext()).getApi() - .postAnswerVote(mAnswerId) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Response() { - @Override - public void onResponse(ResponseBody response) { - super.onResponse(response); - MeEntity me = mDetailEntity.getMe(); - me.setAnswerVoted(true); - mDetailEntity.setMe(me); - int vote = mDetailEntity.getVote() + 1; - mDetailEntity.setVote(vote); - initVote(); - } + @BindingAdapter("setRichContent") + public static void setContent(RichEditor richEditor, String content) { + if (TextUtils.isEmpty(content)) { + richEditor.setVisibility(View.GONE); + } else { + richEditor.setHtml(content, true); + richEditor.setVisibility(View.VISIBLE); + } + } - @Override - public void onFailure(HttpException e) { - super.onFailure(e); - if (e == null || e.code() != 403) { - toast(R.string.request_failure_normal_hint); - } else { - try { - JSONObject object = new JSONObject(e.response().errorBody().string()); - int errorCode = object.getInt("code"); - if (errorCode == 403008) { - toast(R.string.ask_vote_hint); - MeEntity me = mDetailEntity.getMe(); - me.setAnswerVoted(true); - initVote(); - } - } catch (Exception e1) { - e1.printStackTrace(); - } - } -// AskErrorResponseUtils.errorResponseControl(getContext(), e); + public class JsInterface { + @JavascriptInterface + public void imageClick(String url) { + if (url.contains("web_load_dfimg_icon.png")) { + mBaseHandler.post(() -> mRichEditor.replaceAllDfImage()); + } else if (url.contains("/tb/")) { + mBaseHandler.post(() -> mRichEditor.replaceDfImageByUrl(url)); + } else { + int current = 0; + for (int i = 0, size = mAnswersImgs.size(); i < size; i++) { + if (url.equals(mAnswersImgs.get(i))) { + current = i; } - }); + } + Intent intent = ViewImageActivity.getViewImageIntent(getContext(), mAnswersImgs, current, + mEntrance + "+(回答详情[" + mTitle.getText().toString() + "])"); + startActivity(intent); + } + } + + @JavascriptInterface + public void imageArr(String url) { + String defUrl = url.replace("/tb/", "/"); + if (!mAnswersImgs.contains(defUrl) && !url.contains("web_load_dfimg_icon.png")) { + mAnswersImgs.add(defUrl); + } + } } } diff --git a/app/src/main/java/com/gh/gamecenter/ask/viewmodel/AnswerCommentViewModel.java b/app/src/main/java/com/gh/gamecenter/ask/viewmodel/AnswerCommentViewModel.java new file mode 100644 index 0000000000..b450d28e92 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/ask/viewmodel/AnswerCommentViewModel.java @@ -0,0 +1,71 @@ +package com.gh.gamecenter.ask.viewmodel; + +import android.app.Application; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.MutableLiveData; +import android.support.annotation.NonNull; + +import com.gh.common.util.PostCommentUtils; +import com.gh.gamecenter.baselist.ListViewModel; +import com.gh.gamecenter.entity.CommentEntity; +import com.gh.gamecenter.login.ApiResponse; +import com.gh.gamecenter.retrofit.RetrofitManager; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.List; + +import retrofit2.HttpException; +import rx.Observable; + +public class AnswerCommentViewModel extends ListViewModel { + + private MutableLiveData> mPostCommentLiveData = new MutableLiveData<>(); + + public AnswerCommentViewModel(@NonNull Application application) { + super(application); + mResultLiveData.addSource(mListLiveData, mResultLiveData::postValue); + } + + @Override + public Observable> provideDataObservable(int offset) { + return RetrofitManager.getInstance(getApplication()).getApi().getComment("59c0b965e9a64abe2a423544", 0, offset); + } + + public void postComment(String content, CommentEntity commentEntity) { + + JSONObject jsonObject = new JSONObject(); + try { + jsonObject.put("content", content); + } catch (JSONException e) { + e.printStackTrace(); + } + + PostCommentUtils.addCommentData(getApplication(), null, jsonObject.toString(), commentEntity, + new PostCommentUtils.PostCommentListener() { + @Override + public void postSuccess(JSONObject response) { + ApiResponse apiResponse = new ApiResponse<>(); + apiResponse.setData(response); + mPostCommentLiveData.postValue(apiResponse); + } + + @Override + public void postFailed(Throwable e) { + + ApiResponse apiResponse = new ApiResponse<>(); + if (e instanceof HttpException) { + apiResponse.setHttpException((HttpException) e); + mPostCommentLiveData.postValue(apiResponse); + } else { + mPostCommentLiveData.postValue(apiResponse); + } + } + }); + } + + public LiveData> getPostCommentLiveData() { + return mPostCommentLiveData; + } +} diff --git a/app/src/main/java/com/gh/gamecenter/ask/viewmodel/AnswerDetailViewModel.java b/app/src/main/java/com/gh/gamecenter/ask/viewmodel/AnswerDetailViewModel.java new file mode 100644 index 0000000000..eb0b29b760 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/ask/viewmodel/AnswerDetailViewModel.java @@ -0,0 +1,83 @@ +package com.gh.gamecenter.ask.viewmodel; + +import android.app.Application; +import android.arch.lifecycle.AndroidViewModel; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.MutableLiveData; +import android.support.annotation.NonNull; + +import com.gh.common.util.AskLogUtils; +import com.gh.gamecenter.ask.entity.AnswerDetailEntity; +import com.gh.gamecenter.login.ApiResponse; +import com.gh.gamecenter.retrofit.Response; +import com.gh.gamecenter.retrofit.RetrofitManager; +import com.lightgame.utils.Utils; + +import okhttp3.ResponseBody; +import retrofit2.HttpException; +import rx.schedulers.Schedulers; + +public class AnswerDetailViewModel extends AndroidViewModel { + + private MutableLiveData> mAnswerLiveData = new MutableLiveData<>(); + private MutableLiveData> mVoteLiveData = new MutableLiveData<>(); + + public AnswerDetailViewModel(@NonNull Application application) { + super(application); + } + + public void getAnswerDetail(String answerId, String entrance) { + RetrofitManager.getInstance(getApplication()).getApi() + .getAnswerDetail(answerId, Utils.getTime(getApplication())) + .subscribeOn(Schedulers.io()) + .subscribe(new Response() { + @Override + public void onResponse(AnswerDetailEntity response) { + ApiResponse apiResponse = new ApiResponse<>(); + apiResponse.setData(response); + mAnswerLiveData.postValue(apiResponse); + + AskLogUtils.uploadAnswers(getApplication(), entrance, response.getQuestion(), answerId); + } + + @Override + public void onFailure(HttpException e) { + ApiResponse apiResponse = new ApiResponse<>(); + apiResponse.setHttpException(e); + mAnswerLiveData.postValue(apiResponse); + } + }); + } + + public void postVote(String answerId) { + RetrofitManager.getInstance(getApplication()).getApi() + .postAnswerVote(answerId) + .subscribeOn(Schedulers.io()) + .subscribe(new Response() { + @Override + public void onResponse(ResponseBody response) { + ApiResponse apiResponse = new ApiResponse<>(); + apiResponse.setData(response); + mVoteLiveData.postValue(apiResponse); + } + + @Override + public void onFailure(HttpException e) { + + ApiResponse apiResponse = new ApiResponse<>(); + apiResponse.setHttpException(e); + mVoteLiveData.postValue(apiResponse); + +// AskErrorResponseUtils.errorResponseControl(getApplication(), e); + } + }); + } + + public LiveData> getAnswerLiveData() { + return mAnswerLiveData; + } + + public LiveData> getVoteLiveData() { + return mVoteLiveData; + } +} diff --git a/app/src/main/res/drawable-xhdpi/ic_answer_comment_close.png b/app/src/main/res/drawable-xhdpi/ic_answer_comment_close.png new file mode 100644 index 0000000000000000000000000000000000000000..95fe968e51c6695865da3f5219794e192fbd38a9 GIT binary patch literal 348 zcmV-i0i*tjP)%vgMlp}z$AWmT)&X?$bRAqpTxl>RX%E%oU`XX75{cPiGP3`}S zlQ=L8{^!pdr<9fExt} zktI0E`KmbRD~OS0B`t4Q70`9m0P#I<+KeS2weiLfkzM>RAh)YmZ3^9kHDoA50Hz@ uSs|u3UP26T=#4AL!N`wOZ#;pVfcX#l|E2M}46H8z0000hUa^AF2CRN_-@aq=klJkZp=gfmILx5A3&@Dx*6(JabZE3Ei1 z3U*-?Cpy8358x&C;`2ny`y)>$SW{iDx2@t>E3D0VrKxWPN0W?CwT|PtrlU)kO|mvN z)w%!=H8Whmsf`)Z{EJ&brJ(N0Yh zX7CGVlRO!PU~+nTdXJ{vhwu$avN#TH-1r9jv4*)M@7fT}IDX?Jj&w!v2fizcGz+LL Qg#Z8m07*qoM6N<$g5N;N)c^nh literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_answer_detail_check_comment.png b/app/src/main/res/drawable-xhdpi/ic_answer_detail_check_comment.png new file mode 100644 index 0000000000000000000000000000000000000000..c67102123552002cf707daae3ac3fe3b48faccd4 GIT binary patch literal 1309 zcmeAS@N?(olHy`uVBq!ia0vp^G9b*s1|*Ak?@s|zk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m^Cs(B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuk*h0bFQqR!T z(!$6@N5ROz&`jUJQs2--*TB%qz|zXVPyq^*fVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr7I$DAddqG<*}2 zGxI=#nqXbNzE+-j#U+V($*G<$wn{*A^fEJ3tSk+T%*>44T#QUy3=IukEga2^%$ytz z4J=G7j2(^4-C%lM@{>z*Q}aq-dQ%X3U2*CKC5YStpv^9+MVV!(DQ-pixe8#9TV>*Q zixW=spn6kqyTuu&UVWfr^g+>!6x}c(U>X83;fWW>fhYgeJYbqH0w(TVoJJZ942<2L zE{-7;x86*%^f=-m;xJjjC1>ll4@?^a_i%A@Zv=wNOT~>h9^vJ0ARpHX9^7S@uwP-GZGnZu&S*7J0L3Vst}P;=L1V9YjqW7D+r@ zTvnU?Pls#Kno{yVT}qI6s2j%kKm!k3;IS;kGb``kI< zj%82Ss|`wjwjavT-tu!<<@8yzntQ^eJQv^HTJ%acFpT;1smER)*Bx9|7#uWt<*i$j z*iUy#T5~X&Cd{vSa^sS_bmYRb|5xef9Z;$9{$8QwD00A1Cav|@YU>AA^mB8?s~)hq z%{US$DIZu_y|OEKMRV=dbrbfw?Dd|S!`b%FYg&HmdV{tM{XQ$3#&a4eT6L@v49^17 U7K$)6#DWSePgg&ebxsLQ0Kgs4p8x;= literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_answer_detail_edit_empty.png b/app/src/main/res/drawable-xhdpi/ic_answer_detail_edit_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..ee5564f62511dd94540f91e816070bc1b6fb7bce GIT binary patch literal 429 zcmV;e0aE^nP)Pco<|h@ednVXI6qSqv)%-wCn?1(QJyCWDqOCc$<*Q#0?zPPJF_h%zQdbbn3cZ z#KZFZ1wR@h+pxc^7cz4h=5QP9ID^-dR?W;!xrkW6^HO^mDjdS+X^_9*FEGI2VXi9k zx3-Xx_^oC&ZdcnegJ#eSnn9amuHpF;5pf**@Fp`qjN91cMyK!|&u|~B5ivjVeo#hZ z=vbLo@c_HgkBDx`pT@~Hpo3-pn3-2_3p>$^h;C+n&CInnpgz9iYDC=3%zFjfF~mkU zH-X;bY{BmS3v2p&_qU1-pOW2aXd zWg^0utSl^8O^KQidKT}#dLHw8Z{8c?)al-P&bjB?z4zQYeMM2g7*1n{<&jr79}(9Z zhQ6XG#&9{W-{M=3kd@e!=OYm@3H>;S8usJfQnN6cM zY-`vmd0bd7NR#}Ov$9y!a?3vfdZ}I{rJ7QzrIa4D1NE2qp6R^QXL|vSc0%}FdH+uS z+8dRfsDgFv5~P&iLqycN1+(tn5T{c;BM$uqONWsDJ7kxQOYL(qPm6`K)b0GkD&j5Aiwscjj># zm(;&PHKjC^?fbC1k*w_Mj+FRdOCDz<;zUa64aPB*QW}nkYIATe#Zbj398W2oiHHk0 zi`5x6)EwLk=rM*fY`h(;*Yd7*3TuE`%eZ67Z_yT3QEyDP$)O=Q^ZzM?2baV77W zx3os3hLaI71^Jq$a`Fir!e>S8)(e)tkQ!OVIUL)pD{Se8i~?xrU>Cxh3ve7HJ>{ gaR+yCEF!-D0KIpw#%x2MzyJUM07*qoM6N<$f~6P!?EnA( literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_answer_detail_write_comment.png b/app/src/main/res/drawable-xhdpi/ic_answer_detail_write_comment.png new file mode 100644 index 0000000000000000000000000000000000000000..d12b65d7410772a82aa3d73fd534ae07e1c7c521 GIT binary patch literal 1260 zcmaJ>eP|nX7`}ebblFOyr4GfP7t~C8xsRr4?&vjlNgA7NsU?e;42Qd1er=BSK6ZC) z($Yb*QH@q1t3^aXgBz&BjUlTDiZUrqZU2ype^kLKDxwHenRDo%-gQmqAI5{b-v{sW zywCf-5BJpY&_hng9tVOT&e&iiVXb%B?~Z2ct2-|*TFag0K*~I*j+l8thX|ilGZ4gN zVH75ykexdE3G73V29K0XnW^{zMpR|5V8?h1vSy(Xq%T;|1aSzc6DQ(Y80MtGX&oM%9!iSSVMPS>BE|%mlop_dkh^S z1T@qMU9<)_;CAA&ECTD zHLlF6{a=5}t z<$KfD?k>5D*LSo9n=-+2pR4D)mR#Do0Qf?~!<^C$9WA2sEzApEAsB+P{ zn2IjUaVO?xZ}*5B;1X3ibbsPlZrAcE_ug|mSFX)EW)l1N7#{34-;vhxq}$(FUn!<`rH;>3PO>xHjk@&@$HB|Ua>)1AuUOlUCpw?Gs{Gv0*oicqKYQsa S|EX&Ke_{hek#nIV$NvFS)uE06 literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/fragment_answer_comment.xml b/app/src/main/res/layout/fragment_answer_comment.xml new file mode 100644 index 0000000000..c47b0285e2 --- /dev/null +++ b/app/src/main/res/layout/fragment_answer_comment.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + +