From 692f53d8cef32d17cc784b25eeaf766092398df4 Mon Sep 17 00:00:00 2001 From: likebamboo Date: Thu, 16 Jul 2015 21:12:48 +0800 Subject: [PATCH] feedback is ok --- app/src/main/AndroidManifest.xml | 2 +- .../osa/android/entity/BaseRsp.java | 3 + .../osa/android/entity/Feedback.java | 86 +++++ .../osa/android/entity/IssueList.java | 111 ++++++ .../osa/android/request/RequestUrl.java | 10 + .../osa/android/ui/BlogActivity.java | 26 +- .../ui/fragments/FeedbackFragment.java | 317 ++++++++++++++++++ .../osa/android/ui/view/TagGroup.java | 59 +++- .../view/blur/BlurDialogFragmentHelper.java | 11 +- .../osa/android/utils/ValidateUtil.java | 43 +++ .../drawable/bg_feedback_submit_selector.xml | 25 ++ app/src/main/res/drawable/bg_tag_selector.xml | 2 +- app/src/main/res/layout/fragment_feedback.xml | 103 ++++++ app/src/main/res/values/strings.xml | 10 + 14 files changed, 797 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/com/likebamboo/osa/android/entity/Feedback.java create mode 100644 app/src/main/java/com/likebamboo/osa/android/entity/IssueList.java create mode 100644 app/src/main/java/com/likebamboo/osa/android/ui/fragments/FeedbackFragment.java create mode 100644 app/src/main/java/com/likebamboo/osa/android/utils/ValidateUtil.java create mode 100644 app/src/main/res/drawable/bg_feedback_submit_selector.xml create mode 100644 app/src/main/res/layout/fragment_feedback.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fd2408a..506e65a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -76,7 +76,7 @@ android:name="com.likebamboo.osa.android.ui.BlogActivity" android:configChanges="keyboardHidden|orientation|screenSize" android:label="@string/app_name" - android:windowSoftInputMode="adjustPan"/> + android:windowSoftInputMode="adjustResize"/> issues = null; + + @JsonProperty("blogId") + private Long blogId = 0L; + + public String getAddTime() { + return addTime; + } + + public void setAddTime(String addTime) { + this.addTime = addTime; + } + + public String getContact() { + return contact; + } + + public void setContact(String contact) { + this.contact = contact; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public ArrayList getIssues() { + return issues; + } + + public void setIssues(ArrayList issuesArr) { + this.issues = issuesArr; + } + + public Long getBlogId() { + return blogId; + } + + public void setBlogId(Long blogId) { + this.blogId = blogId; + } + + @Override + public String toString() { + return "Feedback [contact=" + contact + ", description=" + description + ", addTime=" + addTime + ", issues=" + issues + "]"; + } + +} diff --git a/app/src/main/java/com/likebamboo/osa/android/entity/IssueList.java b/app/src/main/java/com/likebamboo/osa/android/entity/IssueList.java new file mode 100644 index 0000000..7110c4a --- /dev/null +++ b/app/src/main/java/com/likebamboo/osa/android/entity/IssueList.java @@ -0,0 +1,111 @@ + +package com.likebamboo.osa.android.entity; + +import android.os.Parcel; +import android.os.Parcelable; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; + +/** + * Created by wentaoli on 2015/7/16. + */ +public class IssueList extends BaseRsp { + + @JsonProperty("result") + private ArrayList mList = null; + + public ArrayList getList() { + return mList; + } + + public void setList(ArrayList list) { + this.mList = list; + } + + /** + * 问题表 + * + * @author likebamboo + */ + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Issue implements Parcelable { + + /** + * 名称 + */ + private String name = ""; + + /** + * 描述 + */ + private String description = ""; + + /** + * 添加时间 + */ + private String addTime = ""; + + public String getAddTime() { + return addTime; + } + + public void setAddTime(String addTime) { + this.addTime = addTime; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "issue [name=" + name + "]"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.name); + dest.writeString(this.description); + dest.writeString(this.addTime); + } + + public Issue() { + } + + private Issue(Parcel in) { + this.name = in.readString(); + this.description = in.readString(); + this.addTime = in.readString(); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public Issue createFromParcel(Parcel source) { + return new Issue(source); + } + + public Issue[] newArray(int size) { + return new Issue[size]; + } + }; + } +} diff --git a/app/src/main/java/com/likebamboo/osa/android/request/RequestUrl.java b/app/src/main/java/com/likebamboo/osa/android/request/RequestUrl.java index b8083ce..07ff97c 100644 --- a/app/src/main/java/com/likebamboo/osa/android/request/RequestUrl.java +++ b/app/src/main/java/com/likebamboo/osa/android/request/RequestUrl.java @@ -57,6 +57,16 @@ public class RequestUrl { */ public static final String TAG_BLOG_URL = BLOG_URL + "/tag/%s/"; + /** + * issues + */ + public static final String ISSUES_LIST_URL = BASE_URL + "issue/"; + + /** + * feedback.save + */ + public static final String FEEDBACK_SAVE_URL = BASE_URL + "feedback/save?random=%s"; + /** * 关于我 */ diff --git a/app/src/main/java/com/likebamboo/osa/android/ui/BlogActivity.java b/app/src/main/java/com/likebamboo/osa/android/ui/BlogActivity.java index 3e3082c..1b3b63c 100644 --- a/app/src/main/java/com/likebamboo/osa/android/ui/BlogActivity.java +++ b/app/src/main/java/com/likebamboo/osa/android/ui/BlogActivity.java @@ -16,6 +16,7 @@ import com.likebamboo.osa.android.request.RequestManager; import com.likebamboo.osa.android.request.RequestUrl; import com.likebamboo.osa.android.ui.fragments.BlogInfoFragment; +import com.likebamboo.osa.android.ui.fragments.FeedbackFragment; import com.likebamboo.osa.android.ui.nav.ActivityNavigator; import com.likebamboo.osa.android.ui.view.CommonWebView; import com.likebamboo.osa.android.ui.view.LoadingLayout; @@ -229,11 +230,34 @@ public void onClick(View view) { doUnFavorite(); } }); + // 反馈 mIssueTv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - //TODO 反馈 + // 反馈 + if (isFinishing()) { + return; + } + if (mBlogInfo != null) { + // 显示博客详情信息 + FeedbackFragment fragment = FeedbackFragment.getInstance(mBlogInfo.getBlogId(), mBlogInfo.getTitle()); + fragment.show(getSupportFragmentManager(), "feedback"); + return; + } + // 加载博客信息 + loadBlogInfo(new Response.Listener() { + @Override + public void onResponse(BlogList.Blog blog) { + mLoadingLayout.showLoading(false); + if (blog != null) { + mBlogInfo = blog; + // 显示博客详情信息 + FeedbackFragment fragment = FeedbackFragment.getInstance(mBlogInfo.getBlogId(), mBlogInfo.getTitle()); + fragment.show(getSupportFragmentManager(), "feedback"); + } + } + }); } }); diff --git a/app/src/main/java/com/likebamboo/osa/android/ui/fragments/FeedbackFragment.java b/app/src/main/java/com/likebamboo/osa/android/ui/fragments/FeedbackFragment.java new file mode 100644 index 0000000..b866beb --- /dev/null +++ b/app/src/main/java/com/likebamboo/osa/android/ui/fragments/FeedbackFragment.java @@ -0,0 +1,317 @@ +package com.likebamboo.osa.android.ui.fragments; + +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.TextView; + +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.VolleyError; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.likebamboo.osa.android.R; +import com.likebamboo.osa.android.entity.BaseRsp; +import com.likebamboo.osa.android.entity.Feedback; +import com.likebamboo.osa.android.entity.IssueList; +import com.likebamboo.osa.android.request.JsonRequest; +import com.likebamboo.osa.android.request.RequestManager; +import com.likebamboo.osa.android.request.RequestParams; +import com.likebamboo.osa.android.request.RequestUrl; +import com.likebamboo.osa.android.ui.view.LoadingLayout; +import com.likebamboo.osa.android.ui.view.TagGroup; +import com.likebamboo.osa.android.ui.view.blur.BlurDialogFragmentHelper; +import com.likebamboo.osa.android.utils.ToastUtil; +import com.likebamboo.osa.android.utils.ValidateUtil; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Random; + +import butterknife.ButterKnife; +import butterknife.InjectView; + +/** + * 反馈Fragment + * + * @author likebamboo + */ +public class FeedbackFragment extends DialogFragment { + /** + * 博客id + */ + public static final String EXTRA_BLOG_ID = "extra_blog_id"; + + /** + * 博客标题 + */ + public static final String EXTRA_BLOG_TITLE = "extra_blog_title"; + + /** + * TAG + */ + public static final String TAG = "feedback"; + + private BlurDialogFragmentHelper mHelper; + + /** + * 反馈信息 + */ + private Feedback mFeedback = null; + + /** + * 博客标题 + */ + private String mBlogTitle = ""; + + @InjectView(R.id.feed_title_tv) + TextView mTitleTv; + + @InjectView(R.id.feed_contact_et) + EditText mContactEt; + + @InjectView(R.id.feed_issues_tags) + TagGroup mIssuesTag; + + @InjectView(R.id.feed_desc_et) + EditText mDescEt; + + @InjectView(R.id.feed_submit_tv) + TextView mSubmitTv; + + @InjectView(R.id.loading_layout) + LoadingLayout mLoadingLayout; + + /** + * + */ + ObjectMapper mapper = null; + + /** + * instance + * + * @param blogId + * @return + */ + public static FeedbackFragment getInstance(long blogId, String blogTitle) { + FeedbackFragment fragment = new FeedbackFragment(); + Bundle bundle = new Bundle(); + bundle.putLong(EXTRA_BLOG_ID, blogId); + bundle.putString(EXTRA_BLOG_TITLE, blogTitle); + fragment.setArguments(bundle); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mHelper = new BlurDialogFragmentHelper(this); + mHelper.setDismissOnTouch(false); + mHelper.onCreate(); + mFeedback = new Feedback(); + mFeedback.setIssues(new ArrayList()); + if (getArguments() != null) { + mFeedback.setBlogId(getArguments().getLong(EXTRA_BLOG_ID)); + mBlogTitle = getArguments().getString(EXTRA_BLOG_TITLE); + } + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.fragment_feedback, container, false); + ButterKnife.inject(this, v); + + // 标题 + mTitleTv.setText(mBlogTitle); + // 加载tag + loadingIssues(mIssuesTag); + + // 提交 + mSubmitTv.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (getActivity() == null || getActivity().isFinishing()) { + return; + } + + // 验证联系方式 + if (TextUtils.isEmpty(mContactEt.getText().toString().trim())) { + ToastUtil.show(getActivity().getApplicationContext(), getString(R.string.please_input_contact)); + return; + } + + // 验证联系方式 + if (!validateContact(mContactEt.getText().toString().trim())) { + ToastUtil.show(getActivity().getApplicationContext(), getString(R.string.please_input_contact_correct)); + return; + } + + // 问题 + if (mFeedback.getIssues() == null || mFeedback.getIssues().isEmpty()) { + ToastUtil.show(getActivity().getApplicationContext(), getString(R.string.please_select_issues)); + return; + } + + // 问题详情 + if (TextUtils.isEmpty(mDescEt.getText().toString().trim())) { + ToastUtil.show(getActivity().getApplicationContext(), getString(R.string.please_write_detail)); + return; + } + + // 置为不可点击 + mSubmitTv.setEnabled(false); + + // + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + mFeedback.setAddTime(sdf.format(new Date())); + mFeedback.setContact(mContactEt.getText().toString().trim()); + mFeedback.setDescription(mDescEt.getText().toString().trim()); + + doFeedback(); + } + }); + + return v; + } + + /** + * + */ + private void doFeedback() { + if (mFeedback == null) { + return; + } + mLoadingLayout.showLoading(true); + RequestParams params = new RequestParams(); + + // Convert object to JSON string + try { + if (mapper == null) { + mapper = new ObjectMapper(); + } + String json = mapper.writeValueAsString(mFeedback); + params.add("feedback", json); + } catch (Exception e) { + e.printStackTrace(); + return; + } + + // 服务器端有BUG,post请求返回了cache-age,导致有缓存。 + // 客户端做兼容方案, + JsonRequest request = new JsonRequest(Request.Method.POST, + String.format(RequestUrl.FEEDBACK_SAVE_URL, "" + (new Random()).nextInt()), BaseRsp.class, params, + new Response.Listener() { + @Override + public void onResponse(BaseRsp resp) { + mSubmitTv.setEnabled(true); + if (getActivity() == null || getActivity().isFinishing()) { + return; + } + mLoadingLayout.showLoading(false); + if (resp != null && resp.getErrorCode() == 0) { + // 请求成功 + ToastUtil.show(getActivity().getApplicationContext(), getString(R.string.feedback_commit_success)); + dismiss(); + return; + } + if (resp != null) { + // 请求失败 + ToastUtil.show(getActivity().getApplicationContext(), resp.getMessage()); + } + } + }, + new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError volleyError) { + mSubmitTv.setEnabled(true); + if (volleyError == null || getActivity() == null || getActivity().isFinishing()) { + return; + } + mLoadingLayout.showLoading(false); + // 请求失败 + ToastUtil.show(getActivity().getApplicationContext(), volleyError.getMessage()); + } + }); + RequestManager.addRequest(request, TAG); + } + + /** + * 验证联系方式格式 + * + * @param info + * @return + */ + private boolean validateContact(String info) { + if (TextUtils.isEmpty(info)) { + return false; + } + + return ValidateUtil.isEmail(info) || ValidateUtil.isPhoneNum(info); + } + + /** + * 加载issues列表 + */ + private void loadingIssues(final TagGroup tagGroup) { + JsonRequest request = new JsonRequest(RequestUrl.ISSUES_LIST_URL, IssueList.class, new Response.Listener() { + @Override + public void onResponse(IssueList issueList) { + if (issueList == null || getActivity() == null) { + return; + } + ArrayList issues = issueList.getList(); + if (issues != null && !issues.isEmpty()) { + ArrayList tags = new ArrayList(); + for (IssueList.Issue issue : issues) { + tags.add(issue.getName()); + } + tagGroup.setTags(tags); + // 设置tag单击事件 + tagGroup.setOnTagClickListener(new TagGroup.IOnTagClickListener() { + @Override + public void onTagClick(String tag) { + boolean selected = tagGroup.isTagSelected(tag); + if (selected) { + mFeedback.getIssues().remove(tag); + } else { + mFeedback.getIssues().add(tag); + } + tagGroup.setTagSelected(tag, !selected); + } + + @Override + public void onTagLongClick(String tag) { + + } + }); + } + } + }, null); + RequestManager.addRequest(request, "issues"); + } + + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + mHelper.onActivityCreated(); + } + + @Override + public void onStart() { + super.onStart(); + mHelper.onStart(); + } + + @Override + public void onDismiss(DialogInterface dialog) { + mHelper.onDismiss(); + super.onDismiss(dialog); + RequestManager.cancelAll("issues"); + RequestManager.cancelAll(TAG); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/likebamboo/osa/android/ui/view/TagGroup.java b/app/src/main/java/com/likebamboo/osa/android/ui/view/TagGroup.java index 80de813..1fbfe9a 100644 --- a/app/src/main/java/com/likebamboo/osa/android/ui/view/TagGroup.java +++ b/app/src/main/java/com/likebamboo/osa/android/ui/view/TagGroup.java @@ -335,12 +335,7 @@ public void deleteTag(CharSequence tag) { if (TextUtils.isEmpty(tag)) { return; } - int index = 0; - for (; index < getChildCount(); index++) { - if (getTagViewAt(index).getText().equals(tag)) { - break; - } - } + int index = getTagIndex(tag); if (index < getChildCount()) { removeViewAt(index); } @@ -421,7 +416,57 @@ public boolean onLongClick(View view) { addView(tagView, index, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); } - public float dp2px(float dp) { + /** + * 设置tag选中状态 + * + * @param tag + * @param selected + */ + public void setTagSelected(String tag, boolean selected) { + int index = getTagIndex(tag); + if (index >= getChildCount()) { + return; + } + TagView tagView = getTagViewAt(index); + if (tagView != null) { + tagView.setSelected(selected); + } + } + + /** + * 获取tag选中状态 + * + * @param tag + */ + public boolean isTagSelected(String tag) { + int index = getTagIndex(tag); + if (index >= getChildCount()) { + return false; + } + TagView tagView = getTagViewAt(index); + if (tagView != null) { + return tagView.isSelected(); + } + return false; + } + + /** + * 获取tag 的index + * + * @param tag + * @return + */ + private int getTagIndex(CharSequence tag) { + int index = 0; + for (; index < getChildCount(); index++) { + if (getTagViewAt(index).getText().toString().equals(tag.toString())) { + break; + } + } + return index; + } + + private float dp2px(float dp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); } diff --git a/app/src/main/java/com/likebamboo/osa/android/ui/view/blur/BlurDialogFragmentHelper.java b/app/src/main/java/com/likebamboo/osa/android/ui/view/blur/BlurDialogFragmentHelper.java index d89e80f..0e97bed 100644 --- a/app/src/main/java/com/likebamboo/osa/android/ui/view/blur/BlurDialogFragmentHelper.java +++ b/app/src/main/java/com/likebamboo/osa/android/ui/view/blur/BlurDialogFragmentHelper.java @@ -38,6 +38,11 @@ public class BlurDialogFragmentHelper { private int mBgColorResId; + /** + * 是否在touch时 dismiss + */ + private boolean dismissOnTouch = true; + public BlurDialogFragmentHelper(@NonNull DialogFragment fragment) { mFragment = fragment; mAnimDuration = fragment.getActivity().getResources().getInteger(android.R.integer.config_mediumAnimTime); @@ -62,6 +67,10 @@ public void setBgColorResId(@ColorRes int bgColorResId) { mBgColorResId = bgColorResId; } + public void setDismissOnTouch(boolean dismissOnTouch) { + this.dismissOnTouch = dismissOnTouch; + } + public void onCreate() { mFragment.setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Translucent_NoTitleBar); } @@ -104,7 +113,7 @@ public void onActivityCreated() { bitmap.recycle(); View view = mFragment.getView(); - if (view != null) { + if (view != null && dismissOnTouch) { view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { diff --git a/app/src/main/java/com/likebamboo/osa/android/utils/ValidateUtil.java b/app/src/main/java/com/likebamboo/osa/android/utils/ValidateUtil.java new file mode 100644 index 0000000..75f0d0e --- /dev/null +++ b/app/src/main/java/com/likebamboo/osa/android/utils/ValidateUtil.java @@ -0,0 +1,43 @@ +package com.likebamboo.osa.android.utils; + +import android.text.TextUtils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 格式验证工具类 + * Created by likebamboo on 2015/7/16. + */ +public class ValidateUtil { + + /** + * 验证手机格式 + * + * @param num + * @return + */ + public static boolean isPhoneNum(String num) { + if (TextUtils.isEmpty(num) || num.length() < 11) { + return false; + } + Pattern pattern = Pattern.compile("^(13[0-9]|15[0-9]|14[7|5]|17[0-9]|18[0-9])\\d{8}$"); + // 匹配手机号码 + Matcher matcher = pattern.matcher(num); + return matcher.matches(); + } + + /** + * 验证邮箱格式 + * + * @param email + * @return + */ + public static boolean isEmail(String email) { + String str = "^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$"; + Pattern p = Pattern.compile(str); + Matcher m = p.matcher(email); + + return m.matches(); + } +} diff --git a/app/src/main/res/drawable/bg_feedback_submit_selector.xml b/app/src/main/res/drawable/bg_feedback_submit_selector.xml new file mode 100644 index 0000000..2a6a505 --- /dev/null +++ b/app/src/main/res/drawable/bg_feedback_submit_selector.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_tag_selector.xml b/app/src/main/res/drawable/bg_tag_selector.xml index dc4f31e..f2c2abd 100644 --- a/app/src/main/res/drawable/bg_tag_selector.xml +++ b/app/src/main/res/drawable/bg_tag_selector.xml @@ -10,7 +10,7 @@ - + diff --git a/app/src/main/res/layout/fragment_feedback.xml b/app/src/main/res/layout/fragment_feedback.xml new file mode 100644 index 0000000..57ea63d --- /dev/null +++ b/app/src/main/res/layout/fragment_feedback.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 523a5d7..07b235e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -50,4 +50,14 @@ 排序 + 联系方式: + 问题: + 请填写邮箱/手机号 + 请填写正确的邮箱或手机号 + 请选择问题类型 + 描述: + 请填写问题详细信息 + 提交 + + 您的反馈信息我们已经收到,感谢使用~