From 80d2e2c4884ea81519f4e5e22293843e9910b665 Mon Sep 17 00:00:00 2001 From: kehaoyuan Date: Wed, 11 Jul 2018 16:50:40 +0800 Subject: [PATCH] =?UTF-8?q?constraintLayout=20=E9=80=80=E6=A1=A3=20?= =?UTF-8?q?=E6=95=B4=E7=90=86=E9=97=AE=E9=A2=98=E7=BC=96=E8=BE=91=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +- app/src/main/AndroidManifest.xml | 2 +- .../newest/AskQuestionsNewBodyFragment.java | 2 +- .../detail/QuestionsDetailFragment.java | 2 +- .../qa/questions/edit/QuestionEditActivity.kt | 228 ++++++++++++++++ .../questions/edit/QuestionEditViewModel.kt | 244 ++++++++++++++++++ .../qa/questions/edit/TagsSelectFragment.kt | 214 +++++++++++++++ .../edit/pic/QuestionsEditPicAdapter.kt | 87 +++++++ .../edit/tip/QuestionTitleTipAdapter.kt | 129 +++++++++ .../AskQuestionsRecommendsFragment.java | 2 +- .../qa/search/AskSearchActivity.java | 2 +- .../qa/search/AskSearchFragment.java | 2 +- .../res/layout/activity_questions_edit.xml | 2 +- dependencies.gradle | 2 +- 14 files changed, 912 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditActivity.kt create mode 100644 app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditViewModel.kt create mode 100644 app/src/main/java/com/gh/gamecenter/qa/questions/edit/TagsSelectFragment.kt create mode 100644 app/src/main/java/com/gh/gamecenter/qa/questions/edit/pic/QuestionsEditPicAdapter.kt create mode 100644 app/src/main/java/com/gh/gamecenter/qa/questions/edit/tip/QuestionTitleTipAdapter.kt diff --git a/README.md b/README.md index 9dcb7ed95e..cef58d1229 100644 --- a/README.md +++ b/README.md @@ -67,4 +67,5 @@ - 把 ListViewModel 的数据结构类型转换方式换为抽象方法,让继承的类实现,避免出现无响应的问题 -- rxjava2 如果接口返回为空 会发生异常:java.lang.NullPointerException: Null is not a valid element (答案编辑) \ No newline at end of file +- rxjava2 如果接口返回为空 会发生异常:java.lang.NullPointerException: Null is not a valid element (答案编辑) +- constraintLayout 1.1.2 导致布局出现异常(问题编辑标签选择弹窗) \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 47719f2371..44a8572aa4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -299,7 +299,7 @@ android:screenOrientation = "portrait" /> (QuestionsDetailEntity.TAG) + if (detailEntity != null) { // 问题编辑 + mViewModel?.questionEntity = detailEntity + mViewModel?.content = detailEntity.description + mViewModel?.picList?.postValue(detailEntity.images as MutableList?) + if (mViewModel?.title.isNullOrEmpty()) mViewModel?.title = detailEntity.title + } else { // 新增问题 + var searchKey = intent.getStringExtra(EntranceUtils.KEY_QUESTIONS_SEARCH_KEY) + if (!searchKey.isNullOrEmpty() && searchKey.length > QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH) + searchKey = searchKey.substring(0, QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH) + if (mViewModel?.title.isNullOrEmpty()) mViewModel?.title = searchKey + } + } + + // Navigation + if (mViewModel?.questionEntity != null) { + setNavigationTitle("编辑问题") + } else { + setNavigationTitle(UserManager.getInstance().community.name) + } + + mViewModel?.getDefaultTag() + + // TitleTip + if (mViewModel?.questionEntity == null) { + val titleTipAdapter = QuestionTitleTipAdapter(this, mBinding.questionseditTitle, mViewModel?.communityId) + mBinding.questionseditTitle.setAdapter(titleTipAdapter) + } + + // TitleEdit + mBinding.questionseditTitle.addTextChangedListener(LimitTextWatcher(mBinding.questionseditTitle)) + + // ContentEdit + mBinding.questionseditContent.addTextChangedListener(LimitTextWatcher(mBinding.questionseditContent)) + + // Pic List + val picAdapter = QuestionsEditPicAdapter(this, mViewModel!!) + mBinding.suggestPicRv.layoutManager = object : GridLayoutManager(this, 5) { + override fun canScrollVertically(): Boolean { + return false + } + } + mBinding.suggestPicRv.adapter = picAdapter + + // Process dialog + mViewModel?.processDialog?.observe(this, Observer { it -> + if (it?.isShow!!) { + mProcessingDialog = WaitingDialogFragment.newInstance(it.msg, false) + mProcessingDialog?.show(supportFragmentManager, null, { + if (mViewModel?.uploadImageSubscription != null && !mViewModel?.uploadImageSubscription!!.isDisposed) { + mUpdateImageCancelDialog = DialogUtils.showAlertDialog(this, "提示" + , "图片正在上传中,确定取消吗?" + , "确定", "取消", { + mViewModel?.uploadImageSubscription!!.dispose() + mUpdateImageCancelDialog?.dismiss() + mProcessingDialog?.dismiss() + }, null) + } + }) + } else { + mUpdateImageCancelDialog?.dismiss() + mProcessingDialog?.dismiss() + } + }) + + mViewModel?.titleTags?.observe(this, Observer> { + if (supportFragmentManager.findFragmentByTag(TagsSelectFragment::javaClass.name) == null) { + val dialog = BaseDialogWrapperFragment.getInstance(TagsSelectFragment.getInstance(), false) + dialog.show(supportFragmentManager, TagsSelectFragment::javaClass.name) + } + }) + + mViewModel?.picList?.observe(this, Observer { it -> + if (it != null) picAdapter.notifyPicList(it) + }) + + // 增加提问时, 如果searchKey不为空 光标跳到最后 + mBaseHandler.postDelayed({ + if (mViewModel?.questionEntity == null) { + mBinding.questionseditTitle.setSelection(mBinding.questionseditTitle.text.toString().length) + } + }, 50) + } + + override fun onMenuItemClick(menuItem: MenuItem?): Boolean { + mViewModel?.checkTitleAndLoadTitleTag() + return false + } + + + // Limits of EditText + private inner class LimitTextWatcher(private val mEditText: EditText) : TextWatcher { + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { + if (mEditText === mBinding.questionseditTitle) { + val etContent = s.toString() + + // 去空格 + if (etContent.contains(" ")) { + mBinding.questionseditTitle.setText(etContent.replace(" ".toRegex(), "")) + mBinding.questionseditTitle.setSelection(start) + return + } + + // 检查标题最大长度 + if (s.length > QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH) { + mBinding.questionseditTitle.setText("") + val newText = s.toString().substring(0, QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH) + mBinding.questionseditTitle.setText(newText) + mBinding.questionseditTitle.setSelection(mBinding.questionseditTitle.text?.length!!) + toast("标题最多${QuestionEditViewModel.QUESTION_TITLE_MAX_LENGTH}个字") + } + } else if (mEditText === mBinding.questionseditContent) { + + // 检查内容最大长度 + if (s.length > QuestionEditViewModel.QUESTION_CONTENT_MAX_LENGTH) { + mBinding.questionseditContent.setText("") + val newText = s.toString().substring(0, QuestionEditViewModel.QUESTION_CONTENT_MAX_LENGTH) + mBinding.questionseditContent.setText(newText) + mBinding.questionseditContent.setSelection(mBinding.questionseditContent.text.length) + toast("内容最多${QuestionEditViewModel.QUESTION_CONTENT_MAX_LENGTH}个字") + } + } + } + + override fun afterTextChanged(s: Editable) {} + } + + // 退出提示 + override fun onBackPressed() { + // 需要检查的内容,其中任意一个不为空都要打开提示弹窗 + val imgList = mViewModel?.picList?.value + val title = mBinding.questionseditTitle.text.toString().trim() + val content = mBinding.questionseditContent.text.toString().trim() + + if (imgList != null && imgList.size > 0 || title.isNotEmpty() || content.isNotEmpty()) { + DialogUtils.showCancelAlertDialog(this, "提示" + , if (mViewModel?.questionEntity == null) "确定放弃提问吗?" else "确定放弃编辑吗?" + , "再想想", " 放弃", null) { finish() } + return + } + super.onBackPressed() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditViewModel.kt new file mode 100644 index 0000000000..f8df75abb5 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/QuestionEditViewModel.kt @@ -0,0 +1,244 @@ +package com.gh.gamecenter.qa.questions.edit + +import android.app.Application +import android.arch.lifecycle.AndroidViewModel +import android.arch.lifecycle.LiveData +import android.arch.lifecycle.MediatorLiveData +import android.content.Intent +import android.provider.MediaStore +import android.text.TextUtils +import com.gh.base.fragment.WaitingDialogFragment +import com.gh.common.util.GsonUtils +import com.gh.common.util.UploadUtils +import com.gh.common.util.UrlFilterUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.manager.UserManager +import com.gh.gamecenter.mvvm.NetworkBoundResource +import com.gh.gamecenter.mvvm.Resource +import com.gh.gamecenter.qa.entity.QuestionsDetailEntity +import com.gh.gamecenter.retrofit.Response +import com.gh.gamecenter.retrofit.RetrofitManager +import com.gh.gamecenter.retrofit.service.ApiService +import com.lightgame.utils.Utils +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import okhttp3.MediaType +import okhttp3.RequestBody +import okhttp3.ResponseBody +import retrofit2.HttpException +import java.io.File +import java.util.* + +/** + * Created by khy on 28/04/18. + */ +class QuestionEditViewModel(application: Application) : AndroidViewModel(application) { + companion object { + const val QUESTION_TAG_MAX_COUNT = 5 + const val PIC_MAX_AMOUNT = 3 + const val QUESTION_TITLE_MIN_LENGTH = 6 + const val QUESTION_CONTENT_MAX_LENGTH = 300 + const val QUESTION_TITLE_MAX_LENGTH = 50 + const val PIC_MAX_FILE_SIZE = 10 * 1024 * 1024 + } + + private val mApiService: ApiService = RetrofitManager.getInstance(getApplication()).api + + var communityId: String? = null + + val processDialog = MediatorLiveData() + val titleTags = MediatorLiveData>() + + var uploadImageSubscription: Disposable? = null + + // post data + var title: String? = "" + var content: String? = "" + val picList = MediatorLiveData>() + var defaultTags: MutableList = ArrayList() + var questionEntity: QuestionsDetailEntity? = null + val selectedTags: MutableList = ArrayList() + + /** + * 获取默认标签和确定当前communityId + */ + fun getDefaultTag() { + communityId = if (questionEntity != null) questionEntity?.communityId + else UserManager.getInstance().community.id + mApiService + .getCommunitiesTags(communityId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response>() { + override fun onResponse(response: List?) { + defaultTags = response as MutableList + } + }) + } + + /** + * 检查标题是否符合规则 + * 根据问题标题获取相应标签(问题编辑无需获取) + */ + fun checkTitleAndLoadTitleTag() { + if (TextUtils.isEmpty(title)) { + Utils.toast(getApplication(), "标题不能为空") + return + } + + // 检查标题长度限制 + title?.trim() + title = title?.replace(" ", "") + if (title!!.length < QUESTION_TITLE_MIN_LENGTH) { + Utils.toast(getApplication(), "标题至少${QUESTION_TITLE_MIN_LENGTH}个字") + return + } + + // 检查标题结尾是否存在问号,没则主动加上 + if (title!!.length <= QUESTION_TITLE_MAX_LENGTH) { + val endString = title?.substring(title!!.length - 1, title!!.length) + if ("?" != endString && "?" != endString) + title += "?" + } + + selectedTags.clear() // 清空已选择的标签 + if (questionEntity == null) { + loadTitleTags() + } else { + titleTags.postValue(null) + } + } + + /** + * 根据问题标题获取相应标签(标签默认选中) + */ + private fun loadTitleTags() { + processDialog.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", true)) + mApiService + .getQuestionTagsByTitle(communityId, UrlFilterUtils.getFilterQuery("title", title)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Response>() { + override fun onResponse(response: List?) { + titleTags.postValue(response) + processDialog.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", false)) + } + + override fun onFailure(e: HttpException?) { + processDialog.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", false)) + Utils.toast(getApplication(), R.string.request_failure_normal_hint) + } + }) + } + + /** + * 选择动作(选中标签/移除已选中的标签) + */ + fun selectTag(tag: String): Boolean { + return when { + selectedTags.contains(tag) -> { + selectedTags.remove(tag) + false + } + selectedTags.size < QUESTION_TAG_MAX_COUNT -> { + selectedTags.add(tag) + true + } + else -> { + Utils.toast(getApplication(), R.string.questionsdetail_max_tag_hint) + false + } + } + } + + /** + * 检查图片是否符合规则并上传图片 + * @param picPath 图片本地路径 + */ + fun uploadPic(data: Intent) { + val selectedImage = data.data ?: return + val filePathColumn = arrayOf(MediaStore.Images.Media.DATA) + + val application: Application = getApplication() + + val cursor = application.contentResolver.query(selectedImage, filePathColumn, null, null, null) + ?: return + cursor.moveToFirst() + + val columnIndex = cursor.getColumnIndex(filePathColumn[0]) + val picPath = cursor.getString(columnIndex) + cursor.close() + + Utils.log("picturePath = " + picPath) + val file = File(picPath) + if (file.length() > PIC_MAX_FILE_SIZE) { + Utils.toast(getApplication(), R.string.suggestion_pic_hint) + return + } else { + val picList = picList.value + if (picList != null && picList.size >= PIC_MAX_AMOUNT) { + Utils.toast(getApplication(), R.string.questions_edit_maxpic_hint) + return + } + } + + processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...", true)) + uploadImageSubscription = UploadUtils.compressAndUploadImage(picPath, object : UploadUtils.OnUploadImageListener { + override fun onSuccess(imageUrl: String) { + processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...", false)) + val list = picList.value ?: ArrayList() + list.add(imageUrl) + picList.postValue(list) + } + + override fun onError(e: Throwable?) { + processDialog.postValue(WaitingDialogFragment.WaitingDialogData("上传中...", false)) + if (e != null && e is HttpException && e.code() == 403) { + Utils.toast(getApplication(), "图片违规") + } else { + Utils.toast(getApplication(), "图片上传失败,请检查网络") + } + } + }) + } + + /** + * 移除以上传的图片 + * @param picPath 图片成功上传后的URL + */ + fun removePic(picPath: String) { + val list = picList.value + if (list != null && list.remove(picPath)) { + picList.postValue(list) + } + } + + /** + * 提交问题 + */ + fun postQuestion(): LiveData> { + val entity = QuestionsDetailEntity() + entity.title = title + entity.description = content + entity.tags = selectedTags + entity.images = if (picList.value != null) { + picList.value!! + } else { + ArrayList() + } + + val body = RequestBody.create(MediaType.parse("application/json"), GsonUtils.getInstance().toJson(entity)) + val observable = if (questionEntity != null) { + questionEntity?.tags = entity.tags + questionEntity?.images = entity.images + questionEntity?.title = entity.title + questionEntity?.description = entity.description + mApiService.patchQuestions(body, questionEntity?.id) // patch + } else { + mApiService.postQuestions(body, communityId) // add + } + + return NetworkBoundResource(observable).asLiveData() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/edit/TagsSelectFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/TagsSelectFragment.kt new file mode 100644 index 0000000000..3d4fb00eb3 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/TagsSelectFragment.kt @@ -0,0 +1,214 @@ +package com.gh.gamecenter.qa.questions.edit + +import android.app.Activity +import android.app.Dialog +import android.arch.lifecycle.Observer +import android.arch.lifecycle.ViewModelProviders +import android.content.Intent +import android.os.Bundle +import android.support.v4.content.ContextCompat +import android.text.TextUtils +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.Window +import android.widget.EditText +import android.widget.TextView +import com.gh.base.fragment.BaseDialogWrapperFragment +import com.gh.base.fragment.BaseFragment +import com.gh.base.fragment.WaitingDialogFragment +import com.gh.common.util.AskErrorResponseUtils +import com.gh.common.util.DisplayUtils +import com.gh.common.util.LoginUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.mvvm.Status +import com.gh.gamecenter.qa.entity.QuestionsDetailEntity +import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity +import com.google.android.flexbox.FlexboxLayout +import com.lightgame.utils.Util_System_Keyboard +import kotterknife.bindView +import org.json.JSONObject +import java.util.* + +/** + * Created by khy on 28/04/18. + */ +class TagsSelectFragment : BaseFragment() { + + companion object { + fun getInstance(): TagsSelectFragment { + val fragment = TagsSelectFragment() + return fragment + } + } + + private val mTagFl by bindView(R.id.questions_edit_tag) + private val mAddTagBtn by bindView(R.id.questions_edit_tag_add) + private val mPostBtn by bindView(R.id.questions_edit_tag_positive) + private val mCancelBtn by bindView(R.id.questions_edit_tag_cancel) + + private var mViewModel: QuestionEditViewModel? = null + + private val mAllTags: MutableList = ArrayList() // 所有标签集合 + + override fun getLayoutId(): Int { + return R.layout.questions_edit_tag + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (activity != null) mViewModel = ViewModelProviders.of(activity!!).get(QuestionEditViewModel::class.java) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initTags() + + mAddTagBtn.setOnClickListener { + if (mViewModel?.selectedTags?.size!! < QuestionEditViewModel.QUESTION_TAG_MAX_COUNT) { + showAddTagDialog() + } else { + toast(R.string.questionsdetail_max_tag_hint) + } + } + + mCancelBtn.setOnClickListener { + val fragment = parentFragment + (fragment as? BaseDialogWrapperFragment)?.dismiss() + } + + mPostBtn.setOnClickListener { + mViewModel?.postQuestion()?.observe(this, Observer { it -> + when (it?.status) { + Status.SUCCESS -> { + mViewModel?.processDialog?.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", false)) + toast("提交成功") + if (mViewModel?.questionEntity != null) { // 修改问题 + val data = Intent() + data.putExtra(QuestionsDetailEntity.TAG, mViewModel?.questionEntity) + activity?.setResult(Activity.RESULT_OK, data) + } else { + val data = JSONObject(it.data?.string()) + startActivity(QuestionsDetailActivity.getIntent(context, data.getString("_id"), "(回答编辑)")) + } + activity?.finish() + } + Status.ERROR -> { + mViewModel?.processDialog?.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", false)) + if (!LoginUtils.userPostErrorToast(it.exception, context, false)) { + toast("提交失败") + AskErrorResponseUtils.errorResponseControl(context, it.exception) + } + } + Status.LOADING -> { + mViewModel?.processDialog?.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", true)) + } + } + }) + } + + } + + private fun initTags() { + // 添加标签 + val mDefaultTag = mViewModel?.defaultTags ?: ArrayList() + + if (mViewModel?.questionEntity == null) { + val mTitleTag = (mViewModel?.titleTags?.value ?: ArrayList()) as MutableList + // 添加默认标签(如果标题标签与默认标签重复则选中) + for (s in mDefaultTag.reversed()) { + val contains = mTitleTag.contains(tag) + addTag(s, contains) + if (contains) mTitleTag.remove(tag) + } + // 未匹配到默认标签的默认选中在前排 + for (s in mTitleTag) { + addTag(s, true) + } + } else { + val tags = mViewModel?.questionEntity?.tags ?: ArrayList() + for (s in mDefaultTag) { + if (!tags.contains(s)) + addTag(s, false) + } + for (s in tags.reversed()) { + addTag(s, true) + } + } + } + + private fun showAddTagDialog() { + view?.visibility = View.GONE + val dialog = Dialog(context!!) + val view = View.inflate(context, R.layout.dialog_modify_nickname, null) + val title = view.findViewById(R.id.dialog_nickname_title) + val input = view.findViewById(R.id.dialog_nickname_input) + title.text = "新建标签" + input.hint = "" + input.setSelection(input.text.length) + // 取消按钮 + view.findViewById(R.id.dialog_nickname_cancel).setOnClickListener { dialog.dismiss() } + // 确定按钮 + view.findViewById(R.id.dialog_nickname_confirm).setOnClickListener { + if (!TextUtils.isEmpty(input.text.toString().trim())) { + addTag(input.text.toString().trim(), true) + dialog.dismiss() + } else { + toast(R.string.vote_empty_hint) + } + } + dialog.setOnDismissListener { + Util_System_Keyboard.hideSoftKeyboard(activity) + this.view?.visibility = View.VISIBLE + } + dialog.setCancelable(false) + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) + dialog.setContentView(view) + dialog.show() + mBaseHandler.postDelayed({ Util_System_Keyboard.showSoftKeyboard(context, input) }, 300) + } + + private fun addTag(tag: String, isSelect: Boolean) { + if (isSelect && mAllTags.contains(tag)) { // 标签已存在 + if (!mViewModel?.selectedTags?.contains(tag)!!) { // 标签已存在且未选择 + for (i in 0 until mTagFl.childCount) { + val tagView = mTagFl.getChildAt(i) as TextView + val text = tagView.text + if (text != null && text.toString() == tag) { + mViewModel?.selectedTags?.add(tag) + tagView.setBackgroundResource(R.drawable.comment_border_bg) + tagView.setTextColor(ContextCompat.getColor(context!!, R.color.theme)) + } + } + } + toast("标签已存在") + return + } + + val view = LayoutInflater.from(context).inflate(R.layout.questionsdedit_tag_item, null) + val tagTv = view as TextView + tagTv.text = tag + val params = FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) + params.setMargins(0, DisplayUtils.dip2px(context, 5f), DisplayUtils.dip2px(context, 15f), DisplayUtils.dip2px(context, 5f)) + tagTv.layoutParams = params + mTagFl.addView(view, 0) + + tagTv.setOnClickListener({ + if (mViewModel?.selectTag(tagTv.text.toString())!!) { + tagTv.setBackgroundResource(R.drawable.comment_border_bg) + tagTv.setTextColor(ContextCompat.getColor(context!!, R.color.theme)) + } else { + tagTv.setBackgroundResource(R.drawable.border_suggest_bg) + tagTv.setTextColor(ContextCompat.getColor(context!!, R.color.content)) + } + }) + + if (isSelect) { + mViewModel?.selectedTags?.add(tag) + tagTv.setBackgroundResource(R.drawable.comment_border_bg) + tagTv.setTextColor(ContextCompat.getColor(context!!, R.color.theme)) + } + mAllTags.add(tag) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/edit/pic/QuestionsEditPicAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/pic/QuestionsEditPicAdapter.kt new file mode 100644 index 0000000000..cb894e5eed --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/pic/QuestionsEditPicAdapter.kt @@ -0,0 +1,87 @@ +package com.gh.gamecenter.qa.questions.edit.pic + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.provider.MediaStore +import android.support.v7.widget.RecyclerView +import android.view.View +import android.view.ViewGroup +import com.gh.common.util.ClickUtils +import com.gh.common.util.DialogUtils +import com.gh.common.util.ImageUtils +import com.gh.common.util.NetworkUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.SuggestionActivity.MEDIA_STORE_REQUEST +import com.gh.gamecenter.qa.questions.edit.QuestionEditViewModel +import com.gh.gamecenter.suggest.SuggestPicViewHolder +import com.lightgame.adapter.BaseRecyclerAdapter +import com.lightgame.utils.Utils +import java.util.* + +/** + * Created by khy on 5/05/18. + */ +class QuestionsEditPicAdapter(context: Context, viewModel: QuestionEditViewModel) : BaseRecyclerAdapter(context) { + + private val mViewModel: QuestionEditViewModel = viewModel + private var picList: MutableList = ArrayList() + private var mAgreePostPic: Boolean = false + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val view = mLayoutInflater.inflate(R.layout.suggest_pic_item, parent, false) + return SuggestPicViewHolder(view) + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder is SuggestPicViewHolder) { + if (position == itemCount - 1 && picList.size < QuestionEditViewModel.PIC_MAX_AMOUNT) { + holder.delate.visibility = View.GONE + ImageUtils.display(holder.icon, R.drawable.suggest_add_pic_icon) + } else { + holder.icon.setImageURI(picList[position]) + holder.delate.visibility = View.VISIBLE + } + + holder.itemView.setOnClickListener { + if (!ClickUtils.isFastDoubleClick(R.id.menu_question_post) && position == itemCount - 1 + && picList.size < QuestionEditViewModel.PIC_MAX_AMOUNT + && mContext is Activity) { + if (NetworkUtils.isWifiConnected(mContext) || mAgreePostPic) { + addPic(mContext as Activity) + } else { + mAgreePostPic = true + DialogUtils.showAlertDialog(mContext, + "警告", + "当前使用移动网络,上传图片会消耗流量,确定上传吗?", + "继续上传", "取消", + { addPic(mContext as Activity) }, null) + } + } + } + + holder.delate.setOnClickListener { + mViewModel.removePic(picList[position]) + } + } + } + + private fun addPic(activity: Activity) { + try { + val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) + activity.startActivityForResult(intent, MEDIA_STORE_REQUEST) + } catch (e: Exception) { + Utils.toast(mContext, R.string.media_image_hint) + e.printStackTrace() + } + } + + override fun getItemCount(): Int { + return if (picList.size >= QuestionEditViewModel.PIC_MAX_AMOUNT) picList.size else picList.size + 1 + } + + fun notifyPicList(picPath: MutableList) { + picList = ArrayList(picPath) + notifyDataSetChanged() + } +} diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/edit/tip/QuestionTitleTipAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/tip/QuestionTitleTipAdapter.kt new file mode 100644 index 0000000000..d88dae6359 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/qa/questions/edit/tip/QuestionTitleTipAdapter.kt @@ -0,0 +1,129 @@ +package com.gh.gamecenter.qa.questions.edit.tip + +import android.content.Context +import android.databinding.DataBindingUtil +import android.text.Html +import android.text.TextUtils +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.AutoCompleteTextView +import android.widget.BaseAdapter +import android.widget.Filter +import android.widget.Filterable +import com.gh.common.util.DisplayUtils +import com.gh.common.util.UrlFilterUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.QuestionEditTitleSearchItemBinding +import com.gh.gamecenter.qa.entity.QuestionsIndexEntity +import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity +import com.gh.gamecenter.retrofit.Response +import com.gh.gamecenter.retrofit.RetrofitManager +import java.util.* + + +/** + * Created by khy on 3/05/18. + */ +class QuestionTitleTipAdapter(private val context: Context, title: AutoCompleteTextView, communityId: String?) : BaseAdapter(), Filterable { + + var questionList: MutableList = ArrayList() + var mTitleView = title + var mCommunityId = communityId + var mSearchKey: String? = null + + override fun getView(pos: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val binding: QuestionEditTitleSearchItemBinding + if (convertView == null) { + binding = DataBindingUtil.bind(LayoutInflater.from(context).inflate(R.layout.question_edit_title_search_item, convertView, false))!! + view = binding.root + view.tag = binding + } else { + view = convertView + binding = view.tag as QuestionEditTitleSearchItemBinding + } + val entity = questionList[pos] + binding.entity = entity + binding.questionsEditIndexTitle.text = Html.fromHtml(replayKeyword(entity.title)) + view.setOnClickListener({ + val tracers = "(问题编辑)+(标题自动搜索)" + context.startActivity(QuestionsDetailActivity.getIntent(context, entity.id, tracers)) + }) + return view + + } + + private fun replayKeyword(title: String): String { + var translationKey = escapeExprSpecialWord(mSearchKey) + return if (TextUtils.isEmpty(translationKey)) title else title.replace(translationKey?.toRegex()!!, getHtmlKeyword()) + } + + // 特殊符合转译 + private fun escapeExprSpecialWord(s: String?): String? { + var keyword = s + if (!keyword.isNullOrEmpty()) { + val fbsArr = arrayOf("\\", "$", "(", ")", "*", "+", ".", "[", "]", "?", "^", "{", "}", "|") + for (key in fbsArr) { + if (keyword!!.contains(key)) { + keyword = keyword.replace(key, "\\" + key) + } + } + } + return keyword + } + + private fun getHtmlKeyword(): String { + return "$mSearchKey" + } + + override fun getItem(pos: Int): Any { + return questionList[pos] + } + + override fun getItemId(pos: Int): Long { + return pos.toLong() + } + + override fun getCount(): Int { + return questionList.size + } + + override fun getFilter(): Filter { + return QuestionTitleFilter() + } + + inner class QuestionTitleFilter : Filter() { + + override fun performFiltering(prefix: CharSequence?): FilterResults { + val results = FilterResults() + if (prefix.isNullOrBlank()) return results + RetrofitManager + .getInstance(context).api + .getAskSearchByTitle(mCommunityId, UrlFilterUtils.getFilterQuery("keyword", prefix.toString()), 1) + .subscribe(object : Response>() { + override fun onResponse(response: List?) { + results.values = response + results.count = response!!.size + mSearchKey = prefix.toString() + } + }) + return results + } + + override fun publishResults(constant: CharSequence?, results: FilterResults?) { + if (results != null && results.count > 0) { + questionList = results.values as ArrayList + } else { + questionList.clear() + } + if (questionList.size > 2) { + mTitleView.dropDownHeight = DisplayUtils.dip2px(context, 200F) + } else { + mTitleView.dropDownHeight = ViewGroup.LayoutParams.WRAP_CONTENT + } + notifyDataSetChanged() + } + + } +} diff --git a/app/src/main/java/com/gh/gamecenter/qa/recommends/AskQuestionsRecommendsFragment.java b/app/src/main/java/com/gh/gamecenter/qa/recommends/AskQuestionsRecommendsFragment.java index 63a84bd1ac..cb7a59b9d7 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/recommends/AskQuestionsRecommendsFragment.java +++ b/app/src/main/java/com/gh/gamecenter/qa/recommends/AskQuestionsRecommendsFragment.java @@ -22,7 +22,7 @@ import com.gh.gamecenter.baselist.LoadType; import com.gh.gamecenter.eventbus.EBReuse; import com.gh.gamecenter.fragment.MainWrapperFragment; import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity; -import com.gh.gamecenter.qa.ask.QuestionEditActivity; +import com.gh.gamecenter.qa.questions.edit.QuestionEditActivity; import com.gh.gamecenter.qa.entity.AnswerEntity; import com.gh.gamecenter.qa.entity.Questions; import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity; diff --git a/app/src/main/java/com/gh/gamecenter/qa/search/AskSearchActivity.java b/app/src/main/java/com/gh/gamecenter/qa/search/AskSearchActivity.java index 546bff8140..71cb249c03 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/search/AskSearchActivity.java +++ b/app/src/main/java/com/gh/gamecenter/qa/search/AskSearchActivity.java @@ -16,7 +16,7 @@ import android.widget.TextView; import com.gh.base.BaseActivity; import com.gh.common.util.CheckLoginUtils; import com.gh.gamecenter.R; -import com.gh.gamecenter.qa.ask.QuestionEditActivity; +import com.gh.gamecenter.qa.questions.edit.QuestionEditActivity; import com.lightgame.utils.Util_System_Keyboard; import butterknife.BindView; diff --git a/app/src/main/java/com/gh/gamecenter/qa/search/AskSearchFragment.java b/app/src/main/java/com/gh/gamecenter/qa/search/AskSearchFragment.java index 09e007767f..856408e755 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/search/AskSearchFragment.java +++ b/app/src/main/java/com/gh/gamecenter/qa/search/AskSearchFragment.java @@ -19,7 +19,7 @@ import com.gh.gamecenter.baselist.LoadType; import com.gh.gamecenter.baselist.NormalListViewModel; import com.gh.gamecenter.manager.UserManager; import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity; -import com.gh.gamecenter.qa.ask.QuestionEditActivity; +import com.gh.gamecenter.qa.questions.edit.QuestionEditActivity; import com.gh.gamecenter.qa.entity.AskSearchEntity; import com.gh.gamecenter.qa.entity.Questions; import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity; diff --git a/app/src/main/res/layout/activity_questions_edit.xml b/app/src/main/res/layout/activity_questions_edit.xml index 6fac143c31..0833114285 100644 --- a/app/src/main/res/layout/activity_questions_edit.xml +++ b/app/src/main/res/layout/activity_questions_edit.xml @@ -5,7 +5,7 @@ + type = "com.gh.gamecenter.qa.questions.edit.QuestionEditViewModel" />