diff --git a/app/build.gradle b/app/build.gradle index e05b4bc961..5ae32f8f7b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -144,6 +144,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..730515d4d6 --- /dev/null +++ b/app/src/main/java/com/gh/base/fragment/BaseDialogWrapperFragment.java @@ -0,0 +1,55 @@ +package com.gh.base.fragment; + +import android.app.Dialog; +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); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.setCanceledOnTouchOutside(true); + return dialog; + } +} 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/util/CommentUtils.java b/app/src/main/java/com/gh/common/util/CommentUtils.java index 5913ca78a7..d077dc59c6 100644 --- a/app/src/main/java/com/gh/common/util/CommentUtils.java +++ b/app/src/main/java/com/gh/common/util/CommentUtils.java @@ -151,6 +151,75 @@ public class CommentUtils { } + public static void showAnswerCommentOptions(final CommentEntity commentEntity, final Context context, + final OnCommentCallBackListener listener, final String id, boolean showConversation) { + + final Dialog dialog = new Dialog(context); + + LinearLayout container = new LinearLayout(context); + container.setOrientation(LinearLayout.VERTICAL); + container.setBackgroundColor(Color.WHITE); + container.setPadding(0, DisplayUtils.dip2px(context, 12), 0, DisplayUtils.dip2px(context, 12)); + + List dialogType = new ArrayList<>(); + + if (commentEntity.getUserData() == null || !commentEntity.getUserData().isCommentOwn()) { + dialogType.add("回复"); + } + + dialogType.add("复制"); + dialogType.add("举报"); + + if (commentEntity.getParent() != null && showConversation) { + dialogType.add("查看对话"); + } + + for (String s : dialogType) { + final TextView reportTv = new TextView(context); + reportTv.setText(s); + reportTv.setTextSize(17); + reportTv.setTextColor(ContextCompat.getColor(context, R.color.title)); + reportTv.setBackgroundResource(R.drawable.textview_white_style); + int widthPixels = context.getResources().getDisplayMetrics().widthPixels; + reportTv.setLayoutParams(new LinearLayout.LayoutParams((widthPixels * 9) / 10, + LinearLayout.LayoutParams.WRAP_CONTENT)); + reportTv.setPadding(DisplayUtils.dip2px(context, 20), DisplayUtils.dip2px(context, 12), + 0, DisplayUtils.dip2px(context, 12)); + container.addView(reportTv); + + reportTv.setOnClickListener(v -> { + dialog.cancel(); + switch (reportTv.getText().toString()) { + case "回复": + CheckLoginUtils.checkLogin(context, () -> { + if (listener != null) { + listener.onCommentCallback(commentEntity); + } else if (!TextUtils.isEmpty(id)) { + context.startActivity(MessageDetailActivity.getMessageDetailIntent(context, commentEntity, id)); + } else { + Utils.toast(context, "缺少关键属性"); + } + }); + break; + case "复制": + LibaoUtils.copyLink(commentEntity.getContent(), context); + break; + case "举报": + CheckLoginUtils.checkLogin(context, () -> showReportTypeDialog(commentEntity, context)); + + break; + case "查看对话": + context.startActivity(CommentDetailActivity.getAnswerCommentIntent(context, commentEntity.getId())); + break; + } + }); + } + + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + dialog.setContentView(container); + dialog.show(); + } + private static void showReportTypeDialog(final CommentEntity commentEntity, final Context context) { final String[] arrReportType = new String[]{"垃圾广告营销", "恶意攻击谩骂", "淫秽色情信息", "违法有害信息", "其它"}; @@ -265,6 +334,61 @@ public class CommentUtils { }); } + public static void postVoteToAnswerComment(final Context context, String answerId, final CommentEntity commentEntity, + final TextView commentLikeCountTv, final ImageView commentLikeIv, final OnVoteListener listener) { + CheckLoginUtils.checkLogin(context, () -> { + if (commentLikeCountTv.getCurrentTextColor() == ContextCompat.getColor(context, R.color.theme)) { + Utils.toast(context, "已经点过赞啦!"); + return; + } + commentEntity.setVote(commentEntity.getVote() + 1); + commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.theme)); + commentLikeIv.setImageResource(R.drawable.ic_like_select); + commentLikeCountTv.setText(String.valueOf(commentEntity.getVote())); + commentLikeCountTv.setVisibility(View.VISIBLE); + + PostCommentUtils.voteAnswerComment(context, answerId, commentEntity.getId(), + new PostCommentUtils.PostCommentListener() { + @Override + public void postSuccess(JSONObject response) { + if (listener != null) { + listener.onVote(); + } + } + + @Override + public void postFailed(Throwable e) { + + commentEntity.setVote(commentEntity.getVote() - 1); + commentLikeCountTv.setTextColor(ContextCompat.getColor(context, R.color.hint)); + commentLikeIv.setImageResource(R.drawable.ic_like_unselect); + commentLikeCountTv.setText(String.valueOf(commentEntity.getVote())); + if (commentEntity.getVote() == 0) { + commentLikeCountTv.setVisibility(View.GONE); + } else { + commentLikeCountTv.setVisibility(View.VISIBLE); + } + + if (e instanceof HttpException) { + HttpException exception = (HttpException) e; + if (exception.code() == 403) { + try { + String detail = new JSONObject(exception.response().errorBody().string()).getString("detail"); + if ("voted".equals(detail)) { + Utils.toast(context, "已经点过赞啦!"); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + return; + } + } + Utils.toast(context, "网络异常,点赞失败"); + } + }); + }); + } + // 设置评论item 用户相关的view(点赞/头像/用户名) public static void setCommentUserView(Context mContext, CommentViewHolder holder, CommentEntity entity) { diff --git a/app/src/main/java/com/gh/common/util/NewsUtils.java b/app/src/main/java/com/gh/common/util/NewsUtils.java index 0ca5d84176..dee8b25bf1 100644 --- a/app/src/main/java/com/gh/common/util/NewsUtils.java +++ b/app/src/main/java/com/gh/common/util/NewsUtils.java @@ -170,4 +170,35 @@ public class NewsUtils { } } + public static String getFormattedTime(long time) { + SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault()); + try { + long today = format.parse(format.format(new Date())).getTime(); + long day = time * 1000; + if (day >= today && day < today + 86400 * 1000) { + long min = new Date().getTime() / 1000 - day / 1000; + int hour = (int) (min / (60 * 60)); + if (hour == 0) { + if (min < 60) { + return "刚刚"; + } else { + return (String.format(Locale.getDefault(), "%d分钟前", (int) (min / 60))); + } + } else { + return (String.format(Locale.getDefault(), "%d小时前", hour)); + } + } else if (day >= today - 86400 * 1000 && day < today) { + format.applyPattern("HH:mm"); + return ("昨天 "); + } else { + format.applyPattern("yyyy-MM-dd"); + return (format.format(day)); + } + } catch (ParseException e) { + e.printStackTrace(); + format.applyPattern("yyyy-MM-dd"); + return (format.format(time * 1000)); + } + } + } diff --git a/app/src/main/java/com/gh/common/util/PostCommentUtils.java b/app/src/main/java/com/gh/common/util/PostCommentUtils.java index 98cd2b910a..f373c70ccd 100644 --- a/app/src/main/java/com/gh/common/util/PostCommentUtils.java +++ b/app/src/main/java/com/gh/common/util/PostCommentUtils.java @@ -57,6 +57,62 @@ public class PostCommentUtils { }); } + public static void addAnswerComment(final Context context, final String answerId, final String content, + final CommentEntity commentEntity, + final PostCommentListener listener) { + RequestBody body = RequestBody.create(MediaType.parse("application/json"), content); + Observable observable; + if (commentEntity != null) { + observable = RetrofitManager.getInstance(context).getApi().postReplyToAnswerComment(answerId, commentEntity.getId(), body); + } else { + observable = RetrofitManager.getInstance(context).getApi().postNewCommentToAnswer(answerId, body); + } + observable.subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new JSONObjectResponse() { + @Override + public void onResponse(JSONObject response) { + if (response.length() != 0) { + if (listener != null) { + listener.postSuccess(response); + } + } else { + Utils.toast(context, R.string.post_failure_hint); + } + } + + @Override + public void onFailure(HttpException e) { + if (listener != null) { + listener.postFailed(e); + } + } + }); + } + + public static void voteAnswerComment(final Context context,final String answerId, final String commentId, + final PostCommentListener listener) { + RetrofitManager.getInstance(context).getApi() + .postVoteAnswerComment(answerId,commentId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Response() { + @Override + public void onResponse(ResponseBody response) { + if (listener != null) { + listener.postSuccess(null); + } + } + + @Override + public void onFailure(HttpException e) { + if (listener != null) { + listener.postFailed(e); + } + } + }); + } + public static void addCommentVoto(final Context context, final String commentId, final PostCommentListener listener) { RetrofitManager.getInstance(context).getApi() 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/CommentDetailActivity.java b/app/src/main/java/com/gh/gamecenter/CommentDetailActivity.java index 396a0e5cd3..4712021d23 100644 --- a/app/src/main/java/com/gh/gamecenter/CommentDetailActivity.java +++ b/app/src/main/java/com/gh/gamecenter/CommentDetailActivity.java @@ -5,6 +5,7 @@ import android.content.Intent; import android.os.Bundle; import com.gh.common.util.EntranceUtils; +import com.gh.gamecenter.ask.viewmodel.AnswerCommentConversationFragment; import com.halo.assistant.fragment.comment.CommentDetailFragment; /** @@ -22,4 +23,13 @@ public class CommentDetailActivity extends NormalActivity { return getIntent(context, CommentDetailFragment.class, args); } + public static Intent getAnswerCommentIntent(Context context, String commentId) { + Bundle args = new Bundle(); + args.putString(EntranceUtils.KEY_COMMENTID, commentId); +// return new IntentFactory.Builder(context) +// .setActivity(CommentDetailActivity.class) +// .setFragment(CommentDetailFragment.class).setArgs(args).build(); + return getIntent(context, AnswerCommentConversationFragment.class, args); + } + } diff --git a/app/src/main/java/com/gh/gamecenter/NormalActivity.java b/app/src/main/java/com/gh/gamecenter/NormalActivity.java index 639e11f2b1..9e3843e35e 100644 --- a/app/src/main/java/com/gh/gamecenter/NormalActivity.java +++ b/app/src/main/java/com/gh/gamecenter/NormalActivity.java @@ -169,7 +169,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/adapter/viewholder/AnswerCommentViewHolder.java b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/AnswerCommentViewHolder.java new file mode 100644 index 0000000000..1b36d897c5 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/AnswerCommentViewHolder.java @@ -0,0 +1,22 @@ +package com.gh.gamecenter.adapter.viewholder; + +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.gh.gamecenter.R; + +import butterknife.BindView; + +public class AnswerCommentViewHolder extends CommentViewHolder { + @BindView(R.id.comment_quote_container) + public ViewGroup quoteContainer; + @BindView(R.id.comment_quote_author_tv) + public TextView quoteAuthorTv; + @BindView(R.id.comment_quote_content_tv) + public TextView quoteContentTv; + + public AnswerCommentViewHolder(View itemView) { + super(itemView); + } +} 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..5017e0c07e --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/ask/AnswerCommentAdapter.java @@ -0,0 +1,104 @@ +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.AnswerCommentViewHolder; +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 String mAnswerId; + private boolean mIsShowingConversation; + private OnCommentCallBackListener mOnCommentCallBackListener; + + public AnswerCommentAdapter(Context context, String answerId, boolean isShowingConversation, OnCommentCallBackListener commentCallBackListener) { + super(context); + mAnswerId = answerId; + mIsShowingConversation = isShowingConversation; + 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.answer_comment_item, parent, false); + return new AnswerCommentViewHolder(view); + } + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + if (holder instanceof AnswerCommentViewHolder) { + initCommentViewHolder((AnswerCommentViewHolder) 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 AnswerCommentViewHolder 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()); + + holder.commentContentTv.setText(commentEntity.getContent()); + + if (commentEntity.getParent() != null && commentEntity.getParent().getUser() != null) { + holder.quoteContainer.setVisibility(View.VISIBLE); + holder.quoteAuthorTv.setText(commentEntity.getParent().getUser().getName()); + holder.quoteContentTv.setText("孙一峰,星際爭霸與星際爭霸2的職業選手,電競戰隊Xteam的經理,美少女团体星際老男孩成員之一,還在杭州經營水產生意。"); + } else { + holder.quoteContainer.setVisibility(View.GONE); + } + + holder.commentLikeIv.setOnClickListener(v -> CommentUtils.postVoteToAnswerComment(mContext, mAnswerId, commentEntity, holder.commentLikeCountTv, holder.commentLikeIv, null)); + + holder.itemView.setOnClickListener(v -> CommentUtils.showAnswerCommentOptions(commentEntity, mContext, mOnCommentCallBackListener, null, !mIsShowingConversation)); + } + + 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/AnswerCommentFragment.java b/app/src/main/java/com/gh/gamecenter/ask/AnswerCommentFragment.java new file mode 100644 index 0000000000..ac9e6099c5 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/ask/AnswerCommentFragment.java @@ -0,0 +1,248 @@ +package com.gh.gamecenter.ask; + +import android.app.Application; +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 butterknife.Optional; +import retrofit2.HttpException; + +public class AnswerCommentFragment extends ListFragment implements OnCommentCallBackListener { + + @BindView(R.id.answer_comment_et) + protected EditText mCommentDetailCommentEt; + @BindView(R.id.answer_comment_send_btn) + protected TextView mCommentSend; + + protected Dialog mSendingDialog; + + protected String mAnswerId; + + protected CommentEntity mCommentEntity; // 回复评论的实体 用完马上清空 + + protected AnswerCommentAdapter mAdapter; + + protected boolean mShowSoftKeyboardOnStartUp; + + @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()); + int errorCode = errorJson.getInt("code"); + switch (errorCode) { + case 403018: + toast("内容可能已被删除"); + setSoftInput(false); + break; + case 403019: + toast("你已被禁言"); + break; + case 403020: + toast(R.string.comment_failed_toofrequent); + break; + case 403201: + toast(R.string.comment_failed_illegal); + break; + default: + toast(R.string.comment_failed_unknown); + break; + } + } catch (Exception ex) { + ex.printStackTrace(); + toast("评论异常"); + } + } else if (exception.code() == 404){ + toast(R.string.post_failure_hint); + } + } else { + toast(R.string.post_failure_hint); + } + }); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + if (mShowSoftKeyboardOnStartUp) { + 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, new AnswerCommentViewModel.Factory((Application) getContext().getApplicationContext(), mAnswerId, null)).get(AnswerCommentViewModel.class); + } + + @Override + protected ListAdapter provideListAdapter() { + return mAdapter == null ? mAdapter = new AnswerCommentAdapter(getContext(), mAnswerId, false, this) : mAdapter; + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_answer_comment; + } + + public static AnswerCommentFragment getInstance(String answerId, boolean showSoftKeyboardOnStartUp) { + AnswerCommentFragment fragment = new AnswerCommentFragment(); + fragment.mShowSoftKeyboardOnStartUp = showSoftKeyboardOnStartUp; + fragment.mAnswerId = answerId; + 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); + } + + @Optional + @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, mAnswerId, mCommentEntity); + } + + //软键盘控制 + protected 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 41feeda103..8693ca19a5 100644 --- a/app/src/main/java/com/gh/gamecenter/ask/AnswerDetailFragment.java +++ b/app/src/main/java/com/gh/gamecenter/ask/AnswerDetailFragment.java @@ -1,23 +1,35 @@ package com.gh.gamecenter.ask; +import android.annotation.SuppressLint; import android.app.Activity; +import android.app.Dialog; +import android.arch.lifecycle.Lifecycle; +import android.arch.lifecycle.ViewModelProviders; import android.content.Intent; +import android.databinding.BindingAdapter; +import android.databinding.DataBindingUtil; +import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.text.TextUtils; +import android.view.Gravity; +import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; +import android.view.Window; +import android.view.WindowManager; import android.webkit.JavascriptInterface; 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; +import com.gh.common.util.DisplayUtils; import com.gh.common.util.EntranceUtils; import com.gh.common.util.ImageUtils; import com.gh.common.util.NewsUtils; @@ -25,15 +37,16 @@ import com.gh.common.util.ShareUtils; import com.gh.common.view.RichEditor; import com.gh.gamecenter.NormalActivity; 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.questionsdetail.QuestionsDetailFragment; +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 +56,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 +70,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 +88,22 @@ public class AnswerDetailFragment extends NormalFragment { View mNoData; @BindView(R.id.reuse_tv_none_data) TextView mNoDataTv; - MenuItem mMenuCollect; + @BindView(R.id.answer_detail_title_status_tv) + TextView mAnswerStatusTv; + @BindView(R.id.answer_detail_title_answer_count_tv) + TextView mAnswerCountTv; + @BindView(R.id.answer_detail_title_status_iv) + ImageView mAnswerStatusIv; + @BindView(R.id.answer_detail_comment_count_tv) + TextView mAnswerCommentCountTv; + + private static final int ANSWER_STATUS_UNKNOWN = 0; + private static final int ANSWERED_MY_ANSWER = 1; + private static final int ANSWERED_NOT_MY_ANSWER = 2; + private static final int NOT_ANSWERED_YET = 3; - 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 +111,51 @@ public class AnswerDetailFragment extends NormalFragment { private String mAnswerId; + private MenuItem mCollectMenuItem; + + private AnswerDetailViewModel mViewModel; + + private FragmentAnswerDetailBinding mBinding; + + private int mAnswerStatus = ANSWER_STATUS_UNKNOWN; + + @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); + } + + initMenu(R.menu.menu_answer); + 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,36 +164,327 @@ 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; + + 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(); + } + } + }); + + mViewModel.getVoteLiveData().observe(this, apiResponse -> { + if (apiResponse == null) return; + + 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(); + } + } + } + }); } @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getArguments() != null) { - mAnswerId = getArguments().getString(EntranceUtils.KEY_ANSWER_ID); - initData(); + public void onMenuItemClick(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case R.id.menu_more: + showMoreItemDialog(); + break; + case R.id.menu_collect: + if (mDetailEntity == null) return; + CheckLoginUtils.checkLogin(getContext(), () -> { + if (!mDetailEntity.getMe().isAnswerFavorite()) { + CollectionUtils.INSTANCE.postCollection(getContext(), mAnswerId + , CollectionUtils.CollectionType.answer, new CollectionUtils.OnCollectionListener() { + @Override + public void onSuccess() { + mCollectMenuItem.setIcon(R.drawable.menu_ic_question_concern_select); + toast(R.string.collection_success); + MeEntity me = mDetailEntity.getMe(); + me.setAnswerFavorite(true); + mDetailEntity.setMe(me); + } + + @Override + public void onError() { + toast(R.string.collection_failure); + } + }); + } else { + CollectionUtils.INSTANCE.deleteCollection(getContext(), mAnswerId + , CollectionUtils.CollectionType.answer, new CollectionUtils.OnCollectionListener() { + @Override + public void onSuccess() { + mCollectMenuItem.setIcon(R.drawable.menu_ic_question_concern_unselect); + MeEntity me = mDetailEntity.getMe(); + me.setAnswerFavorite(false); + mDetailEntity.setMe(me); + toast(R.string.collection_cancel); + + } + + @Override + public void onError() { + toast(R.string.collection_cancel_failure); + } + }); + } + }); } } - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - mRichEditor.addJavascriptInterface(new JsInterface(), "imagelistener"); + private void showMoreItemDialog() { + if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED) || mDetailEntity != null) { + View view = LayoutInflater.from(getContext()).inflate(R.layout.menu_answer_detail_more, null); + Dialog dialog = new Dialog(getActivity()); + dialog.setContentView(view); + Window window = dialog.getWindow(); + if (window != null) { + window.setGravity(Gravity.RIGHT | Gravity.TOP); + window.setBackgroundDrawable(new ColorDrawable(0)); + window.setDimAmount(0.2f); + WindowManager.LayoutParams lp = window.getAttributes(); + lp.x = DisplayUtils.dip2px(getContext(), 17); + lp.y = DisplayUtils.dip2px(getContext(), 45); // 减去卡片高度 + window.setAttributes(lp); + } + dialog.show(); + ImageView icon = view.findViewById(R.id.more_item_icon1); + TextView title = view.findViewById(R.id.more_item_title1); + if (mDetailEntity.getMe().isAnswerOwn()) { + icon.setImageResource(R.drawable.menu_more_edit); + title.setText("编辑"); + } + View item1 = view.findViewById(R.id.more_item1); + View item2 = view.findViewById(R.id.more_item2); + item1.setOnClickListener(v -> { + dialog.dismiss(); + if ("编辑".equals(title.getText().toString())) { + // 跳转编辑问题页面 + editContent(); + } else { + // 跳转意见反馈 + SuggestionActivity.startSuggestionActivity(getContext(), 1, "report", "问题举报:"); + } + }); + item2.setOnClickListener(v -> { + dialog.dismiss(); + if (mDetailEntity == null) return; + String shareIcon; + String shareSummary = mRichEditor.getText(); + if (mAnswersImgs.size() > 0) { + shareIcon = mAnswersImgs.get(0); + } else { + shareIcon = getString(R.string.share_ghzs_logo); + } + if (TextUtils.isEmpty(shareSummary)) { + shareSummary = getString(R.string.ask_share_default_summary); + } + + ShareUtils.getInstance(getContext()).showShareWindows(getActivity(), getView() + , getString(R.string.share_answers_url, mDetailEntity.getQuestion().getId(), mAnswerId) + , shareIcon + , getString(R.string.ask_share_answers_title, mDetailEntity.getUser().getName(), mDetailEntity.getQuestion().getTitle(), mDetailEntity.getVote()) + , shareSummary, ShareUtils.ShareType.askNormal); + }); + } + } + + @OnClick({R.id.answer_detail_vote, + R.id.reuse_no_connection, + R.id.answer_detail_title, + R.id.answer_detail_title_status_tv, + R.id.answer_detail_title_answer_count_tv, + 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_vote: + CheckLoginUtils.checkLogin(getContext(), () -> { + if (mDetailEntity != null && !mDetailEntity.getMe().isAnswerVoted()) { + mViewModel.postVote(mAnswerId); + } else { + toast(R.string.ask_vote_hint); + } + }); + break; + case R.id.reuse_no_connection: + mNoConn.setVisibility(View.GONE); + mLoading.setVisibility(View.VISIBLE); + mViewModel.getAnswerDetail(mAnswerId, mEntrance); + break; + case R.id.answer_detail_title: + if (mDetailEntity != null) { + Bundle bundle = new Bundle(); + bundle.putString(EntranceUtils.KEY_QUESTIONS_ID, mDetailEntity.getQuestion().getId()); + bundle.putString(EntranceUtils.KEY_ENTRANCE, mEntrance); + NormalActivity.startFragment(getContext(), QuestionsDetailFragment.class, bundle); + } + break; + case R.id.answer_detail_do_comment_container: + BaseDialogWrapperFragment dialog = BaseDialogWrapperFragment.getInstance(AnswerCommentFragment.getInstance(mAnswerId, true)); + dialog.show(getFragmentManager(), "CommentDialog"); + break; + case R.id.answer_detail_comment_count_container: + BaseDialogWrapperFragment dialogFragment = BaseDialogWrapperFragment.getInstance(AnswerCommentFragment.getInstance(mAnswerId, false)); + dialogFragment.show(getFragmentManager(), "CommentDialog"); + break; + case R.id.answer_detail_title_status_tv: + switch (mAnswerStatus) { + case ANSWER_STATUS_UNKNOWN: + break; + case ANSWERED_MY_ANSWER: + toast("当前已是你的回答"); + break; + case ANSWERED_NOT_MY_ANSWER: + Bundle answerDetailBundle = new Bundle(); + answerDetailBundle.putString(EntranceUtils.KEY_ANSWER_ID, mDetailEntity.getMe().getMyAnswerId()); + NormalActivity.startFragmentForResult(getContext(), AnswerDetailFragment.class, answerDetailBundle, ANSWER_PATCH_REQUEST); + break; + case NOT_ANSWERED_YET: + CheckLoginUtils.checkLogin(getContext(), () -> { + Bundle answerEditBundle = new Bundle(); + answerEditBundle.putString(EntranceUtils.KEY_QUESTIONS_ID, mDetailEntity.getQuestion().getId()); + answerEditBundle.putString(EntranceUtils.KEY_QUESTIONS_TITLE, mDetailEntity.getQuestion().getTitle()); + NormalActivity.startFragmentForResult(getActivity(), AnswerEditFragment.class, answerEditBundle, ANSWER_PATCH_REQUEST); + }); + break; + } + break; + case R.id.answer_detail_title_answer_count_tv: + + break; + } + } + + 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); + } + } + + @SuppressLint("DefaultLocale") + private void updateView() { + mCollectMenuItem = getItemMenu(R.id.menu_collect); + + if (mDetailEntity.getMe().isAnswerFavorite()) { + mCollectMenuItem.setIcon(R.drawable.menu_ic_question_concern_select); + } else { + mCollectMenuItem.setIcon(R.drawable.menu_ic_question_concern_unselect); + } + + UserEntity user = mDetailEntity.getUser(); + if (user != null) { + ImageUtils.Companion.display(mUsericon, user.getIcon()); + mUsername.setText(user.getName()); + } + + mAnswerCountTv.setText(String.format("查看全部%d个答案", mDetailEntity.getQuestion().getAnswerCount())); + + // 是否已回答 + if (!TextUtils.isEmpty(mDetailEntity.getMe().getMyAnswerId())) { + mAnswerStatusTv.setText("我的回答"); + mAnswerStatusIv.setImageResource(R.drawable.ic_answer_detail_edit_full); + if (mDetailEntity.getMe().isAnswerOwn()) { + mAnswerStatus = ANSWERED_MY_ANSWER; + } else { + mAnswerStatus = ANSWERED_NOT_MY_ANSWER; + } + } else { + mAnswerStatus = NOT_ANSWERED_YET; + mAnswerStatusTv.setText("我来回答"); + } + + if (mDetailEntity.getPublishTime() == mDetailEntity.getUpdateTime()) { + mTime.setText(String.format("发布于 %s", NewsUtils.getFormattedTime(mDetailEntity.getPublishTime()))); + } else { + mTime.setText(String.format("编辑于 %s", NewsUtils.getFormattedTime(mDetailEntity.getUpdateTime()))); + } + + mAnswerCommentCountTv.setText(String.format("%d 评论", mDetailEntity.getQuestion().getCommentCount())); + + mNoConn.setVisibility(View.GONE); + mLoading.setVisibility(View.GONE); + mContent.setVisibility(View.VISIBLE); + + updateVote(); + } + + private void updateVote() { + mVoteCount.setText(getString(R.string.ask_vote_count, AskUtils.voteCountFormat(mDetailEntity.getVote()))); + + if (getContext() == null) return; + if (mDetailEntity.getMe().isAnswerVoted()) { + mVote.setImageResource(R.drawable.answer_detail_unvote); + mVoteCount.setTextColor(ContextCompat.getColor(getContext(), R.color.theme)); + } else { + mVote.setImageResource(R.drawable.answer_detail_vote); + mVoteCount.setTextColor(ContextCompat.getColor(getContext(), R.color.hint)); + } + } + + @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); + } } public class JsInterface { - @JavascriptInterface public void imageClick(String url) { if (url.contains("web_load_dfimg_icon.png")) { @@ -159,233 +512,4 @@ public class AnswerDetailFragment extends NormalFragment { } } } - - - @Override - public void onMenuItemClick(MenuItem menuItem) { - switch (menuItem.getItemId()) { - case R.id.menu_share: - if (mDetailEntity == null) return; - String shareIcon; - String shareSummary = mRichEditor.getText(); - if (mAnswersImgs.size() > 0) { - shareIcon = mAnswersImgs.get(0); - } else { - shareIcon = getString(R.string.share_ghzs_logo); - } - if (TextUtils.isEmpty(shareSummary)) { - shareSummary = getString(R.string.ask_share_default_summary); - } - - ShareUtils.getInstance(getContext()).showShareWindows(getActivity(), getView() - , getString(R.string.share_answers_url, mDetailEntity.getQuestion().getId(), mAnswerId) - , shareIcon - , getString(R.string.ask_share_answers_title, mDetailEntity.getUser().getName(), mDetailEntity.getQuestion().getTitle(), mDetailEntity.getVote()) - , shareSummary, ShareUtils.ShareType.askNormal); - break; - case R.id.menu_collect: - if (mDetailEntity == null) return; - CheckLoginUtils.checkLogin(getContext(), () -> { - if (!mDetailEntity.getMe().isAnswerFavorite()) { - CollectionUtils.INSTANCE.postCollection(getContext(), mAnswerId - , CollectionUtils.CollectionType.answer, new CollectionUtils.OnCollectionListener() { - @Override - public void onSuccess() { - mMenuCollect.setIcon(R.drawable.menu_ic_collect_select); - toast(R.string.collection_success); - MeEntity me = mDetailEntity.getMe(); - me.setAnswerFavorite(true); - mDetailEntity.setMe(me); - } - - @Override - public void onError() { - toast(R.string.collection_failure); - } - }); - } else { - CollectionUtils.INSTANCE.deleteCollection(getContext(), mAnswerId - , CollectionUtils.CollectionType.answer, new CollectionUtils.OnCollectionListener() { - @Override - public void onSuccess() { - mMenuCollect.setIcon(R.drawable.menu_ic_collect_unselect); - MeEntity me = mDetailEntity.getMe(); - me.setAnswerFavorite(false); - mDetailEntity.setMe(me); - toast(R.string.collection_cancel); - - } - - @Override - public void onError() { - toast(R.string.collection_cancel_failure); - } - }); - } - }); - break; - } - } - - @OnClick({R.id.answer_detail_edit, R.id.answer_detail_vote, R.id.reuse_no_connection, R.id.answer_detail_title}) - 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(); - } else { - toast(R.string.ask_vote_hint); - } - }); - break; - case R.id.reuse_no_connection: - mNoConn.setVisibility(View.GONE); - mLoading.setVisibility(View.VISIBLE); - initData(); - break; - case R.id.answer_detail_title: - if (mDetailEntity != null) { - Bundle bundle = new Bundle(); - bundle.putString(EntranceUtils.KEY_QUESTIONS_ID, mDetailEntity.getQuestion().getId()); - bundle.putString(EntranceUtils.KEY_ENTRANCE, mEntrance); - NormalActivity.startFragment(getContext(), QuestionsDetailFragment.class, bundle); - } - 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 initView() { - 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(); - } - - private void initVote() { - mVoteCount.setText(getString(R.string.ask_vote_count, AskUtils.voteCountFormat(mDetailEntity.getVote()))); - - if (getContext() == null) return; - if (mDetailEntity.getMe().isAnswerVoted()) { - mVote.setImageResource(R.drawable.answer_detail_unvote); - mVoteCount.setTextColor(ContextCompat.getColor(getContext(), R.color.theme)); - } else { - mVote.setImageResource(R.drawable.answer_detail_vote); - mVoteCount.setTextColor(ContextCompat.getColor(getContext(), R.color.hint)); - } - } - - 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(); - } - - @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); - } - }); - } } diff --git a/app/src/main/java/com/gh/gamecenter/ask/entity/AnswerDetailEntity.kt b/app/src/main/java/com/gh/gamecenter/ask/entity/AnswerDetailEntity.kt index 861a37804c..22703e8994 100644 --- a/app/src/main/java/com/gh/gamecenter/ask/entity/AnswerDetailEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/ask/entity/AnswerDetailEntity.kt @@ -3,6 +3,7 @@ package com.gh.gamecenter.ask.entity import android.os.Parcel import android.os.Parcelable import com.gh.gamecenter.entity.UserEntity +import com.google.gson.annotations.SerializedName /** * Created by khy on 18/12/17. @@ -13,6 +14,12 @@ class AnswerDetailEntity() : Parcelable { var time: Long = 0 + @SerializedName("publish_time") + var publishTime: Long = 0 + + @SerializedName("update_time") + var updateTime: Long = 0 + var question: Questions = Questions() var me: MeEntity = MeEntity() diff --git a/app/src/main/java/com/gh/gamecenter/ask/entity/Questions.kt b/app/src/main/java/com/gh/gamecenter/ask/entity/Questions.kt index 02e20ff4d0..bd5c356cd7 100644 --- a/app/src/main/java/com/gh/gamecenter/ask/entity/Questions.kt +++ b/app/src/main/java/com/gh/gamecenter/ask/entity/Questions.kt @@ -20,11 +20,15 @@ class Questions() : Parcelable { @SerializedName("answer_count") var answerCount: Int = 0 + @SerializedName("comment_count") + var commentCount:Int = 0 + constructor(parcel: Parcel) : this() { id = parcel.readString() title = parcel.readString() communityName = parcel.readString() answerCount = parcel.readInt() + commentCount = parcel.readInt() } override fun writeToParcel(parcel: Parcel, flags: Int) { @@ -32,6 +36,7 @@ class Questions() : Parcelable { parcel.writeString(title) parcel.writeString(communityName) parcel.writeInt(answerCount) + parcel.writeInt(commentCount) } override fun describeContents(): Int { diff --git a/app/src/main/java/com/gh/gamecenter/ask/viewmodel/AnswerCommentConversationFragment.java b/app/src/main/java/com/gh/gamecenter/ask/viewmodel/AnswerCommentConversationFragment.java new file mode 100644 index 0000000000..0fcb5aa328 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/ask/viewmodel/AnswerCommentConversationFragment.java @@ -0,0 +1,64 @@ +package com.gh.gamecenter.ask.viewmodel; + +import android.annotation.SuppressLint; +import android.app.Application; +import android.arch.lifecycle.ViewModelProviders; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.View; + +import com.gh.common.util.EntranceUtils; +import com.gh.gamecenter.R; +import com.gh.gamecenter.ask.AnswerCommentFragment; +import com.gh.gamecenter.entity.CommentEntity; + +import butterknife.BindView; + +public class AnswerCommentConversationFragment extends AnswerCommentFragment { + + @BindView(R.id.answer_comment_content_container) + View mCommentContainer; + + private String mCommentId; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mCommentId = getArguments().getString(EntranceUtils.KEY_COMMENTID); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mCommentContainer.setVisibility(View.GONE); + setNavigationTitle("查看对话"); + + mListRv.setOnTouchListener((v, event) -> { + if (mCommentContainer.getVisibility() == View.VISIBLE) { + mCommentContainer.setVisibility(View.GONE); + } + return false; + }); + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_answer_comment_conversation; + } + + @Override + protected AnswerCommentViewModel provideListViewModel() { + return ViewModelProviders.of(this, new AnswerCommentViewModel.Factory((Application) getContext().getApplicationContext(), mAnswerId, mCommentId)).get(AnswerCommentViewModel.class); + } + + @Override + public void onCommentCallback(CommentEntity entity) { + + mCommentContainer.setVisibility(View.VISIBLE); + mCommentEntity = entity; + setSoftInput(true); + } +} 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..1202b1ea6b --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/ask/viewmodel/AnswerCommentViewModel.java @@ -0,0 +1,102 @@ +package com.gh.gamecenter.ask.viewmodel; + +import android.app.Application; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.MutableLiveData; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +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 String mAnswerId; + private String mCommentId; + + private MutableLiveData> mPostCommentLiveData = new MutableLiveData<>(); + + public AnswerCommentViewModel(@NonNull Application application, String answerId, @Nullable String commentId) { + super(application); + mResultLiveData.addSource(mListLiveData, mResultLiveData::postValue); + mAnswerId = answerId; + mCommentId = commentId; + } + + @Override + public Observable> provideDataObservable(int offset) { + if (TextUtils.isEmpty(mCommentId)) { + return RetrofitManager.getInstance(getApplication()).getApi().getAnswerCommentList(mAnswerId, 0, offset); + } else { + return RetrofitManager.getInstance(getApplication()).getApi().getAnswerCommentConversationList(mAnswerId, mCommentId, 0, offset); + } +// return RetrofitManager.getInstance(getApplication()).getApi().getComment("59c0b965e9a64abe2a423544", 0, offset); + } + + public void postComment(String content, String answerId, CommentEntity commentEntity) { + + JSONObject jsonObject = new JSONObject(); + try { + jsonObject.put("content", content); + } catch (JSONException e) { + e.printStackTrace(); + } + + PostCommentUtils.addAnswerComment(getApplication(), answerId, 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; + } + + public static class Factory extends ViewModelProvider.NewInstanceFactory { + private Application mApplication; + private String mAnswerId; + private String mCommentId; + + public Factory(Application application, String answerId, String commentId) { + mApplication = application; + mAnswerId = answerId; + mCommentId = commentId; + } + + @Override + public T create(Class modelClass) { + return (T) new AnswerCommentViewModel(mApplication, mAnswerId, mCommentId); + } + } +} 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/java/com/gh/gamecenter/entity/CommentParentEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/CommentParentEntity.kt index 61dd3e1ffe..0625e0296b 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/CommentParentEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/CommentParentEntity.kt @@ -5,13 +5,16 @@ import android.os.Parcelable class CommentParentEntity() : Parcelable { var user: UserEntity? = null + var content: String? = null constructor(parcel: Parcel) : this() { user = parcel.readParcelable(UserEntity::class.java.classLoader) + content = parcel.readString() } override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeParcelable(user, flags) + parcel.writeString(content) } override fun describeContents(): Int { diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java index be7a110e1f..4c5f8d959c 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java @@ -895,9 +895,39 @@ public interface ApiService { // @GET("settings") // Observable getDefaultCommunity(); -// @GET("settings") + // @GET("settings") // Observable> getGhzsControlData(@Query("version") String version, @Query("channel") String channel); @GET("settings") Observable getSettings(); + + /** + * 给一个回答新增评论 + */ + @POST("answers/{answer_id}/comments") + Observable postNewCommentToAnswer(@Path("answer_id") String answerId, @Body RequestBody body); + + /** + * 在评论列表回复某一条评论 + */ + @POST("answers/{answer_id}/comments/{comment_id}:reply") + Observable postReplyToAnswerComment(@Path("answer_id") String answerId, @Path("comment_id") String commentId, @Body RequestBody body); + + /** + * 对评论的点赞 + */ + @POST("answers/{answer_id}/comments/{comment_id}:vote") + Observable postVoteAnswerComment(@Path("answer_id") String answerId, @Path("comment_id") String commentId); + + /** + * 获取评论列表.可以分页 + */ + @GET("answers/{answer_id}/comments") + Observable> getAnswerCommentList(@Path("answer_id") String answerId, @Query("limit") int limit, @Query("offset") int offset); + + /** + * 获取评论的对话列表. + */ + @GET("answers/{answer_id}/comments/{comment_id}/trace") + Observable> getAnswerCommentConversationList(@Path("answer_id") String answerId, @Path("comment_id") String commentId, @Query("limit") int limit, @Query("offset") int offset); } \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/ic_like_select.png b/app/src/main/res/drawable-hdpi/ic_like_select.png deleted file mode 100644 index 1e5e84383f..0000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_like_select.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_like_unselect.png b/app/src/main/res/drawable-hdpi/ic_like_unselect.png deleted file mode 100644 index 9585f4c2aa..0000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_like_unselect.png and /dev/null differ 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 0000000000..95fe968e51 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_answer_comment_close.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_answer_detail_arrow.png b/app/src/main/res/drawable-xhdpi/ic_answer_detail_arrow.png new file mode 100644 index 0000000000..6baaca2c68 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_answer_detail_arrow.png differ 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 0000000000..c671021235 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_answer_detail_check_comment.png differ 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 0000000000..ee5564f625 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_answer_detail_edit_empty.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_answer_detail_edit_full.png b/app/src/main/res/drawable-xhdpi/ic_answer_detail_edit_full.png new file mode 100644 index 0000000000..d47c8ec1bc Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_answer_detail_edit_full.png differ 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 0000000000..d12b65d741 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_answer_detail_write_comment.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_like_select.png b/app/src/main/res/drawable-xhdpi/ic_like_select.png new file mode 100644 index 0000000000..8ea70341a2 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_like_select.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_like_unselect.png b/app/src/main/res/drawable-xhdpi/ic_like_unselect.png new file mode 100644 index 0000000000..9a9b36bf45 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_like_unselect.png differ diff --git a/app/src/main/res/drawable-xhdpi/menu_more.png b/app/src/main/res/drawable-xhdpi/menu_more.png new file mode 100644 index 0000000000..9f51a5056f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/menu_more.png differ diff --git a/app/src/main/res/drawable/round_grey_bg.xml b/app/src/main/res/drawable/round_grey_bg.xml new file mode 100644 index 0000000000..3ba9f23d4a --- /dev/null +++ b/app/src/main/res/drawable/round_grey_bg.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/answer_comment_item.xml b/app/src/main/res/layout/answer_comment_item.xml new file mode 100644 index 0000000000..afcd1eeb59 --- /dev/null +++ b/app/src/main/res/layout/answer_comment_item.xml @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file 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..fe65a66821 --- /dev/null +++ b/app/src/main/res/layout/fragment_answer_comment.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_answer_comment_conversation.xml b/app/src/main/res/layout/fragment_answer_comment_conversation.xml new file mode 100644 index 0000000000..a5cd640a2e --- /dev/null +++ b/app/src/main/res/layout/fragment_answer_comment_conversation.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_answer_detail.xml b/app/src/main/res/layout/fragment_answer_detail.xml index 73ff8da9f8..6346131a51 100644 --- a/app/src/main/res/layout/fragment_answer_detail.xml +++ b/app/src/main/res/layout/fragment_answer_detail.xml @@ -1,159 +1,287 @@ - + - + + + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + android:id="@+id/answer_detail_username" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="10dp" + android:maxLength="10" + android:textColor="@color/title" + android:textSize="14sp" + app:layout_constraintBottom_toTopOf="@+id/answer_detail_Rd" + app:layout_constraintLeft_toRightOf="@id/answer_detail_usericon" + app:layout_constraintTop_toBottomOf="@id/answer_detail_line2" /> - + + + + + + + + + + + + + + + + + + + + + + android:layout_width="1dp" + android:layout_height="match_parent" + android:background="#f5f5f5" /> - + - + - + + + - + - + + - - - - - - - - - - - - - \ No newline at end of file + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_comment_detail.xml b/app/src/main/res/layout/fragment_comment_detail.xml index 03feda2115..e2fbd53186 100644 --- a/app/src/main/res/layout/fragment_comment_detail.xml +++ b/app/src/main/res/layout/fragment_comment_detail.xml @@ -1,8 +1,9 @@ - + + android:visibility = "gone" + tools:visibility = "visible"> + + + + + \ 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 new file mode 100644 index 0000000000..516c94568b --- /dev/null +++ b/app/src/main/res/layout/menu_answer_detail_more.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/piece_comment_typing_container.xml b/app/src/main/res/layout/piece_comment_typing_container.xml new file mode 100644 index 0000000000..1901fc8335 --- /dev/null +++ b/app/src/main/res/layout/piece_comment_typing_container.xml @@ -0,0 +1,46 @@ + + + + + + + + +