添加搜索页

This commit is contained in:
wangyu 2025-12-30 18:42:34 +08:00
parent 88e72def3c
commit e22a134687
87 changed files with 2995 additions and 131 deletions

View File

@ -64,7 +64,7 @@
android:resizeableActivity="true" android:resizeableActivity="true"
android:roundIcon="@mipmap/ic_launcher_icon" android:roundIcon="@mipmap/ic_launcher_icon"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.Material" android:theme="@style/Theme.Base"
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
tools:replace="android:allowBackup,android:supportsRtl"> tools:replace="android:allowBackup,android:supportsRtl">

View File

@ -2,11 +2,11 @@ package com.cheng.bole.bean
import java.io.Serializable import java.io.Serializable
class CityBean( class AreaBean(
val id: Int = 0, val id: Int = 0,
val pid: Int = 0, val pid: Int = 0,
val name: String = "", val name: String = "",
val amount: String = "", val amount: String = "",
var children: MutableList<CityBean> = mutableListOf(), var children: MutableList<AreaBean> = mutableListOf(),
var isChecked: Boolean = false var isChecked: Boolean = false
) : Serializable ) : Serializable

View File

@ -13,32 +13,4 @@ data class BidItemBean(
val money: String, val money: String,
val tipsTime: String, val tipsTime: String,
val star: String val star: String
) { )
fun getShortName(): String {
return when (typeName) {
"招标计划" -> "招标"
"采购公告" -> "采购"
"招标公告" -> "预告"
"合同公告" -> "合同"
"中标公告" -> "中标"
"竞争性磋商" -> "竞争性磋商"
"更正公告" -> "更正"
"终止公告" -> "终止"
else -> "其他"
}
}
fun getTypeColor(): Int {
return when (typeName) {
"招标计划" -> Color.parseColor("#2B88F9")
"采购公告" -> Color.parseColor("#FF7344")
"招标公告" -> Color.parseColor("#14CEB3")
"合同公告" -> Color.parseColor("#FFA91D")
"中标公告" -> Color.parseColor("#FF1B1B")
"竞争性磋商" -> Color.parseColor("#0DA9FF")
"更正公告" -> Color.parseColor("#7066FF")
"终止公告" -> Color.parseColor("#8C9199")
else -> Color.parseColor("#EEEEEE")
}
}
}

View File

@ -0,0 +1,70 @@
package com.cheng.bole.bean
import com.cheng.bole.manager.UserConfigManager
import java.io.Serializable
class SearchOptionBean(
val title: String,
val items: List<OptionItem>,
var isChecked: Boolean = false
) : Serializable {
class OptionItem(
val id: Int = 0,
val name: String = "",
var isChecked: Boolean = false,
var startTime: String = "",
var endTime: String = ""
) : Serializable
companion object {
fun getAreaOptionList(): List<SearchOptionBean> {
val areaList = UserConfigManager.getAreaList()
val list = mutableListOf<SearchOptionBean>()
list.add(SearchOptionBean("全国地区", listOf(
OptionItem(0, "全国", true)
)))
areaList.forEach { area ->
val cityList = mutableListOf<OptionItem>()
cityList.add(OptionItem(0, "全部"))
area.children.forEach { city ->
cityList.add(OptionItem(city.id, city.name))
}
list.add(SearchOptionBean(area.name, cityList))
}
return list
}
fun getTimeOptionList(): List<SearchOptionBean> {
val list = mutableListOf<SearchOptionBean>()
list.add(SearchOptionBean("时间排序", listOf(
OptionItem(0, "全部时间", true),
OptionItem(1, "近三天"),
OptionItem(2, "近七天"),
OptionItem(3, "近一个月"),
OptionItem(4, "近三个月"),
OptionItem(5, "近一年")
)))
return list
}
fun getSortOptionList(): List<SearchOptionBean> {
val list = mutableListOf<SearchOptionBean>()
list.add(SearchOptionBean("排序方式", listOf(
OptionItem(0, "综合排序", true),
OptionItem(1, "时间排序")
)))
return list
}
fun getTypeOptionList(): List<SearchOptionBean> {
val list = mutableListOf<SearchOptionBean>()
val typeList = mutableListOf<OptionItem>()
UserConfigManager.getBidTypes().forEach {
typeList.add(OptionItem(it.id.toInt(), it.name))
}
list.add(SearchOptionBean("信息类型", typeList))
return list
}
}
}

View File

@ -3,8 +3,8 @@ package com.cheng.bole.bean
import java.io.Serializable import java.io.Serializable
data class WxShareEntity( data class WxShareEntity(
val content: String = "", var content: String = "",
val image: String = "", var image: String = "",
val link: String = "", var link: String = "",
val title: String = "" var title: String = ""
) : Serializable ) : Serializable

View File

@ -27,9 +27,8 @@ object Constants {
const val Encrypt = "zpzkfp72v3hgatzg5w7pyg86x5342kxt" const val Encrypt = "zpzkfp72v3hgatzg5w7pyg86x5342kxt"
const val Signature = "ckBHUSWBx3TqwNT2kxMrsXyXFuA3PW" const val Signature = "ckBHUSWBx3TqwNT2kxMrsXyXFuA3PW"
val almmsht = Typeface.createFromAsset(Utils.getApp().assets, "fonts/Alimama ShuHeiTi.ttf") val almmsht = Typeface.createFromAsset(Utils.getApp().assets, "fonts/AlimamaShuHeiTi.ttf")
val dDIN_PRO_M = Typeface.createFromAsset(Utils.getApp().assets, "fonts/D-DIN-PRO-500-Medium.otf") val dDIN_PRO_M = Typeface.createFromAsset(Utils.getApp().assets, "fonts/D-DIN-PRO-500-Medium.otf")
val youSheBiaoTiHei = Typeface.createFromAsset(Utils.getApp().assets, "fonts/YouSheBiaoTiHei.ttf")
val douyinsansB = Typeface.createFromAsset(Utils.getApp().assets, "fonts/DouyinSansBold.otf") val douyinsansB = Typeface.createFromAsset(Utils.getApp().assets, "fonts/DouyinSansBold.otf")
val pmzdbt = Typeface.createFromAsset(Utils.getApp().assets, "fonts/PangMenZhengDaoBiaoTiTi.ttf") val pmzdbt = Typeface.createFromAsset(Utils.getApp().assets, "fonts/PangMenZhengDaoBiaoTiTi.ttf")
} }

View File

@ -29,56 +29,19 @@ object EventConstants {
const val ERROR_CLIENT_ALIPAY_ERR = "client.alipay.err" //支付宝支付失败 const val ERROR_CLIENT_ALIPAY_ERR = "client.alipay.err" //支付宝支付失败
const val ERROR_CLIENT_DOWNLOAD_IMG = "client.download.img.err" //图片下载失败
const val ERROR_CLIENT_DOWNLOAD_VIDEO = "client.download.video.err" //视频下载失败
const val ERROR_CLIENT_DOWNLOAD_AUDIO = "client.download.audio.err" //音频下载失败
const val CANCEL_DOWNLOAD_VIDEO = "client.download.video.cancel" //取消视频下载
const val PAUSE_DOWNLOAD_VIDEO = "client.download.video.pause" //暂停视频下载
const val CONTINUE_DOWNLOAD_VIDEO = "client.download.video.continue" //继续视频下载
const val RESTART_DOWNLOAD_VIDEO = "client.download.video.restart" //重新视频下载
const val SPEED_UP_DOWNLOAD_VIDEO = "client.download.video.speed.up" //加速视频下载
const val BACKGROUND_CLIENT_DOWNLOAD = "client.download.background" //后台下载
const val FLOAT_WINDOW_CLICK = "client.float.window.click" //点击悬浮窗
const val SAVE_AI_MEDIA = "client.ai.media.save" //ai生成文件保存
const val RECOGNIZE_AUDIO_TO_TEXT = "client.audio.text.recognize" //音频转文字
const val PKG_UPDATE = "client.pkg.update" //升级弹窗点击更新 const val PKG_UPDATE = "client.pkg.update" //升级弹窗点击更新
const val PKG_CANCEL = "client.pkg.cancel" //升级弹窗点击取消 const val PKG_CANCEL = "client.pkg.cancel" //升级弹窗点击取消
const val GET_MATERIAL = "client.get.material" //获取素材 const val JUMP_TO_BID_DETAIL = "client.jump.to.bid.detail" //跳转到标讯详情页
const val GET_MATERIAL_CANCEL = "client.get.material.cancel" //取消获取素材 const val JUMP_TO_BID_SEARCH = "client.jump.to.bid.search" //跳转到搜索
const val DIALOG_CONFIRM_SAVE_FILE = "client.dialog.confirm.save.file" //保存文件地址弹框确认
const val DIALOG_GO_TO_VIEW = "client.dialog.go.to.view" //前往保存文件的地址查看 const val DIALOG_GO_TO_VIEW = "client.dialog.go.to.view" //前往保存文件的地址查看
const val JUMP_TO_ABOUT_US = "client.jump.to.about.us" //界面跳转 const val JUMP_TO_ABOUT_US = "client.jump.to.about.us" //界面跳转
const val JUMP_TO_LINK_EXTRACT = "client.jump.to.link.extract" //跳转链接提取
const val JUMP_TO_WECHAT_VIDEO = "client.jump.to.wechat.video" //跳转视频号
const val JUMP_TO_WECHAT_PLAYBACK = "client.jump.to.wechat.video.playback" //跳转直播回放
const val JUMP_TO_COURSE_WX_VIDEO = "client.course.wechat.video" //视频号视频教程
const val JUMP_TO_COURSE_PLAYBACK = "client.course.playback" //直播回放视频教程
const val JUMP_TO_TOOL = "client.jump.to.home.tool" //跳转工具
const val MAIN_CENTER_ENABLE = "client.main.center.enable" //首页跳转个人中心 const val MAIN_CENTER_ENABLE = "client.main.center.enable" //首页跳转个人中心
const val JUMP_TO_MEMBER_RECHARGE = "client.jump.to.member.recharge" //跳转到充值页 const val JUMP_TO_MEMBER_RECHARGE = "client.jump.to.member.recharge" //跳转到充值页
@ -95,21 +58,13 @@ object EventConstants {
const val JUMP_TO_ACCOUNT_MANAGE = "client.jump.to.account.manage" //跳转到账号管理 const val JUMP_TO_ACCOUNT_MANAGE = "client.jump.to.account.manage" //跳转到账号管理
const val JUMP_TO_DOWNLOAD_HISTORY = "client.jump.to.download.history" //跳转到下载记录
const val JUMP_TO_DOWNLOAD_TASK_LIST = "client.jump.to.download.task.list" //跳转到下载任务列表
const val JUMP_TO_RECHARGE_DIAMOND = "client.jump.to.recharge.diamond" //跳转到M币充值 const val JUMP_TO_RECHARGE_DIAMOND = "client.jump.to.recharge.diamond" //跳转到M币充值
const val JUMP_TO_COUPON_LIST = "client.jump.to.coupon.list" //跳转优惠券列表 const val JUMP_TO_COUPON_LIST = "client.jump.to.coupon.list" //跳转优惠券列表
const val JUMP_TO_CHALLENGE_TASK = "client.jump.to.challenge.task" //跳转到0元挑战 const val JUMP_TO_CHALLENGE_TASK = "client.jump.to.challenge.task" //跳转到0元挑战
const val JUMP_TO_SHARE_WX_VIDEO = "client.jump.to.wechat.share.video" //跳转到视频号分享
const val JUMP_TO_SHARE_WX_PLAYBACK = "client.jump.to.wechat.share.playback" //跳转到直播回放分享
const val JUMP_TO_COURSE = "client.jump.to.course" //跳转到指导教程
const val DOWNLOAD_FILE = "client.download.file" //下载文件 const val DOWNLOAD_FILE = "client.download.file" //下载文件

View File

@ -0,0 +1,4 @@
package com.cheng.bole.event
class FavoriteEvent {
}

View File

@ -10,7 +10,7 @@ import okhttp3.RequestBody.Companion.toRequestBody
object EventReportManager { object EventReportManager {
fun eventReport(key: String?, value: String?, extra: String) { fun eventReport(key: String?, value: String? = "", extra: String = "") {
GlobalScope.launch { GlobalScope.launch {
try { try {
val jsonObject = JSONObject() val jsonObject = JSONObject()

View File

@ -0,0 +1,44 @@
package com.cheng.bole.manager
import android.text.TextUtils
import com.example.base.utils.MMKVUtils
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
/**
* 搜索历史
*/
object SearchHistoryManager {
fun addHistory(keyword: String): List<String> {
val list = getHistory()
if (!list.contains(keyword)) {
if (list.size == 20) list.removeLast()
list.add(0, keyword)
MMKVUtils.put("search_history", Gson().toJson(list))
}
return list
}
fun updateHistory(keyword: String): List<String> {
val list = getHistory()
if (list.contains(keyword)) {
list.remove(keyword)
}
list.add(0, keyword)
MMKVUtils.put("search_history", Gson().toJson(list))
return list
}
fun getHistory(): MutableList<String> {
val str = MMKVUtils.getString("search_history")
if (!TextUtils.isEmpty(str)) {
return Gson().fromJson(str, object : TypeToken<MutableList<String>>() {}.type)
}
return mutableListOf()
}
fun clear() {
MMKVUtils.removeKey("search_history")
}
}

View File

@ -3,6 +3,8 @@ package com.cheng.bole.manager
import android.os.Build import android.os.Build
import android.text.TextUtils import android.text.TextUtils
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.cheng.bole.bean.BidTypeBean
import com.cheng.bole.bean.AreaBean
import com.cheng.bole.net.ApiFactory import com.cheng.bole.net.ApiFactory
import com.example.base.extensions.toast import com.example.base.extensions.toast
import com.example.base.utils.MMKVUtils import com.example.base.utils.MMKVUtils
@ -210,6 +212,60 @@ object UserConfigManager {
return emptyList() return emptyList()
} }
/**
* 搜索排序
*/
private fun saveSearchSort(sort: String) {
MMKVUtils.put("search_sort", sort)
}
fun getSearchSort(): String {
return MMKVUtils.getString("search_sort") ?: ""
}
/**
* 地区列表
*/
fun saveAreaList(list: List<AreaBean>) {
if (list.isNotEmpty()) {
MMKVUtils.put("area_list", Gson().toJson(list))
}
}
fun getAreaList(): MutableList<AreaBean> {
val str = MMKVUtils.getString("area_list")
if (!TextUtils.isEmpty(str)) {
return Gson().fromJson(str, object : TypeToken<MutableList<AreaBean>>() {}.type)
}
return mutableListOf()
}
/**
* 城市列表
*/
fun getCityList(): List<AreaBean> {
val list = mutableListOf<AreaBean>()
getAreaList().forEach {
list.addAll(it.children)
}
return list
}
/**
* 招标类型
*/
fun saveBidTypes(list: List<BidTypeBean>) {
MMKVUtils.put("bid_type", Gson().toJson(list))
}
fun getBidTypes(): List<BidTypeBean> {
val str = MMKVUtils.getString("bid_type")
if (!TextUtils.isEmpty(str)) {
return Gson().fromJson(str, object : TypeToken<List<BidTypeBean>>() {}.type)
}
return emptyList()
}
/** /**
* 保存个推cid * 保存个推cid
*/ */

View File

@ -3,7 +3,7 @@ package com.cheng.bole.net
import com.cheng.bole.bean.BidDetailBean import com.cheng.bole.bean.BidDetailBean
import com.cheng.bole.bean.BidItemBean import com.cheng.bole.bean.BidItemBean
import com.cheng.bole.bean.BidTypeBean import com.cheng.bole.bean.BidTypeBean
import com.cheng.bole.bean.CityBean import com.cheng.bole.bean.AreaBean
import com.cheng.bole.bean.CompanyBean import com.cheng.bole.bean.CompanyBean
import com.cheng.bole.bean.CorpInfoBean import com.cheng.bole.bean.CorpInfoBean
import com.cheng.bole.bean.GuideTotalBidInfoBean import com.cheng.bole.bean.GuideTotalBidInfoBean
@ -182,13 +182,13 @@ interface ApiService {
* 城市列表 * 城市列表
*/ */
@GET("/api/city") @GET("/api/city")
suspend fun getCityList(): HttpBaseResult<List<CityBean>> suspend fun getAreaList(): HttpBaseResult<List<AreaBean>>
/** /**
* 获取当前城市 * 获取当前城市
*/ */
@GET("/api/city/default") @GET("/api/city/default")
suspend fun getUserCity(): HttpBaseResult<CityBean> suspend fun getUserCity(): HttpBaseResult<AreaBean>
/** /**
* 总计商机 * 总计商机

View File

@ -50,7 +50,7 @@ class AccountListDialog : DialogFragment() {
binding = DialogAccountListBinding.bind(view) binding = DialogAccountListBinding.bind(view)
binding.tvTitle.typeface = Constants.youSheBiaoTiHei binding.tvTitle.typeface = Constants.douyinsansB
binding.mRecyclerView.adapter = mAdapter binding.mRecyclerView.adapter = mAdapter
binding.mRecyclerView.addItemDecoration(SpacesItemDecoration(DensityUtils.dp2px(10f))) binding.mRecyclerView.addItemDecoration(SpacesItemDecoration(DensityUtils.dp2px(10f)))

View File

@ -0,0 +1,104 @@
package com.cheng.bole.ui.dialog
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.cheng.bole.R
import com.cheng.bole.databinding.DialogDatePickerBinding
import com.example.base.extensions.onClick
import com.example.base.utils.ScreenUtils
import com.github.gzuliyujiang.wheelpicker.annotation.DateMode
import com.github.gzuliyujiang.wheelpicker.entity.DateEntity
import java.util.Calendar
import java.util.Date
class DatePickerDialog : DialogFragment() {
private val title by lazy {arguments?.getString("title")}
private val time by lazy { arguments?.getLong("time") ?: System.currentTimeMillis() }
private val startTime by lazy { arguments?.getLong("start_time") ?: 0 }
private val endTime by lazy { arguments?.getLong("end_time") ?: System.currentTimeMillis() }
private val dateMode by lazy { arguments?.getInt("date_mode") ?: DateMode.YEAR_MONTH_DAY }
private var selectedTime: Calendar = Calendar.getInstance()
private var mOnBackListener: ((Long) -> Unit)? = null //回调事件
lateinit var binding: DialogDatePickerBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = ScreenUtils.getWindowSize().x
windowParams?.gravity = Gravity.BOTTOM
windowParams?.windowAnimations = R.style.dialog_bottom
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_date_picker, null)
binding = DialogDatePickerBinding.bind(view)
binding.tvTitle.text = title
selectedTime.timeInMillis = time
binding.datePicker.setRange(DateEntity.target(Date(startTime)), if (endTime != 0L) DateEntity.target(Date(endTime)) else null, DateEntity.target(Date(time)))
binding.datePicker.setDateMode(dateMode)
binding.datePicker.setOnDateSelectedListener { year, month, day ->
selectedTime.set(Calendar.YEAR, year)
selectedTime.set(Calendar.MONTH, month - 1)
selectedTime.set(Calendar.DAY_OF_MONTH, day)
}
binding.tvConfirm.onClick {
mOnBackListener?.invoke(selectedTime.timeInMillis)
dismiss()
}
binding.tvCancel.onClick {
dismiss()
}
val dialog = Dialog(requireContext())
dialog.setContentView(view)
return dialog
}
fun setOnSelectListener(listener: ((Long) -> Unit)) {
mOnBackListener = listener
}
companion object {
fun newInstance(
title: String? = "",
time: Long = System.currentTimeMillis(),
startTime: Long = 0,
endTime: Long = System.currentTimeMillis(),
dateMode: Int = DateMode.YEAR_MONTH_DAY
): DatePickerDialog {
val arg = Bundle()
val fragment = DatePickerDialog()
arg.putString("title", title)
arg.putLong("time", time)
arg.putLong("start_time", startTime)
arg.putLong("end_time", endTime)
arg.putInt("date_mode", dateMode)
fragment.arguments = arg
return fragment
}
}
}

View File

@ -0,0 +1,144 @@
package com.cheng.bole.ui.dialog
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.os.Environment
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.cheng.bole.R
import com.cheng.bole.bean.AttachmentBean
import com.cheng.bole.common.Constants
import com.cheng.bole.databinding.DialogDownloadAttachmentBinding
import com.cheng.bole.manager.DialogEnum
import com.cheng.bole.manager.ShareManager
import com.cheng.bole.utils.DownLoadUtils
import com.example.base.dialog.LoadingDialog
import com.example.base.extensions.longToast
import com.example.base.extensions.onClick
import com.example.base.extensions.toast
import com.example.base.utils.DensityUtils
import com.example.base.utils.ScreenUtils
import com.example.base.utils.SpanUtils
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class DownloadAttachmentDialog : DialogFragment() {
private val mAdapter by lazy { AttachmentAdapter() }
private val attachmentList = mutableListOf<AttachmentBean>()
private val loadingDialog by lazy { LoadingDialog(requireContext()) }
private var mOnBackListener: ((DialogEnum) -> Unit)? = null //回调事件
lateinit var binding: DialogDownloadAttachmentBinding
override fun onStart() {
super.onStart()
val window = dialog?.window
val windowParams = window?.attributes
windowParams?.dimAmount = 0.7f
windowParams?.width = (ScreenUtils.getWindowSize().x * 0.8).toInt()
dialog?.window?.attributes = windowParams
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_download_attachment, null)
binding = DialogDownloadAttachmentBinding.bind(view)
binding.tvTitle.typeface = Constants.douyinsansB
val listStr = arguments?.getString("list")
if (!TextUtils.isEmpty(listStr)) {
attachmentList.addAll(Gson().fromJson(listStr, object : TypeToken<List<AttachmentBean>>() {}.type))
}
binding.rvAttachment.adapter = mAdapter
mAdapter.setList(attachmentList)
mAdapter.setOnItemChildClickListener { _, v, i ->
when (v.id) {
R.id.btn_download -> {
download(mAdapter.getItem(i))
}
}
}
binding.ivClose.onClick {
dismiss()
}
val dialog = Dialog(requireContext())
dialog.setContentView(view)
return dialog
}
private fun download(bean: AttachmentBean) {
loadingDialog.show()
lifecycleScope.launch(Dispatchers.IO) {
DownLoadUtils.getInstance()
.setReadTimeOut(10L)
.setDeleteWhenException(false)
.initUrl(bean.url, null)
.addHeader(mapOf(Pair("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:139.0) Gecko/20100101 Firefox/139.0")))
.setFilePath(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath)
.setFileName("${bean.title}.${bean.type}")
.setActionCallBack(
actionSuccess = {
ShareManager.shareFile(requireActivity(), it)
longToast("已下载到文件管理/内部储存/下载/${it.name}")
loadingDialog.dismiss()
},
actionFail = {
loadingDialog.dismiss()
toast("下载失败")
}
).down()
}
}
fun setOnSelectListener(listener: ((DialogEnum) -> Unit)) {
mOnBackListener = listener
}
companion object {
fun newInstance(list: List<AttachmentBean>): DownloadAttachmentDialog {
val arg = Bundle()
arg.putString("list", Gson().toJson(list))
val fragment = DownloadAttachmentDialog()
fragment.arguments = arg
return fragment
}
}
inner class AttachmentAdapter : BaseQuickAdapter<AttachmentBean, BaseViewHolder>(R.layout.listitem_bid_attachment) {
init {
addChildClickViewIds(R.id.btn_download)
}
override fun convert(holder: BaseViewHolder, item: AttachmentBean) {
SpanUtils.with(holder.getView(R.id.tv_name))
.appendImage(R.mipmap.ic_pdf_attachment)
.appendSpace(DensityUtils.dp2px(8f))
.append(item.title)
.create()
}
}
}

View File

@ -1,5 +1,6 @@
package com.cheng.bole.ui.dialog package com.cheng.bole.ui.dialog
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
@ -7,12 +8,27 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.PopupWindow import android.widget.PopupWindow
import com.example.base.extensions.onClick import androidx.fragment.app.FragmentManager
import com.cheng.bole.R import com.cheng.bole.R
import com.cheng.bole.bean.SearchOptionBean
import com.cheng.bole.databinding.PopAboutTipBinding import com.cheng.bole.databinding.PopAboutTipBinding
import com.cheng.bole.databinding.PopupSearchOptionsBinding
import com.cheng.bole.ui.activity.PublicActivity import com.cheng.bole.ui.activity.PublicActivity
import com.cheng.bole.ui.fragment.guide.GuideFragment import com.cheng.bole.ui.fragment.guide.GuideFragment
import com.cheng.bole.ui.fragment.mine.about.AppConfigFragment import com.cheng.bole.ui.fragment.mine.about.AppConfigFragment
import com.cheng.bole.ui.fragment.search.list.SearchOptionChildAdapter
import com.cheng.bole.ui.fragment.search.list.SearchOptionParentAdapter
import com.cheng.bole.utils.DateUtils
import com.efs.sdk.memleaksdk.monitor.internal.bi
import com.example.base.decoration.DividerItemDecoration
import com.example.base.extensions.getColor
import com.example.base.extensions.getYYYYMMDD
import com.example.base.extensions.gone
import com.example.base.extensions.onClick
import com.example.base.extensions.toast
import com.example.base.extensions.visible
import com.example.base.utils.DensityUtils
import java.util.Calendar
object PopupDialog { object PopupDialog {
@ -39,4 +55,338 @@ object PopupDialog {
val height = context.resources.displayMetrics.heightPixels - y val height = context.resources.displayMetrics.heightPixels - y
popWindow.showAsDropDown(v, 0, 0) popWindow.showAsDropDown(v, 0, 0)
} }
fun showSearchAreaOptions(context: Context, v: View, cityList: List<SearchOptionBean.OptionItem>, onDismiss: () -> Unit, callback: (List<SearchOptionBean.OptionItem>) -> Unit) {
val view = LayoutInflater.from(context).inflate(R.layout.popup_search_options, null, false)
val binding = PopupSearchOptionsBinding.bind(view)
val parentAdapter = SearchOptionParentAdapter()
binding.rvParent.adapter = parentAdapter
val childAdapter = SearchOptionChildAdapter(true)
binding.rvChild.adapter = childAdapter
val optionList = SearchOptionBean.getAreaOptionList()
if (cityList.isNotEmpty()) {
optionList[0].isChecked = false
optionList[0].items[0].isChecked = false
optionList.forEach { option ->
option.items.forEach { item ->
if (cityList.find { it.id == item.id } != null) {
item.isChecked = true
if (optionList.find { it.isChecked } == null) {
option.isChecked = true
}
}
}
val selectedList = option.items.filter { item -> item.id != 0 }
if (selectedList.isNotEmpty() && selectedList.all { item -> item.isChecked }) {
option.isChecked = true
option.items[0].isChecked = true
}
}
} else {
optionList[0].isChecked = true
optionList[0].items[0].isChecked = true
}
parentAdapter.setList(optionList)
childAdapter.setList(optionList.find { it.isChecked }?.items)
parentAdapter.setOnItemClickListener { _, _, i ->
val item = parentAdapter.getItem(i)
parentAdapter.data.find { it.isChecked }?.isChecked = false
item.isChecked = true
parentAdapter.notifyDataSetChanged()
childAdapter.setList(item.items)
}
childAdapter.setOnItemClickListener { _, _, i ->
val item = childAdapter.getItem(i)
item.isChecked = !item.isChecked
if (item.isChecked) {
if (item.id == 0) {
childAdapter.data.forEach { it.isChecked = true }
} else {
if (childAdapter.data.filter { it.id != 0 }.all { it.isChecked }) {
childAdapter.data[0].isChecked = true
}
}
} else {
if (item.id == 0) {
childAdapter.data.forEach { it.isChecked = false }
} else {
if (childAdapter.data[0].isChecked) {
childAdapter.data[0].isChecked = false
}
}
}
if (parentAdapter.data[0].isChecked) {
for (i in 1 until parentAdapter.data.size) {
parentAdapter.getItem(i).items.forEach {
it.isChecked = false
}
}
} else {
if (parentAdapter.data[0].items[0].isChecked) {
parentAdapter.data[0].items[0].isChecked = false
}
}
childAdapter.notifyDataSetChanged()
}
val popWindow = PopupWindow(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true)
popWindow.isClippingEnabled = false
popWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
popWindow.setOnDismissListener {
onDismiss.invoke()
}
binding.btnReset.onClick { parentAdapter.setList(SearchOptionBean.getAreaOptionList()) }
binding.btnNext.onClick {
val list = mutableListOf<SearchOptionBean.OptionItem>()
parentAdapter.data.forEachIndexed { index, option ->
if (index != 0) {
list.addAll(option.items.filter { it.isChecked && it.id != 0 })
}
}
if (!parentAdapter.data[0].items[0].isChecked && list.isEmpty()) {
toast("请选择地区")
return@onClick
}
callback.invoke(list)
popWindow.dismiss()
}
val location = IntArray(2)
v.getLocationOnScreen(location)
popWindow.showAsDropDown(v, 0, 0)
}
@SuppressLint("NotifyDataSetChanged")
fun showSearchTimeOptions(context: Context, v: View, manager: FragmentManager, time: SearchOptionBean.OptionItem?, onDismiss: () -> Unit, callback: (SearchOptionBean.OptionItem) -> Unit) {
val view = LayoutInflater.from(context).inflate(R.layout.popup_search_options, null, false)
val binding = PopupSearchOptionsBinding.bind(view)
binding.rvParent.gone()
binding.layoutCustomTime.visible()
var startTime = 0L
var endTime = 0L
val adapter = SearchOptionChildAdapter(false)
binding.rvChild.adapter = adapter
binding.rvChild.addItemDecoration(DividerItemDecoration(DensityUtils.dp2px(16f), DensityUtils.dp2px(16f), color = getColor(R.color.color_eeeeee)))
val optionList = SearchOptionBean.getTimeOptionList()[0]
if (time != null) {
if (time.id == -1) {
optionList.items[0].isChecked = false
} else {
optionList.items.forEach {
it.isChecked = it.id == time.id
}
}
if (time.id != 0) {
startTime = time.startTime.toLong() * 1000
endTime = time.endTime.toLong() * 1000
binding.tvStartTime.text = startTime.getYYYYMMDD()
binding.tvEndTime.text = endTime.getYYYYMMDD()
}
}
adapter.setList(optionList.items)
val popWindow = PopupWindow(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true)
popWindow.isClippingEnabled = false
popWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
popWindow.setOnDismissListener {
onDismiss.invoke()
}
adapter.setOnItemClickListener { _, _, i ->
val item = adapter.getItem(i)
adapter.data.find { it.isChecked }?.isChecked = false
item.isChecked = true
adapter.notifyDataSetChanged()
if (item.id == 0) {
startTime = 0L
endTime = 0L
binding.tvStartTime.text = ""
binding.tvEndTime.text = ""
} else {
val calendar = Calendar.getInstance()
when(item.id) {
1-> calendar.add(Calendar.DATE, -2)
2-> calendar.add(Calendar.DATE, -6)
3-> calendar.add(Calendar.MONTH, -1)
4-> calendar.add(Calendar.MONTH, -3)
5-> calendar.add(Calendar.YEAR, -1)
}
startTime = DateUtils.getDayStartTime(calendar.timeInMillis) * 1000
endTime = DateUtils.getDayEndTime() * 1000
binding.tvStartTime.text = startTime.getYYYYMMDD()
binding.tvEndTime.text = endTime.getYYYYMMDD()
}
}
binding.tvStartTime.onClick {
val f = DatePickerDialog.newInstance("开始时间")
f.setOnSelectListener {
startTime = DateUtils.getDayStartTime(it) * 1000
if (endTime in 1..<startTime) {
toast("开始时间不能大于结束时间")
} else {
binding.tvStartTime.text = it.getYYYYMMDD()
optionList.items.find { item -> item.isChecked }?.isChecked = false
adapter.notifyDataSetChanged()
}
}
f.show(manager, DatePickerDialog::class.java.simpleName)
}
binding.tvEndTime.onClick {
val f = DatePickerDialog.newInstance("结束时间")
f.setOnSelectListener {
endTime = DateUtils.getDayEndTime(it) * 1000
if (endTime < startTime) {
toast("结束时间不能小于开始时间")
} else {
binding.tvEndTime.text = it.getYYYYMMDD()
optionList.items.find { item -> item.isChecked }?.isChecked = false
adapter.notifyDataSetChanged()
}
}
f.show(manager, DatePickerDialog::class.java.simpleName)
}
binding.btnReset.onClick {
startTime = 0
endTime = 0
binding.tvStartTime.text = ""
binding.tvEndTime.text = ""
adapter.setList(SearchOptionBean.getTimeOptionList()[0].items)
}
binding.btnNext.onClick {
var option = adapter.data.find { it.isChecked }
if (option != null) {
option.startTime = if (option.id == 0) "" else "${startTime / 1000}"
option.endTime = if (option.id == 0) "" else "${endTime / 1000}"
} else {
if (startTime == 0L) {
toast("请选择开始时间")
return@onClick
}
if (endTime == 0L) {
toast("请选择结束时间")
return@onClick
}
option = SearchOptionBean.OptionItem(-1, startTime = "${startTime / 1000}", endTime = "${endTime / 1000}")
}
callback.invoke(option)
popWindow.dismiss()
}
val location = IntArray(2)
v.getLocationOnScreen(location)
popWindow.showAsDropDown(v, 0, 0)
}
fun showSearchSortOptions(context: Context, v: View, sort: SearchOptionBean.OptionItem?, onDismiss: () -> Unit, callback: (SearchOptionBean.OptionItem) -> Unit) {
val view = LayoutInflater.from(context).inflate(R.layout.popup_search_options, null, false)
val binding = PopupSearchOptionsBinding.bind(view)
binding.rvParent.gone()
val adapter = SearchOptionChildAdapter(false)
binding.rvChild.adapter = adapter
binding.rvChild.addItemDecoration(DividerItemDecoration(DensityUtils.dp2px(16f), DensityUtils.dp2px(16f), color = getColor(R.color.color_eeeeee)))
val optionList = SearchOptionBean.getSortOptionList()[0]
if (sort != null) {
optionList.items.forEach {
it.isChecked = it.id == sort.id
}
}
adapter.setList(optionList.items)
val popWindow = PopupWindow(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true)
popWindow.isClippingEnabled = false
popWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
popWindow.setOnDismissListener {
onDismiss.invoke()
}
adapter.setOnItemClickListener { _, _, i ->
val item = adapter.getItem(i)
adapter.data.find { it.isChecked }?.isChecked = false
item.isChecked = true
adapter.notifyDataSetChanged()
}
binding.btnReset.onClick { adapter.setList(SearchOptionBean.getSortOptionList()[0].items) }
binding.btnNext.onClick {
val option = adapter.data.find { it.isChecked }
if (option != null) {
callback.invoke(option)
popWindow.dismiss()
}
}
val location = IntArray(2)
v.getLocationOnScreen(location)
popWindow.showAsDropDown(v, 0, 0)
}
fun showSearchTypeOptions(context: Context, v: View, typeList: List<SearchOptionBean.OptionItem>, onDismiss: () -> Unit, callback: (List<SearchOptionBean.OptionItem>) -> Unit) {
val view = LayoutInflater.from(context).inflate(R.layout.popup_search_options, null, false)
val binding = PopupSearchOptionsBinding.bind(view)
binding.rvParent.gone()
val adapter = SearchOptionChildAdapter(false)
binding.rvChild.adapter = adapter
binding.rvChild.addItemDecoration(DividerItemDecoration(DensityUtils.dp2px(16f), DensityUtils.dp2px(16f), color = getColor(R.color.color_eeeeee)))
val optionList = SearchOptionBean.getTypeOptionList()[0]
if (typeList.isNotEmpty()) {
optionList.items.forEach { item ->
if (typeList.find { it.id == item.id } != null) {
item.isChecked = true
}
}
}
adapter.setList(optionList.items)
val popWindow = PopupWindow(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true)
popWindow.isClippingEnabled = false
popWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
popWindow.setOnDismissListener {
onDismiss.invoke()
}
adapter.setOnItemClickListener { _, _, i ->
val item = adapter.getItem(i)
item.isChecked = !item.isChecked
adapter.notifyDataSetChanged()
}
binding.btnReset.onClick { adapter.setList(SearchOptionBean.getTypeOptionList()[0].items) }
binding.btnNext.onClick {
val list = adapter.data.filter { it.isChecked }
callback.invoke(list)
popWindow.dismiss()
}
val location = IntArray(2)
v.getLocationOnScreen(location)
popWindow.showAsDropDown(v, 0, 0)
}
} }

View File

@ -143,7 +143,7 @@ class UpdateVersionDialog : DialogFragment() {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
var totalProgress = 0L var totalProgress = 0L
DownLoadUtils.getInstance() DownLoadUtils.getInstance()
.setReadTImeOut(10L) .setReadTimeOut(10L)
.setDeleteWhenException(false) .setDeleteWhenException(false)
.initUrl(url, null) .initUrl(url, null)
.setFilePath(com.cheng.bole.utils.FileUtils.getInstance().cacheDownLoderDir.absolutePath) .setFilePath(com.cheng.bole.utils.FileUtils.getInstance().cacheDownLoderDir.absolutePath)

View File

@ -1,10 +1,11 @@
package com.cheng.bole.ui.fragment.home package com.cheng.bole.ui.fragment.bid
import android.text.Html import android.text.Html
import android.text.TextUtils import android.text.TextUtils
import com.chad.library.adapter.base.viewholder.BaseViewHolder import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.cheng.bole.R import com.cheng.bole.R
import com.cheng.bole.bean.BidItemBean import com.cheng.bole.bean.BidItemBean
import com.cheng.bole.utils.BidTypeUtils
import com.cheng.bole.widget.CommonShapeView import com.cheng.bole.widget.CommonShapeView
import com.example.base.ui.list.LoadMoreAdapter import com.example.base.ui.list.LoadMoreAdapter
import java.text.DecimalFormat import java.text.DecimalFormat
@ -13,7 +14,8 @@ class BidAdapter(private val showTipsTime: Boolean = false) : LoadMoreAdapter<Bi
override fun convert(holder: BaseViewHolder, item: BidItemBean) { override fun convert(holder: BaseViewHolder, item: BidItemBean) {
val tvTag = holder.getView<CommonShapeView>(R.id.tv_tag) val tvTag = holder.getView<CommonShapeView>(R.id.tv_tag)
tvTag.setBgColor(item.getTypeColor()) tvTag.setBgColor(BidTypeUtils.getTypeColor(item.typeName))
tvTag.text = BidTypeUtils.getShortName(item.typeName)
holder.setText(R.id.tv_title, Html.fromHtml(item.title, Html.FROM_HTML_MODE_LEGACY)) holder.setText(R.id.tv_title, Html.fromHtml(item.title, Html.FROM_HTML_MODE_LEGACY))
holder.setText(R.id.tv_content, Html.fromHtml(item.content, Html.FROM_HTML_MODE_LEGACY)) holder.setText(R.id.tv_content, Html.fromHtml(item.content, Html.FROM_HTML_MODE_LEGACY))

View File

@ -0,0 +1,202 @@
package com.cheng.bole.ui.fragment.bid.detail
import android.annotation.SuppressLint
import android.content.Intent
import android.net.Uri
import android.text.TextUtils
import android.util.Base64
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import com.cheng.bole.R
import com.cheng.bole.bean.BidDetailBean
import com.cheng.bole.bean.UploadFileBean
import com.cheng.bole.bean.WxShareEntity
import com.cheng.bole.common.Constants
import com.cheng.bole.common.EventConstants
import com.cheng.bole.databinding.FragmentBidDetailBinding
import com.cheng.bole.event.FavoriteEvent
import com.cheng.bole.manager.EventReportManager
import com.cheng.bole.manager.ShareManager
import com.cheng.bole.manager.UserConfigManager
import com.cheng.bole.ui.dialog.DownloadAttachmentDialog
import com.cheng.bole.utils.BidTypeUtils
import com.example.base.browser.BrowserActivity
import com.example.base.common.RxBus
import com.example.base.extensions.getColor
import com.example.base.extensions.gone
import com.example.base.extensions.onClick
import com.example.base.extensions.toast
import com.example.base.extensions.visible
import com.example.base.ui.BaseFragment
import com.example.base.utils.ClipboardUtils
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.tencent.mm.opensdk.openapi.IWXAPI
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.umeng.socialize.bean.SHARE_MEDIA
class BidDetailFragment: BaseFragment<FragmentBidDetailBinding, BidDetailViewModel>() {
private lateinit var api: IWXAPI
private val id by lazy { arguments?.getString("id") ?: "" }
private val infoSource by lazy { arguments?.getString("info_source") ?: "" }
private val contactsAdapter by lazy { ContactsAdapter() }
private val imageAdapter by lazy { BidImageAdapter() }
private var detail: BidDetailBean? = null
private var isFavorite: Boolean = false
override fun initView() {
super.initView()
binding.rvContacts.adapter = contactsAdapter
binding.rvImage.adapter = imageAdapter
initWebView()
}
private fun initWebView() {
val settings = binding.webView.settings
settings.useWideViewPort = true
settings.loadWithOverviewMode = true
binding.webView.isVerticalScrollBarEnabled = false
binding.webView.isHorizontalScrollBarEnabled = false
binding.webView.setWebViewClient(object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
return true
}
})
}
override fun initData() {
super.initData()
api = WXAPIFactory.createWXAPI(requireContext(), Constants.WechatAppId)
mViewModel.getBidDetail(id, infoSource)
mViewModel.sendAuth()
EventReportManager.eventReport(EventConstants.JUMP_TO_BID_DETAIL, "", "{\"id\": $id}")
}
override fun initListener() {
super.initListener()
binding.ivShare.onClick {
if (!api.isWXAppInstalled) {
toast("您没有安装微信客户端,请先下载安装")
return@onClick
}
val shareEntity = WxShareEntity()
shareEntity.title = detail!!.origin_title
shareEntity.link = UserConfigManager.getShareEntity()?.link ?: detail!!.share_url
shareEntity.content = UserConfigManager.getShareEntity()?.content ?: ""
ShareManager.shareUrl(requireActivity(), SHARE_MEDIA.WEIXIN, shareEntity) {}
}
binding.ivDownload.onClick {
if (detail!!.origin_attachment.isNotEmpty()) {
val f = DownloadAttachmentDialog.newInstance(detail!!.origin_attachment)
f.show(childFragmentManager, DownloadAttachmentDialog::class.java.simpleName)
} else {
toast("不可下载")
}
}
binding.ivFavorite.onClick {
if (!isFavorite) {
mViewModel.favorite(detail!!.id, detail!!.info_source)
} else {
mViewModel.favoriteCancel(detail!!.id)
}
}
binding.ivView.onClick {
BrowserActivity.start(requireContext(), "原文", detail!!.origin_url, true)
ClipboardUtils.copyText(detail!!.origin_url)
toast("原文链接已复制")
}
contactsAdapter.setOnItemChildClickListener { _, view, i ->
val item = contactsAdapter.getItem(i)
when(view.id) {
R.id.iv_call -> {
val intent = Intent(Intent.ACTION_DIAL, Uri.parse("tel:${item.phone}"))
startActivity(intent)
}
}
}
}
override fun initObserve() {
super.initObserve()
mViewModel.detailLiveData.observe(this) {
detail = it
setData()
}
mViewModel.favoriteLiveData.observe(this) {
isFavorite = true
setFavoriteStyle()
RxBus.defaultInstance.post(FavoriteEvent())
toast("收藏成功")
}
mViewModel.cancelLiveData.observe(this) {
isFavorite = false
setFavoriteStyle()
RxBus.defaultInstance.post(FavoriteEvent())
toast("取消收藏")
}
}
@SuppressLint("SetJavaScriptEnabled")
private fun setData() {
if (detail != null) {
binding.tvTitle.text = detail!!.origin_title
binding.tvTag.text = BidTypeUtils.getShortName(detail!!.type_name)
binding.tvTag.setBgColor(BidTypeUtils.getTypeColor(detail!!.type_name))
binding.tvAmount.text = detail!!.project_amount
binding.tvTime.text = detail!!.tips_time
contactsAdapter.setList(detail!!.contact)
if (TextUtils.isEmpty(detail!!.content_type) || detail!!.content_type == "1") {
val encodedHtml: String = Base64.encodeToString(detail!!.origin_content.toString().toByteArray(), Base64.NO_PADDING)
binding.webView.loadData(encodedHtml,"text/html","base64")
binding.webView.visible()
binding.rvImage.gone()
} else {
val imageList = Gson().fromJson<List<UploadFileBean>>(Gson().toJson(detail!!.origin_content), object : TypeToken<List<UploadFileBean>>() {}.type)
imageAdapter.setList(imageList)
binding.rvImage.visible()
binding.webView.gone()
}
isFavorite = detail!!.is_fav
setFavoriteStyle()
if (TextUtils.isEmpty(detail?.project_amount)) {
binding.tvAmount.gone()
}
if (detail!!.contact.isEmpty()) {
binding.layoutContacts.gone()
}
if (detail!!.origin_attachment.isEmpty()) {
binding.ivDownload.setImageResource(R.mipmap.ic_bid_download_disable)
}
}
}
private fun setFavoriteStyle() {
if (isFavorite) {
binding.ivFavorite.setImageResource(R.mipmap.ic_bid_favorited)
} else {
binding.ivFavorite.setImageResource(R.mipmap.ic_bid_favorite)
}
}
override fun onDestroyView() {
binding.webView.destroy()
super.onDestroyView()
}
}

View File

@ -0,0 +1,75 @@
package com.cheng.bole.ui.fragment.bid.detail
import androidx.lifecycle.MutableLiveData
import com.cheng.bole.bean.BidDetailBean
import com.cheng.bole.net.ApiFactory
import com.example.base.extensions.toast
import com.example.base.utils.L
import com.example.base.viewmodel.BaseViewModel
import com.google.gson.JsonObject
import okhttp3.RequestBody.Companion.toRequestBody
class BidDetailViewModel: BaseViewModel() {
val detailLiveData = MutableLiveData<BidDetailBean>()
val favoriteLiveData = MutableLiveData<Any>()
val cancelLiveData = MutableLiveData<Any>()
fun getBidDetail(id: String, infoSource: String) {
showDialog()
launchOnUiTryCatch({
val response = ApiFactory.apiService.getBidDetail(id, "recommend", infoSource)
if (response.status) {
detailLiveData.postValue(response.data)
} else toast(response.message, true)
dismissDialog()
}, {
dismissDialog()
setError(it)
L.d(it)
})
}
fun favorite(id: String, infoSource: String) {
showDialog()
launchOnUiTryCatch({
val jsonObject = JsonObject()
jsonObject.addProperty("infoId", id)
jsonObject.addProperty("infoSource",infoSource)
val response = ApiFactory.apiService.favorite(jsonObject.toString().toRequestBody())
if (response.status) {
favoriteLiveData.postValue(Any())
}
dismissDialog()
}, {
dismissDialog()
setError(it)
L.d(it)
})
}
fun favoriteCancel(id: String) {
showDialog()
launchOnUiTryCatch({
val response = ApiFactory.apiService.favoriteCancel(id)
if (response.status) {
cancelLiveData.postValue(Any())
}
dismissDialog()
}, {
dismissDialog()
setError(it)
L.d(it)
})
}
fun sendAuth() {
launchOnUiTryCatch({
val jsonObject = JsonObject()
jsonObject.addProperty("scene", "info")
jsonObject.addProperty("count", 1)
ApiFactory.apiService.sendAuth(jsonObject.toString().toRequestBody())
}, {
L.d(it)
})
}
}

View File

@ -0,0 +1,32 @@
package com.cheng.bole.ui.fragment.bid.detail
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.cheng.bole.R
import com.cheng.bole.bean.UploadFileBean
import com.cheng.bole.utils.BitmapUtils
class BidImageAdapter: BaseQuickAdapter<UploadFileBean, BaseViewHolder>(R.layout.listitem_bid_detail_image) {
override fun convert(holder: BaseViewHolder, item: UploadFileBean) {
Glide.with(context)
.asBitmap()
.load(item.url)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
val scale = recyclerView.width / resource.width
val bitmap = BitmapUtils.resizeBitmap(resource, recyclerView.width, resource.height * scale )
holder.setImageBitmap(R.id.iv_image, bitmap)
}
override fun onLoadCleared(placeholder: Drawable?) {
}
})
}
}

View File

@ -0,0 +1,17 @@
package com.cheng.bole.ui.fragment.bid.detail
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.cheng.bole.R
import com.cheng.bole.bean.ContactsInfoBean
class ContactsAdapter: BaseQuickAdapter<ContactsInfoBean, BaseViewHolder>(R.layout.listitem_bid_detail_contact) {
init {
addChildClickViewIds(R.id.iv_call)
}
override fun convert(holder: BaseViewHolder, item: ContactsInfoBean) {
holder.setText(R.id.tv_name, item.name)
holder.setText(R.id.tv_phone, item.phone)
}
}

View File

@ -2,20 +2,28 @@ package com.cheng.bole.ui.fragment.home
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.recyclerview.widget.RecyclerView.HORIZONTAL import androidx.recyclerview.widget.RecyclerView.HORIZONTAL
import com.chad.library.adapter.base.BaseQuickAdapter import com.cheng.bole.R
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.cheng.bole.bean.BidItemBean import com.cheng.bole.bean.BidItemBean
import com.cheng.bole.bean.MenuEntity import com.cheng.bole.bean.MenuEntity
import com.cheng.bole.common.Constants import com.cheng.bole.common.Constants
import com.cheng.bole.common.EventConstants
import com.cheng.bole.databinding.FragmentHomeBinding import com.cheng.bole.databinding.FragmentHomeBinding
import com.efs.sdk.memleaksdk.monitor.internal.bi import com.cheng.bole.manager.EventReportManager
import com.cheng.bole.manager.SearchHistoryManager
import com.cheng.bole.ui.activity.PublicActivity
import com.cheng.bole.ui.fragment.bid.BidAdapter
import com.cheng.bole.ui.fragment.bid.detail.BidDetailFragment
import com.cheng.bole.ui.fragment.mine.vip.VipFragment
import com.cheng.bole.ui.fragment.search.SearchFragment
import com.cheng.bole.ui.fragment.search.list.SearchListFragment
import com.example.base.decoration.GridSpaceItemDecoration import com.example.base.decoration.GridSpaceItemDecoration
import com.example.base.decoration.SpacesItemDecoration import com.example.base.decoration.SpacesItemDecoration
import com.example.base.extensions.getColor
import com.example.base.extensions.onClick import com.example.base.extensions.onClick
import com.example.base.ui.BaseFragment
import com.example.base.ui.list.ListFragment import com.example.base.ui.list.ListFragment
import com.example.base.utils.DensityUtils import com.example.base.utils.DensityUtils
import com.example.base.utils.L import com.example.base.utils.SpanUtils
import java.text.DecimalFormat
import kotlin.math.abs import kotlin.math.abs
@ -31,6 +39,8 @@ class HomeFragment : ListFragment<FragmentHomeBinding, HomeViewModel, BidItemBea
override fun bindAdapter() = BidAdapter() override fun bindAdapter() = BidAdapter()
private var item: BidItemBean? = null
override fun initView() { override fun initView() {
super.initView() super.initView()
binding.tvTitle.typeface = Constants.pmzdbt binding.tvTitle.typeface = Constants.pmzdbt
@ -54,16 +64,17 @@ class HomeFragment : ListFragment<FragmentHomeBinding, HomeViewModel, BidItemBea
override fun initListener() { override fun initListener() {
super.initListener() super.initListener()
binding.appBarLayout.addOnOffsetChangedListener { _, verticalOffset -> binding.appBarLayout.addOnOffsetChangedListener { appBarLayout, verticalOffset ->
val lp = binding.layoutContent.layoutParams as CoordinatorLayout.LayoutParams val lp = binding.layoutContent.layoutParams as CoordinatorLayout.LayoutParams
if (abs(verticalOffset) >= binding.appBarLayout.height - DensityUtils.dp2px(45f)) { lp.topMargin = (-DensityUtils.dp2px(45f) * (1f - abs(verticalOffset).toFloat() / appBarLayout.totalScrollRange)).toInt()
lp.topMargin = (-DensityUtils.dp2px(25f) * (1f - abs(verticalOffset).toFloat() / (binding.appBarLayout.height - DensityUtils.dp2px(20f)))).toInt()
} else {
lp.topMargin = -DensityUtils.dp2px(65f)
}
binding.layoutContent.layoutParams = lp binding.layoutContent.layoutParams = lp
} }
binding.tvSearch.onClick {
PublicActivity.start(requireContext(), SearchFragment::class.java)
EventReportManager.eventReport(EventConstants.JUMP_TO_BID_SEARCH)
}
binding.ivRefresh.onClick { binding.ivRefresh.onClick {
if (keywordAdapter.data.isNotEmpty()) { if (keywordAdapter.data.isNotEmpty()) {
mViewModel.getHotKeywordList(keywordAdapter.data.last()) mViewModel.getHotKeywordList(keywordAdapter.data.last())
@ -71,6 +82,19 @@ class HomeFragment : ListFragment<FragmentHomeBinding, HomeViewModel, BidItemBea
mViewModel.getHotKeywordList("") mViewModel.getHotKeywordList("")
} }
} }
mAdapter.setOnItemClickListener { _, _, i ->
mAdapter.setOnItemClickListener { _, _, i ->
item = mAdapter.getItem(i)
mViewModel.checkAuth()
}
}
keywordAdapter.setOnItemClickListener { _, _, i ->
val item = keywordAdapter.getItem(i)
PublicActivity.start(requireContext(), SearchListFragment::class.java,Pair("keyword", item))
SearchHistoryManager.addHistory(item)
}
} }
override fun initObserve() { override fun initObserve() {
@ -78,5 +102,27 @@ class HomeFragment : ListFragment<FragmentHomeBinding, HomeViewModel, BidItemBea
mViewModel.recommendLiveData.observe(this) { mViewModel.recommendLiveData.observe(this) {
keywordAdapter.setList(it) keywordAdapter.setList(it)
} }
mViewModel.totalLiveData.observe(this) {
SpanUtils.with(binding.tvUpdateCount)
.append("已更新")
.append(DecimalFormat("0.#").format(it.toInt()/ 10000f))
.setForegroundColor(getColor(R.color.color_ff2222))
.append("万条")
.create()
}
mViewModel.authLiveData.observe(this) {
if (it.auth) {
PublicActivity.start(
requireContext(),
BidDetailFragment::class.java,
Pair("id", item!!.id),
Pair("info_source", item!!.info_source)
)
} else {
PublicActivity.start(requireContext(), VipFragment::class.java, Pair("origin", "view_bid"))
}
}
} }
} }

View File

@ -11,13 +11,18 @@ import com.example.base.utils.L
import com.example.base.viewmodel.ListViewModel import com.example.base.viewmodel.ListViewModel
class HomeViewModel : ListViewModel<BidItemBean>() { class HomeViewModel : ListViewModel<BidItemBean>() {
override suspend fun requestApi(params: ArrayMap<String, String>): Result<List<BidItemBean>> { val totalLiveData = MutableLiveData<String>()
return ApiFactory.apiService.getRecommendList(params).toListResult()
}
val authLiveData = MutableLiveData<UserAuthBean>() val authLiveData = MutableLiveData<UserAuthBean>()
val recommendLiveData = MutableLiveData<List<String>>() val recommendLiveData = MutableLiveData<List<String>>()
override suspend fun requestApi(params: ArrayMap<String, String>): Result<List<BidItemBean>> {
val response = ApiFactory.apiService.getRecommendList(params)
if (response.status) {
totalLiveData.postValue(response.data.total)
}
return response.toListResult()
}
fun getHotKeywordList(query: String) { fun getHotKeywordList(query: String) {
launchOnUiTryCatch({ launchOnUiTryCatch({
val params = mutableMapOf<String, String>() val params = mutableMapOf<String, String>()

View File

@ -99,6 +99,9 @@ class MainFragment : BaseFragment<FragmentMainBinding, MainViewModel>() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
mViewModel.userInfo() mViewModel.userInfo()
if (UserConfigManager.getAreaList().isEmpty()) {
mViewModel.getAreaList()
}
} }
override fun initObserve() { override fun initObserve() {
@ -121,6 +124,11 @@ class MainFragment : BaseFragment<FragmentMainBinding, MainViewModel>() {
} }
} }
} }
mViewModel.areaLiveData.observe(this) {
UserConfigManager.saveAreaList(it)
}
mViewModel.getCouponLiveData.observe(this) { mViewModel.getCouponLiveData.observe(this) {
toast("领取成功") toast("领取成功")
PublicActivity.start(requireContext(), CouponFragment::class.java) PublicActivity.start(requireContext(), CouponFragment::class.java)

View File

@ -1,15 +1,19 @@
package com.cheng.bole.ui.fragment.main package com.cheng.bole.ui.fragment.main
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.cheng.bole.bean.AreaBean
import com.cheng.bole.bean.UserEntity
import com.cheng.bole.net.ApiFactory
import com.example.base.extensions.toast import com.example.base.extensions.toast
import com.example.base.utils.L import com.example.base.utils.L
import com.example.base.viewmodel.BaseViewModel import com.example.base.viewmodel.BaseViewModel
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.cheng.bole.net.ApiFactory
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
class MainViewModel : BaseViewModel() { class MainViewModel : BaseViewModel() {
val userInfoLiveData = MutableLiveData<com.cheng.bole.bean.UserEntity>() val userInfoLiveData = MutableLiveData<UserEntity>()
val areaLiveData = MutableLiveData<List<AreaBean>>()
val getCouponLiveData = MutableLiveData<Int>() val getCouponLiveData = MutableLiveData<Int>()
fun userInfo() { fun userInfo() {
@ -24,6 +28,19 @@ class MainViewModel : BaseViewModel() {
}) })
} }
fun getAreaList() {
launchOnUiTryCatch({
val response = ApiFactory.apiService.getAreaList()
if (response.status) {
areaLiveData.postValue(response.data)
} else toast(response.message, true)
}, {
setError(it)
L.d(it)
})
}
fun getActivityCoupon(ids: String, type: Int) { fun getActivityCoupon(ids: String, type: Int) {
showDialog() showDialog()
launchOnUiTryCatch({ launchOnUiTryCatch({

View File

@ -0,0 +1,11 @@
package com.cheng.bole.ui.fragment.search
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.cheng.bole.R
class HistoryKeywordAdapter: BaseQuickAdapter<String, BaseViewHolder>(R.layout.listitem_search_history) {
override fun convert(holder: BaseViewHolder, item: String) {
holder.setText(R.id.tv_name, item)
}
}

View File

@ -0,0 +1,11 @@
package com.cheng.bole.ui.fragment.search
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.cheng.bole.R
class RecommendKeywordAdapter: BaseQuickAdapter<String, BaseViewHolder>(R.layout.listitem_search_recommend) {
override fun convert(holder: BaseViewHolder, item: String) {
holder.setText(R.id.tv_name, item)
}
}

View File

@ -0,0 +1,165 @@
package com.cheng.bole.ui.fragment.search
import android.annotation.SuppressLint
import android.text.TextUtils
import android.view.View
import android.view.ViewTreeObserver
import android.view.animation.RotateAnimation
import androidx.constraintlayout.widget.ConstraintLayout
import com.cheng.bole.common.Constants
import com.cheng.bole.databinding.FragmentSearchBinding
import com.cheng.bole.impl.TextWatcherImpl
import com.cheng.bole.manager.DialogEnum
import com.cheng.bole.manager.SearchHistoryManager
import com.cheng.bole.ui.activity.PublicActivity
import com.cheng.bole.ui.dialog.TipDialog
import com.cheng.bole.ui.fragment.merchant.MerchantFragment
import com.cheng.bole.ui.fragment.search.list.SearchListFragment
import com.example.base.extensions.gone
import com.example.base.extensions.onClick
import com.example.base.extensions.toast
import com.example.base.extensions.visible
import com.example.base.ui.BaseFragment
import com.google.android.flexbox.FlexDirection
import com.google.android.flexbox.FlexWrap
import com.google.android.flexbox.FlexboxLayoutManager
import com.google.android.flexbox.JustifyContent
class SearchFragment: BaseFragment<FragmentSearchBinding, SearchViewModel>() {
private val type by lazy { arguments?.getInt("type") ?: 0 }
private val historyAdapter by lazy { HistoryKeywordAdapter() }
private val recommendAdapter by lazy { RecommendKeywordAdapter() }
private val textWatcher = object : TextWatcherImpl() {
@SuppressLint("SetTextI18n")
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
binding.ivClearText.visibility = if (TextUtils.isEmpty(s)) View.INVISIBLE else View.VISIBLE
}
}
override fun initView() {
super.initView()
binding.tvTitle.typeface = Constants.pmzdbt
val historyLayoutManager = FlexboxLayoutManager(requireContext())
historyLayoutManager.flexDirection = FlexDirection.ROW
historyLayoutManager.flexWrap = FlexWrap.WRAP
historyLayoutManager.justifyContent = JustifyContent.FLEX_START
binding.rvHistory.layoutManager = historyLayoutManager
binding.rvHistory.adapter = historyAdapter
val recommendLayoutManager = FlexboxLayoutManager(requireContext())
recommendLayoutManager.flexDirection = FlexDirection.ROW
recommendLayoutManager.flexWrap = FlexWrap.WRAP
recommendLayoutManager.justifyContent = JustifyContent.FLEX_START
binding.rvRecommend.layoutManager = recommendLayoutManager
binding.rvRecommend.adapter = recommendAdapter
}
override fun initData() {
super.initData()
mViewModel.getHotKeywordList("")
}
override fun initListener() {
super.initListener()
binding.ivTopBg.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
(binding.tvTitle.layoutParams as ConstraintLayout.LayoutParams).topMargin = (binding.ivTopBg.height * 100f / 300f).toInt()
(binding.layoutSearch.layoutParams as ConstraintLayout.LayoutParams).topMargin = (binding.ivTopBg.height * 200f / 300f).toInt()
binding.ivTopBg.viewTreeObserver.addOnGlobalLayoutListener(this)
}
})
binding.etSearch.addTextChangedListener(textWatcher)
binding.ivClearText.onClick {
binding.etSearch.setText("")
}
binding.btnSearch.onClick {
val keyword = binding.etSearch.text.toString().trim()
if (TextUtils.isEmpty(keyword)) {
toast("请输入搜索关键词")
return@onClick
}
if (type == 0) {
PublicActivity.start(requireContext(), SearchListFragment::class.java, Pair("keyword", keyword))
} else {
PublicActivity.start(requireContext(), MerchantFragment::class.java, Pair("keyword", keyword))
}
historyAdapter.setList(SearchHistoryManager.addHistory(keyword))
binding.layoutHistory.visible()
}
binding.ivClearHistory.onClick {
val f = TipDialog.newInstance("温馨提示", "确定清空搜索历史?")
f.setOnSelectListener {
if (it == DialogEnum.CLICK_OK) {
SearchHistoryManager.clear()
historyAdapter.setList(emptyList())
binding.layoutHistory.gone()
}
}
f.show(childFragmentManager, TipDialog::class.java.simpleName)
}
binding.ivRefreshRecommend.onClick {
startRotate()
mViewModel.getHotKeywordList(if (recommendAdapter.data.isNotEmpty()) recommendAdapter.data.last() else "")
}
historyAdapter.setOnItemClickListener { _, _, i ->
val item = historyAdapter.getItem(i)
if (type == 0) {
PublicActivity.start(requireContext(), SearchListFragment::class.java, Pair("keyword", item))
} else {
PublicActivity.start(requireContext(), MerchantFragment::class.java, Pair("keyword", item))
}
binding.etSearch.setText(item)
historyAdapter.setList(SearchHistoryManager.updateHistory(item))
}
recommendAdapter.setOnItemClickListener { _, _, i ->
val item = recommendAdapter.getItem(i)
if (type == 0) {
PublicActivity.start(requireContext(), SearchListFragment::class.java, Pair("keyword", item))
} else {
PublicActivity.start(requireContext(), MerchantFragment::class.java, Pair("keyword", item))
}
binding.etSearch.setText(item)
historyAdapter.setList(SearchHistoryManager.addHistory(item))
binding.layoutHistory.visible()
}
}
override fun initObserve() {
super.initObserve()
mViewModel.recommendLiveData.observe(this) {
recommendAdapter.setList(it)
}
}
private fun startRotate() {
if (binding.ivRefreshRecommend.animation != null) {
binding.ivRefreshRecommend.animation.cancel()
}
val anim = RotateAnimation(0f, 360f, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f)
anim.duration = 1000
binding.ivRefreshRecommend.startAnimation(anim)
}
override fun onResume() {
super.onResume()
if (SearchHistoryManager.getHistory().isNotEmpty()) {
historyAdapter.setList(SearchHistoryManager.getHistory())
binding.layoutHistory.visible()
}
}
override fun onDestroyView() {
binding.etSearch.removeTextChangedListener(textWatcher)
super.onDestroyView()
}
}

View File

@ -0,0 +1,29 @@
package com.cheng.bole.ui.fragment.search
import androidx.lifecycle.MutableLiveData
import com.cheng.bole.net.ApiFactory
import com.example.base.extensions.toast
import com.example.base.utils.L
import com.example.base.viewmodel.BaseViewModel
class SearchViewModel: BaseViewModel() {
val recommendLiveData = MutableLiveData<List<String>>()
fun getHotKeywordList(query: String) {
showDialog()
launchOnUiTryCatch({
val params = mutableMapOf<String, String>()
params["query"] = query
params["size"] = "12"
val response = ApiFactory.apiService.getHotKeywords(params)
if (response.status) {
recommendLiveData.postValue(response.data)
} else toast(response.message, true)
dismissDialog()
}, {
dismissDialog()
setError(it)
L.d(it)
})
}
}

View File

@ -0,0 +1,206 @@
package com.cheng.bole.ui.fragment.search.list
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.text.TextUtils
import android.view.KeyEvent
import android.view.View
import androidx.core.animation.addListener
import com.cheng.bole.R
import com.cheng.bole.bean.BidItemBean
import com.cheng.bole.bean.SearchOptionBean
import com.cheng.bole.databinding.FragmentSearchListBinding
import com.cheng.bole.impl.TextWatcherImpl
import com.cheng.bole.manager.SearchHistoryManager
import com.cheng.bole.manager.UserConfigManager
import com.cheng.bole.ui.activity.PublicActivity
import com.cheng.bole.ui.dialog.PopupDialog
import com.cheng.bole.ui.fragment.bid.BidAdapter
import com.cheng.bole.ui.fragment.bid.detail.BidDetailFragment
import com.cheng.bole.ui.fragment.mine.vip.VipFragment
import com.cheng.bole.utils.KeyboardUtils
import com.example.base.extensions.getColor
import com.example.base.extensions.gone
import com.example.base.extensions.onClick
import com.example.base.extensions.toast
import com.example.base.extensions.visible
import com.example.base.ui.list.ListFragment
class SearchListFragment : ListFragment<FragmentSearchListBinding, SearchListViewModel, BidItemBean>() {
private val keyword by lazy { arguments?.getString("keyword") ?: "" }
private val typeId by lazy { arguments?.getString("typeId") ?: "" }
private val cityList = mutableListOf<SearchOptionBean.OptionItem>()
private val typeList = mutableListOf<SearchOptionBean.OptionItem>()
private var timeOption: SearchOptionBean.OptionItem? = null
private var sortOption: SearchOptionBean.OptionItem? = null
private var item: BidItemBean? = null
override fun noDataClick() {
}
override fun bindAdapter() = BidAdapter(true)
private val textWatcher = object : TextWatcherImpl() {
@SuppressLint("SetTextI18n")
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
binding.ivClearText.visibility = if (TextUtils.isEmpty(s)) View.INVISIBLE else View.VISIBLE
}
}
override fun initView() {
super.initView()
mEmptyView.setNoDataLogo(R.mipmap.ic_empty_data)
}
override fun initData() {
super.initData()
binding.etSearch.setText(keyword)
mViewModel.params["query"] = keyword
mViewModel.params["sort"] = UserConfigManager.getSearchSort()
if (!TextUtils.isEmpty(typeId)) {
val type = UserConfigManager.getBidTypes().find { it.id == typeId }
if (type != null) {
typeList.add(SearchOptionBean.OptionItem(type.id.toInt(), type.name, true))
mViewModel.params["typeId"] = typeList.map { item -> item.id }.joinToString(",")
}
}
firstLoad()
}
override fun initListener() {
super.initListener()
binding.etSearch.addTextChangedListener(textWatcher)
binding.etSearch.setOnEditorActionListener { _, _, event ->
if (event != null && event.keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN) {
val keyword = binding.etSearch.text.toString().trim()
if (TextUtils.isEmpty(keyword)) {
toast("请输入搜索关键词")
return@setOnEditorActionListener true
}
KeyboardUtils.hideSoftInput(requireActivity())
SearchHistoryManager.addHistory(keyword)
mViewModel.params["query"] = keyword
firstLoad()
return@setOnEditorActionListener true
}
false
}
binding.ivClearText.onClick {
binding.etSearch.setText("")
}
binding.btnArea.onClick {
binding.btnArea.setTextColor(getColor(R.color.color_125ffe))
binding.btnArea.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.mipmap.ic_option_arrow_up, 0)
PopupDialog.showSearchAreaOptions(requireContext(), binding.layoutOptions, cityList, {
binding.viewMask.gone()
binding.btnArea.setTextColor(getColor(R.color.color_1a1a1a))
binding.btnArea.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.mipmap.ic_option_arrow_down, 0)
}, {
cityList.clear()
cityList.addAll(it)
mViewModel.params["cityId"] = it.map { item -> item.id }.joinToString(",")
firstLoad()
})
showMask()
}
binding.btnTime.onClick {
binding.btnTime.setTextColor(getColor(R.color.color_125ffe))
binding.btnTime.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.mipmap.ic_option_arrow_up, 0)
PopupDialog.showSearchTimeOptions(requireContext(), binding.layoutOptions, childFragmentManager, timeOption, {
binding.viewMask.gone()
binding.btnTime.setTextColor(getColor(R.color.color_1a1a1a))
binding.btnTime.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.mipmap.ic_option_arrow_down, 0)
}, {
timeOption = it
mViewModel.params["start_time"] = it.startTime
mViewModel.params["end_time"] = it.endTime
firstLoad()
})
showMask()
}
binding.btnSort.onClick {
binding.btnSort.setTextColor(getColor(R.color.color_125ffe))
binding.btnSort.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.mipmap.ic_option_arrow_up, 0)
PopupDialog.showSearchSortOptions(requireContext(), binding.layoutOptions, sortOption, {
binding.viewMask.gone()
binding.btnSort.setTextColor(getColor(R.color.color_1a1a1a))
binding.btnSort.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.mipmap.ic_option_arrow_down, 0)
}, {
sortOption = it
if (it.id == 0) {
mViewModel.params["sort"] = UserConfigManager.getSearchSort()
} else {
if (UserConfigManager.getSearchSort() == "issue_time DESC") {
mViewModel.params["sort"] = "issue_time ASC"
} else {
mViewModel.params["sort"] = "issue_time DESC"
}
}
firstLoad()
})
showMask()
}
binding.btnType.onClick {
binding.btnType.setTextColor(getColor(R.color.color_125ffe))
binding.btnType.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.mipmap.ic_option_arrow_up, 0)
PopupDialog.showSearchTypeOptions(requireContext(), binding.layoutOptions, typeList, {
binding.viewMask.gone()
binding.btnType.setTextColor(getColor(R.color.color_1a1a1a))
binding.btnType.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.mipmap.ic_option_arrow_down, 0)
}, {
typeList.addAll(it)
mViewModel.params["typeId"] = it.map { item -> item.id }.joinToString(",")
firstLoad()
})
showMask()
}
mAdapter.setOnItemClickListener { _, _, i ->
item = mAdapter.getItem(i)
mViewModel.checkAuth()
}
}
override fun initObserve() {
super.initObserve()
mViewModel.authLiveData.observe(this) {
if (it.auth) {
PublicActivity.start(
requireContext(),
BidDetailFragment::class.java,
Pair("id", item!!.id),
Pair("info_source", item!!.info_source)
)
} else {
PublicActivity.start(requireContext(), VipFragment::class.java, Pair("origin", "view_bid"))
}
}
}
private fun showMask() {
val anim = ObjectAnimator.ofFloat(binding.viewMask, "alpha", 0f, 1f)
anim.duration = 200
anim.addListener(onStart = {
binding.viewMask.visible()
})
anim.startDelay = 100
anim.start()
}
override fun onDestroyView() {
binding.etSearch.removeTextChangedListener(textWatcher)
super.onDestroyView()
}
}

View File

@ -0,0 +1,31 @@
package com.cheng.bole.ui.fragment.search.list
import androidx.collection.ArrayMap
import androidx.lifecycle.MutableLiveData
import com.cheng.bole.bean.BidItemBean
import com.cheng.bole.bean.UserAuthBean
import com.cheng.bole.net.ApiFactory
import com.cheng.bole.net.model.toListResult
import com.example.base.extensions.toast
import com.example.base.utils.L
import com.example.base.viewmodel.ListViewModel
class SearchListViewModel: ListViewModel<BidItemBean>() {
override suspend fun requestApi(params: ArrayMap<String, String>): Result<List<BidItemBean>> {
return ApiFactory.apiService.search(params).toListResult()
}
val authLiveData = MutableLiveData<UserAuthBean>()
fun checkAuth() {
launchOnUiTryCatch({
val response = ApiFactory.apiService.checkAuth()
if (response.status) {
authLiveData.postValue(response.data)
} else toast(response.message, true)
}, {
setError(it)
L.d(it)
})
}
}

View File

@ -0,0 +1,24 @@
package com.cheng.bole.ui.fragment.search.list
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.cheng.bole.R
import com.cheng.bole.bean.SearchOptionBean
import com.example.base.extensions.getColor
import com.example.base.utils.DensityUtils
class SearchOptionChildAdapter(private val hasParent: Boolean) :
BaseQuickAdapter<SearchOptionBean.OptionItem, BaseViewHolder>(R.layout.listitem_search_option_child) {
override fun convert(holder: BaseViewHolder, item: SearchOptionBean.OptionItem) {
holder.setText(R.id.tv_name, item.name)
holder.setTextColor(R.id.tv_name, if (item.isChecked) getColor(R.color.color_125ffe) else getColor(R.color.color_1a1a1a))
holder.setVisible(R.id.iv_check, item.isChecked)
if (hasParent) {
holder.itemView.layoutParams.height = DensityUtils.dp2px(40f)
holder.itemView.setPadding(DensityUtils.dp2px(30f), 0, DensityUtils.dp2px(25f), 0)
} else {
holder.itemView.layoutParams.height = DensityUtils.dp2px(44f)
holder.itemView.setPadding(DensityUtils.dp2px(16f), 0, DensityUtils.dp2px(16f), 0)
}
}
}

View File

@ -0,0 +1,15 @@
package com.cheng.bole.ui.fragment.search.list
import android.graphics.Color
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.cheng.bole.R
import com.cheng.bole.bean.SearchOptionBean
class SearchOptionParentAdapter: BaseQuickAdapter<SearchOptionBean, BaseViewHolder>(R.layout.listitem_search_option_parent) {
override fun convert(holder: BaseViewHolder, item: SearchOptionBean) {
holder.setText(R.id.tv_name, item.title)
holder.setVisible(R.id.view_tag, item.isChecked)
holder.itemView.setBackgroundColor(if (item.isChecked) Color.WHITE else Color.TRANSPARENT)
}
}

View File

@ -0,0 +1,33 @@
package com.cheng.bole.utils
import android.graphics.Color
object BidTypeUtils {
fun getShortName(typeName: String): String {
return when (typeName) {
"招标计划" -> "招标"
"采购公告" -> "采购"
"招标公告" -> "预告"
"合同公告" -> "合同"
"中标公告" -> "中标"
"竞争性磋商" -> "竞争性磋商"
"更正公告" -> "更正"
"终止公告" -> "终止"
else -> "其他"
}
}
fun getTypeColor(typeName: String): Int {
return when (typeName) {
"招标计划" -> Color.parseColor("#2B88F9")
"采购公告" -> Color.parseColor("#FF7344")
"招标公告" -> Color.parseColor("#14CEB3")
"合同公告" -> Color.parseColor("#FFA91D")
"中标公告" -> Color.parseColor("#FF1B1B")
"竞争性磋商" -> Color.parseColor("#0DA9FF")
"更正公告" -> Color.parseColor("#7066FF")
"终止公告" -> Color.parseColor("#8C9199")
else -> Color.parseColor("#EEEEEE")
}
}
}

View File

@ -44,7 +44,7 @@ class DownLoadUtils private constructor() {
} }
private var readTimeOut = 30L private var readTimeOut = 30L
fun setReadTImeOut(read: Long): DownLoadUtils { fun setReadTimeOut(read: Long): DownLoadUtils {
this.readTimeOut = read this.readTimeOut = read
return this return this
} }
@ -90,23 +90,24 @@ class DownLoadUtils private constructor() {
.addInterceptor(interceptor ?: LoggingInterceptor()) .addInterceptor(interceptor ?: LoggingInterceptor())
.build() .build()
} }
private var actionGetTotal: (total: Long) -> Unit? = { _ -> } private var actionGetTotal: ((total: Long) -> Unit)? = { _ -> }
private var actionProgress: (position: Long) -> Unit? = { _ -> } private var actionProgress: ((position: Long) -> Unit)? = { _ -> }
private var actionSuccess: (file: File) -> Unit? = { _ -> } private var actionSuccess: (file: File) -> Unit = { _ -> }
private var actionCancel: () -> Unit? = { } private var actionFail: ((msg: String) -> Unit)? = { _ -> }
private var actionFail: (msg: String) -> Unit? = { _ -> } private var actionCancel: (() -> Unit)? = { }
fun setActionCallBack( fun setActionCallBack(
actionGetTotal: (total: Long) -> Unit, actionGetTotal: ((total: Long) -> Unit)? = null,
actionProgress: (position: Long) -> Unit, actionProgress: ((position: Long) -> Unit)? = null,
actionSuccess: (file: File) -> Unit, actionSuccess: (file: File) -> Unit,
actionFail: (msg: String) -> Unit, actionFail: (msg: String) -> Unit,
actionCancel: (() -> Unit)? = null
): DownLoadUtils { ): DownLoadUtils {
this.actionGetTotal = actionGetTotal this.actionGetTotal = actionGetTotal
this.actionProgress = actionProgress this.actionProgress = actionProgress
this.actionSuccess = actionSuccess this.actionSuccess = actionSuccess
this.actionFail = actionFail this.actionFail = actionFail
this.actionCancel = actionCancel
return this return this
} }
@ -278,7 +279,7 @@ class DownLoadUtils private constructor() {
private fun doException(err: String) { private fun doException(err: String) {
runOnUiThread { runOnUiThread {
if (downCallBack == null) { if (downCallBack == null) {
actionFail.invoke(err) actionFail?.invoke(err)
} else { } else {
downCallBack?.fail(err) downCallBack?.fail(err)
} }
@ -304,7 +305,7 @@ class DownLoadUtils private constructor() {
private fun doGetTotal(total: Long) { private fun doGetTotal(total: Long) {
runOnUiThread { runOnUiThread {
if (downCallBack == null) { if (downCallBack == null) {
actionGetTotal.invoke(total) actionGetTotal?.invoke(total)
} else { } else {
downCallBack?.total(total) downCallBack?.total(total)
} }
@ -315,7 +316,7 @@ class DownLoadUtils private constructor() {
private fun doProgress(progress: Long) { private fun doProgress(progress: Long) {
runOnUiThread { runOnUiThread {
if (downCallBack == null) { if (downCallBack == null) {
actionProgress.invoke(progress) actionProgress?.invoke(progress)
} else { } else {
downCallBack?.progress(progress) downCallBack?.progress(progress)
} }
@ -325,7 +326,7 @@ class DownLoadUtils private constructor() {
private fun doCancel() { private fun doCancel() {
runOnUiThread { runOnUiThread {
if (downCallBack == null) { if (downCallBack == null) {
actionCancel.invoke() actionCancel?.invoke()
} else { } else {
downCallBack?.cancel() downCallBack?.cancel()
} }

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:topLeftRadius="@dimen/dp_40" />
</shape>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="@dimen/dp_6" />
<solid android:color="#F4F8FF" />
</shape>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="@dimen/dp_10" />
<solid android:color="@color/color_f6f6f6" />
</shape>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="@dimen/dp_25" />
<solid android:color="@color/color_f6f6f6" />
</shape>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="@dimen/dp_4" />
<solid android:color="@color/color_f6f6f6" />
</shape>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners android:radius="@dimen/dp_10" />
<stroke
android:width="@dimen/dp_1"
android:color="@color/color_125ffe" />
</shape>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_125ffe" />
<corners
android:bottomRightRadius="@dimen/dp_2"
android:topRightRadius="@dimen/dp_2" />
</shape>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners
android:bottomLeftRadius="@dimen/dp_10"
android:bottomRightRadius="@dimen/dp_10" />
</shape>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners
android:topLeftRadius="@dimen/dp_16"
android:topRightRadius="@dimen/dp_16" />
</shape>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_white_top_cor16"
android:paddingStart="@dimen/dp_12"
android:paddingEnd="@dimen/dp_12"
android:paddingBottom="@dimen/dp_50">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_16"
android:text=""
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_16"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="取消"
android:textColor="@color/color_999999"
android:textSize="@dimen/sp_15"
app:layout_constraintBottom_toBottomOf="@id/tv_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_title" />
<TextView
android:id="@+id/tv_confirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="确定"
android:textColor="@color/color_125ffe"
android:textSize="@dimen/sp_15"
app:layout_constraintBottom_toBottomOf="@id/tv_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_title" />
<com.github.gzuliyujiang.wheelpicker.widget.DateWheelLayout
android:id="@+id/date_picker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_30"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_white_cor16"
android:paddingBottom="@dimen/dp_26">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:src="@mipmap/ic_attachment_dialog_top_bg"
app:layout_constraintDimensionRatio="h,816:360"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_20"
android:text="下载附件(PDF)"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_17"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_attachment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="@dimen/dp_300"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toBottomOf="@id/tv_title"
tools:itemCount="2"
tools:listitem="@layout/listitem_bid_attachment" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginEnd="@dimen/dp_10"
android:src="@mipmap/ic_close_dialog"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,230 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:src="@mipmap/ic_bid_detail_top_bg"
app:layout_constraintDimensionRatio="h,1125:984" />
<com.example.base.widget.TitleBar
android:id="@+id/mTitleBar"
style="@style/Custom.TitleBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="@drawable/ic_back_black"
app:title=" ">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginEnd="@dimen/dp_16"
android:src="@mipmap/ic_bid_share" />
</com.example.base.widget.TitleBar>
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_16"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginEnd="@dimen/dp_16"
android:fontFamily="sans-serif-medium"
android:text="酒钢集团榆中长虹公司2025年焊丝生产用涂层模模具业务外包"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_18"
app:layout_constraintTop_toBottomOf="@id/mTitleBar" />
<LinearLayout
android:id="@+id/layout_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_16"
android:layout_marginTop="@dimen/dp_4"
android:layout_marginEnd="@dimen/dp_16"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title">
<com.cheng.bole.widget.CommonShapeView
android:id="@+id/tv_tag"
android:layout_width="wrap_content"
android:layout_height="@dimen/dp_18"
android:layout_marginEnd="@dimen/dp_8"
android:paddingStart="@dimen/dp_4"
android:paddingEnd="@dimen/dp_4"
android:text="招标"
android:textColor="@color/white"
android:textSize="@dimen/sp_11"
app:csb_cornerRadius="@dimen/dp_3"
app:csb_fillColor="#2B88F9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_title" />
<com.cheng.bole.widget.CommonShapeView
android:id="@+id/tv_location"
android:layout_width="wrap_content"
android:layout_height="@dimen/dp_18"
android:layout_marginEnd="@dimen/dp_8"
android:paddingStart="@dimen/dp_4"
android:paddingEnd="@dimen/dp_4"
android:text="全国"
android:textColor="#585D6C"
android:textSize="@dimen/sp_11"
app:csb_cornerRadius="@dimen/dp_3"
app:csb_fillColor="#F4F6FA"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_content" />
<com.cheng.bole.widget.CommonShapeView
android:id="@+id/tv_amount"
android:layout_width="wrap_content"
android:layout_height="@dimen/dp_18"
android:layout_marginEnd="@dimen/dp_8"
android:paddingStart="@dimen/dp_4"
android:paddingEnd="@dimen/dp_4"
android:text="2.71万元"
android:textColor="@color/color_ff493c"
android:textSize="@dimen/sp_11"
app:csb_cornerRadius="@dimen/dp_3"
app:csb_fillColor="#1aff493c"
app:layout_constraintStart_toEndOf="@id/tv_location"
app:layout_constraintTop_toTopOf="@id/tv_location" />
<com.cheng.bole.widget.CommonShapeView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="@dimen/dp_18"
android:paddingStart="@dimen/dp_4"
android:paddingEnd="@dimen/dp_4"
android:text="20分钟前"
android:textColor="#22C29C"
android:textSize="@dimen/sp_11"
app:csb_cornerRadius="@dimen/dp_3"
app:csb_fillColor="#E8F8F5"
app:layout_constraintStart_toEndOf="@id/tv_amount"
app:layout_constraintTop_toTopOf="@id/tv_amount" />
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="@dimen/dp_40"
android:background="@drawable/shape_bid_detail_bg"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/layout_info">
<LinearLayout
android:id="@+id/layout_contacts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_16"
android:layout_marginTop="@dimen/dp_37"
android:layout_marginEnd="@dimen/dp_16"
android:background="@drawable/shape_f4f8ff_cor6"
android:orientation="vertical"
android:paddingStart="@dimen/dp_16"
android:paddingTop="@dimen/dp_12"
android:paddingEnd="@dimen/dp_16"
android:paddingBottom="@dimen/dp_12"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:text="联系人"
android:textColor="@color/color_125ffe"
android:textSize="@dimen/sp_14" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_contacts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="2"
tools:listitem="@layout/listitem_bid_detail_contact" />
</LinearLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="@dimen/dp_16"
android:layout_marginTop="@dimen/dp_20"
android:layout_marginEnd="@dimen/dp_16"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/layout_contacts">
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_13" />
</androidx.core.widget.NestedScrollView>
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="@dimen/dp_16"
android:layout_marginTop="@dimen/dp_20"
android:layout_marginEnd="@dimen/dp_16"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/layout_contacts" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_image"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="@dimen/dp_16"
android:layout_marginTop="@dimen/dp_20"
android:layout_marginEnd="@dimen/dp_16"
android:visibility="gone"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/layout_contacts"
tools:listitem="@layout/listitem_bid_detail_image" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_download"
android:layout_width="@dimen/dp_60"
android:layout_height="@dimen/dp_60"
android:layout_marginBottom="-30dp"
android:src="@mipmap/ic_bid_download"
app:layout_constraintBottom_toTopOf="@id/layout_content"
app:layout_constraintEnd_toStartOf="@id/iv_favorite" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_favorite"
android:layout_width="@dimen/dp_60"
android:layout_height="@dimen/dp_60"
android:layout_marginBottom="-30dp"
android:src="@mipmap/ic_bid_favorite"
app:layout_constraintBottom_toTopOf="@id/layout_content"
app:layout_constraintEnd_toStartOf="@id/iv_view" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_view"
android:layout_width="@dimen/dp_60"
android:layout_height="@dimen/dp_60"
android:layout_marginBottom="-30dp"
android:src="@mipmap/ic_bid_view"
app:layout_constraintBottom_toTopOf="@id/layout_content"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -3,9 +3,11 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:background="@color/white">
<androidx.coordinatorlayout.widget.CoordinatorLayout <androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/layout_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -112,7 +114,7 @@
android:layout_marginTop="@dimen/dp_10" android:layout_marginTop="@dimen/dp_10"
android:background="@drawable/shape_white_top_cor20" android:background="@drawable/shape_white_top_cor20"
android:paddingTop="@dimen/dp_17" android:paddingTop="@dimen/dp_17"
android:paddingBottom="@dimen/dp_40" android:paddingBottom="@dimen/dp_20"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintTop_toBottomOf="@id/tv_hot_title" app:layout_constraintTop_toBottomOf="@id/tv_hot_title"
app:spanCount="4" app:spanCount="4"
@ -125,7 +127,7 @@
android:id="@+id/layout_content" android:id="@+id/layout_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginTop="-65dp" android:layout_marginTop="-45dp"
android:paddingTop="@dimen/dp_45" android:paddingTop="@dimen/dp_45"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> app:layout_behavior="@string/appbar_scrolling_view_behavior">
@ -183,6 +185,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginTop="@dimen/dp_12" android:layout_marginTop="@dimen/dp_12"
android:background="@color/windowBackground"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_bid_title"> app:layout_constraintTop_toBottomOf="@id/tv_bid_title">

View File

@ -0,0 +1,273 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_top_bg"
android:layout_width="match_parent"
android:layout_height="0dp"
android:src="@mipmap/ic_search_top_bg"
app:layout_constraintDimensionRatio="h,1125:900"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_24"
android:layout_marginTop="@dimen/dp_100"
android:text="搜索招标商机"
android:textColor="#000511"
android:textSize="@dimen/sp_30"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_3"
android:text="信息领航,商机在握"
android:textColor="#72757E"
android:textSize="@dimen/sp_14"
app:layout_constraintStart_toStartOf="@id/tv_title"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
<LinearLayout
android:id="@+id/layout_search"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_46"
android:layout_marginStart="@dimen/dp_16"
android:layout_marginTop="@dimen/dp_200"
android:layout_marginEnd="@dimen/dp_16"
android:background="@drawable/shape_search_edit_bg"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/et_search"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/dp_12"
android:layout_weight="1"
android:background="@null"
android:drawableStart="@mipmap/ic_search"
android:drawablePadding="@dimen/dp_8"
android:gravity="center_vertical"
android:hint="请搜索关键词"
android:lines="1"
android:singleLine="true"
android:textColor="@color/color_1a1a1a"
android:textColorHint="@color/color_bcbcbc"
android:textSize="@dimen/sp_15" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_clear_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_12"
android:layout_marginEnd="@dimen/dp_12"
android:src="@mipmap/ic_clear_text"
android:visibility="invisible" />
<com.cheng.bole.widget.CommonShapeView
android:id="@+id/btn_search"
android:layout_width="@dimen/dp_60"
android:layout_height="@dimen/dp_34"
android:layout_marginEnd="@dimen/dp_6"
android:text="搜索"
android:textColor="@color/white"
android:textSize="@dimen/sp_15"
app:csb_cornerRadius="@dimen/dp_10"
app:csb_fillColor="@color/color_125ffe" />
</LinearLayout>
<com.lihang.ShadowLayout
android:id="@+id/layout_history"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_9"
android:layout_marginTop="@dimen/dp_13"
android:layout_marginEnd="@dimen/dp_9"
app:hl_cornerRadius="@dimen/dp_10"
android:visibility="gone"
app:hl_layoutBackground="@color/white"
app:hl_shadowColor="#0d4a4f5b"
app:hl_shadowLimit="@dimen/dp_7"
app:layout_constraintTop_toBottomOf="@id/layout_search">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/dp_12"
android:paddingTop="@dimen/dp_16"
android:paddingEnd="@dimen/dp_12"
android:paddingBottom="@dimen/dp_16">
<TextView
android:id="@+id/tv_history_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="@mipmap/ic_search_history"
android:drawablePadding="@dimen/dp_4"
android:fontFamily="sans-serif-medium"
android:gravity="center"
android:text="历史搜索"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_16"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_clear_history"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_clear_history"
app:layout_constraintBottom_toBottomOf="@id/tv_history_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_history_title" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_history"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_6"
android:orientation="horizontal"
android:overScrollMode="never"
app:layoutManager="com.google.android.flexbox.FlexboxLayoutManager"
app:layout_constraintTop_toBottomOf="@id/tv_history_title"
tools:listitem="@layout/listitem_search_history" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.lihang.ShadowLayout>
<com.lihang.ShadowLayout
android:id="@+id/layout_recommend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_9"
android:layout_marginEnd="@dimen/dp_9"
app:hl_cornerRadius="@dimen/dp_10"
app:hl_layoutBackground="@color/white"
app:hl_shadowColor="#0d4a4f5b"
app:hl_shadowLimit="@dimen/dp_7"
app:layout_goneMarginTop="@dimen/dp_13"
app:layout_constraintTop_toBottomOf="@id/layout_history">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/dp_12"
android:paddingTop="@dimen/dp_16"
android:paddingEnd="@dimen/dp_12"
android:paddingBottom="@dimen/dp_16">
<TextView
android:id="@+id/tv_recommend_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="@mipmap/ic_search_recommend_keyword"
android:drawablePadding="@dimen/dp_4"
android:fontFamily="sans-serif-medium"
android:gravity="center"
android:text="搜索推荐"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_16"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_refresh_recommend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_refresh2"
app:layout_constraintBottom_toBottomOf="@id/tv_recommend_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_recommend_title" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_recommend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_6"
android:orientation="horizontal"
android:overScrollMode="never"
app:layoutManager="com.google.android.flexbox.FlexboxLayoutManager"
app:layout_constraintTop_toBottomOf="@id/tv_recommend_title"
tools:listitem="@layout/listitem_search_recommend" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.lihang.ShadowLayout>
<com.lihang.ShadowLayout
android:id="@+id/layout_hot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_9"
android:layout_marginEnd="@dimen/dp_9"
app:hl_cornerRadius="@dimen/dp_10"
app:hl_layoutBackground="@color/white"
app:hl_shadowColor="#0d4a4f5b"
app:hl_shadowLimit="@dimen/dp_7"
app:layout_constraintTop_toBottomOf="@id/layout_recommend">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/dp_12"
android:paddingTop="@dimen/dp_16"
android:paddingEnd="@dimen/dp_12"
android:paddingBottom="@dimen/dp_16">
<TextView
android:id="@+id/tv_hot_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="@mipmap/ic_search_hot_type"
android:drawablePadding="@dimen/dp_4"
android:fontFamily="sans-serif-medium"
android:gravity="center"
android:text="热门类型"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_16"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_hot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_6"
android:orientation="vertical"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toBottomOf="@id/tv_hot_title"
tools:listitem="@layout/listitem_search_hot_type" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.lihang.ShadowLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<com.example.base.widget.TitleBar
android:id="@+id/mTitleBar"
style="@style/Custom.TitleBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="@drawable/ic_back_black"
app:title=" " />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="@color/white"
android:layout_height="match_parent">
<com.example.base.widget.TitleBar
android:id="@+id/mTitleBar"
style="@style/Custom.TitleBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="@drawable/ic_back_black"
app:title=" " />
<FrameLayout
android:id="@+id/layout_search"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:layout_marginStart="@dimen/dp_50"
android:layout_marginEnd="@dimen/dp_16"
app:layout_constraintBottom_toBottomOf="@id/mTitleBar">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="@dimen/dp_36"
android:layout_gravity="center_vertical"
android:background="@drawable/shape_f6f6f6_cor10"
android:gravity="center_vertical"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/et_search"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/dp_2"
android:layout_weight="1"
android:background="@null"
android:drawableStart="@mipmap/ic_search"
android:drawablePadding="@dimen/dp_8"
android:gravity="center_vertical"
android:hint="请输入关键词"
android:lines="1"
android:imeOptions="actionSearch"
android:maxLines="1"
android:paddingStart="@dimen/dp_14"
android:singleLine="true"
android:textColor="@color/color_1a1a1a"
android:textColorHint="@color/color_bcbcbc"
android:textSize="@dimen/sp_14" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_clear_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_10"
android:layout_marginEnd="@dimen/dp_10"
android:src="@mipmap/ic_clear_text"
android:visibility="invisible" />
</androidx.appcompat.widget.LinearLayoutCompat>
</FrameLayout>
<LinearLayout
android:id="@+id/layout_options"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_12"
android:layout_marginTop="@dimen/dp_14"
android:layout_marginEnd="@dimen/dp_12"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@id/mTitleBar">
<com.cheng.bole.widget.CommonShapeView
android:id="@+id/btn_area"
android:layout_width="0dp"
android:layout_height="@dimen/dp_34"
android:layout_weight="1"
android:drawableEnd="@mipmap/ic_option_arrow_down"
android:drawablePadding="@dimen/dp_4"
android:text="地区"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_13"
app:csb_cornerRadius="@dimen/dp_25"
app:csb_drawablePosition="right" />
<com.cheng.bole.widget.CommonShapeView
android:id="@+id/btn_time"
android:layout_width="0dp"
android:layout_height="@dimen/dp_34"
android:layout_marginStart="@dimen/dp_9"
android:layout_weight="1"
android:drawableEnd="@mipmap/ic_option_arrow_down"
android:drawablePadding="@dimen/dp_4"
android:text="时间"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_13"
app:csb_cornerRadius="@dimen/dp_25"
app:csb_drawablePosition="right" />
<com.cheng.bole.widget.CommonShapeView
android:id="@+id/btn_sort"
android:layout_width="0dp"
android:layout_height="@dimen/dp_34"
android:layout_marginStart="@dimen/dp_9"
android:layout_weight="1"
android:drawableEnd="@mipmap/ic_option_arrow_down"
android:drawablePadding="@dimen/dp_4"
android:text="排序"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_13"
app:csb_cornerRadius="@dimen/dp_25"
app:csb_drawablePosition="right" />
<com.cheng.bole.widget.CommonShapeView
android:id="@+id/btn_type"
android:layout_width="0dp"
android:layout_height="@dimen/dp_34"
android:layout_marginStart="@dimen/dp_9"
android:layout_weight="1"
android:drawableEnd="@mipmap/ic_option_arrow_down"
android:drawablePadding="@dimen/dp_4"
android:text="信息"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_13"
app:csb_cornerRadius="@dimen/dp_25"
app:csb_drawablePosition="right" />
</LinearLayout>
<com.scwang.smart.refresh.layout.SmartRefreshLayout
android:id="@+id/mRefreshLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/windowBackground"
android:layout_marginTop="@dimen/dp_5"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/layout_options">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/mRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/listitem_bid" />
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
<View
android:id="@+id/view_mask"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#cc000000"
android:clickable="true"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/mRefreshLayout"
app:layout_constraintTop_toTopOf="@id/mRefreshLayout" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_16">
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_22"
android:layout_marginEnd="@dimen/dp_22"
android:ellipsize="end"
android:gravity="center"
android:lines="1"
android:singleLine="true"
android:text="20250711180945-2000026473"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_14"
app:layout_constraintTop_toTopOf="parent" />
<com.cheng.bole.widget.CommonShapeView
android:id="@+id/btn_download"
android:layout_width="@dimen/dp_132"
android:layout_height="@dimen/dp_34"
android:layout_marginTop="@dimen/dp_16"
android:text="下载并分享到微信"
android:textColor="@color/color_125ffe"
android:textSize="@dimen/sp_13"
app:csb_activeEnable="true"
app:csb_fillColor="#0d125ffe"
app:csb_cornerRadius="@dimen/dp_10"
app:csb_strokeColor="@color/color_125ffe"
app:csb_strokeWidth="@dimen/dp_1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_name" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_marginTop="@dimen/dp_8"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="郭女士"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_14"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<TextView
android:id="@+id/tv_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0937-6719119"
android:layout_marginStart="@dimen/dp_16"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_14"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_name"/>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_call"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:src="@mipmap/ic_phone_contacts"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_image"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="@dimen/dp_30"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/shape_f6f6f6_cor25"
android:paddingStart="@dimen/dp_14"
android:layout_marginStart="@dimen/dp_5"
android:layout_marginEnd="@dimen/dp_5"
android:layout_marginTop="@dimen/dp_10"
android:paddingEnd="@dimen/dp_14">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="国土局"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:textColor="@color/color_666666"
android:textSize="@dimen/sp_13" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40">
<com.cheng.bole.widget.CommonShapeView
android:id="@+id/tv_tag"
android:layout_width="@dimen/dp_16"
android:layout_height="@dimen/dp_16"
android:text="1"
android:textColor="@color/white"
android:textSize="@dimen/sp_12"
app:csb_cornerRadius="@dimen/dp_2"
app:csb_endColor="#FFCD1B"
app:csb_orientation="TOP_BOTTOM"
app:csb_startColor="#FFB505"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_8"
android:text="招标公告"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_14"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_tag"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2.5万次"
android:textColor="#0A204D"
android:textSize="@dimen/sp_12"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40"
android:paddingStart="@dimen/dp_30"
android:paddingEnd="@dimen/dp_25">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="全部"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_14"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_option_checked"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40">
<View
android:id="@+id/view_tag"
android:layout_width="@dimen/dp_4"
android:background="@drawable/shape_search_option_tag"
android:layout_height="@dimen/dp_16"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="全国地区"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_14"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="@dimen/dp_30"
android:layout_marginStart="@dimen/dp_5"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginEnd="@dimen/dp_5"
android:background="@drawable/shape_f6f6f6_cor25"
android:paddingStart="@dimen/dp_14"
android:paddingEnd="@dimen/dp_14">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="国土局"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_13"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_white_bottom_cor10">
<androidx.core.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintHeight_max="@dimen/dp_400"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintHeight_max="@dimen/dp_400">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_parent"
android:layout_width="@dimen/dp_120"
android:layout_height="0dp"
android:background="@color/color_f6f6f6"
android:orientation="vertical"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/listitem_search_option_parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_child"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/rv_parent"
tools:listitem="@layout/listitem_search_option_child" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_custom_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/dp_16"
android:paddingEnd="@dimen/dp_16"
android:paddingBottom="@dimen/dp_12"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/layout_content"
tools:visibility="visible">
<View
app:layout_constraintTop_toTopOf="parent"
android:layout_width="match_parent"
android:background="@color/color_eeeeee"
android:layout_height="@dimen/dp_1"/>
<TextView
android:id="@+id/tv_custom_time_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="自定义时间"
android:layout_marginTop="@dimen/dp_12"
android:textColor="@color/color_1a1a1a"
android:textSize="@dimen/sp_15"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_start_time"
android:layout_width="0dp"
android:layout_height="@dimen/dp_34"
android:layout_marginTop="@dimen/dp_20"
android:background="@drawable/shape_f6f6f6_cor4"
android:gravity="center"
android:hint="开始时间"
android:textColor="@color/color_1a1a1a"
android:textColorHint="@color/color_999999"
android:textSize="@dimen/sp_14"
app:layout_constraintEnd_toStartOf="@id/view_divider"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_custom_time_title" />
<View
android:id="@+id/view_divider"
android:layout_width="@dimen/dp_26"
android:layout_height="@dimen/dp_1"
android:layout_marginStart="@dimen/dp_12"
android:layout_marginEnd="@dimen/dp_12"
android:background="@color/color_dddddd"
app:layout_constraintBottom_toBottomOf="@id/tv_start_time"
app:layout_constraintEnd_toStartOf="@id/tv_end_time"
app:layout_constraintStart_toEndOf="@id/tv_start_time"
app:layout_constraintTop_toTopOf="@id/tv_start_time" />
<TextView
android:id="@+id/tv_end_time"
android:layout_width="0dp"
android:layout_height="@dimen/dp_34"
android:layout_marginTop="@dimen/dp_20"
android:background="@drawable/shape_f6f6f6_cor4"
android:gravity="center"
android:hint="结束时间"
android:textColor="@color/color_1a1a1a"
android:textColorHint="@color/color_999999"
android:textSize="@dimen/sp_14"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/view_divider"
app:layout_constraintTop_toBottomOf="@id/tv_custom_time_title" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/color_e8e8e8"
app:layout_constraintBottom_toTopOf="@id/layout_bottom" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/dp_12"
android:paddingTop="@dimen/dp_14"
android:paddingEnd="@dimen/dp_12"
android:paddingBottom="@dimen/dp_14"
app:layout_constraintTop_toBottomOf="@id/nestedScrollView">
<com.cheng.bole.widget.CommonShapeView
android:id="@+id/btn_reset"
android:layout_width="0dp"
android:layout_height="@dimen/dp_40"
android:text="重置"
android:textColor="@color/color_9a9ea7"
android:textSize="@dimen/sp_15"
app:csb_activeEnable="true"
app:csb_cornerRadius="@dimen/dp_10"
app:csb_fillColor="@color/color_ebf5ff"
app:layout_constraintEnd_toStartOf="@id/btn_next"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.cheng.bole.widget.CommonShapeView
android:id="@+id/btn_next"
android:layout_width="0dp"
android:layout_height="@dimen/dp_40"
android:layout_marginStart="@dimen/dp_10"
android:text="确定"
android:textColor="@color/white"
android:textSize="@dimen/sp_15"
app:csb_cornerRadius="@dimen/dp_10"
app:csb_fillColor="@color/color_125ffe"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/btn_reset"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -1,6 +1,6 @@
<resources> <resources>
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Theme.Material" parent="Theme.MaterialComponents.Light.NoActionBar"> <style name="Theme.Base" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/color_2090fe</item> <item name="colorAccent">@color/color_2090fe</item>
@ -26,7 +26,7 @@
<item name="android:windowExitAnimation">@anim/dialog_exit</item> <item name="android:windowExitAnimation">@anim/dialog_exit</item>
</style> </style>
<style name="SplashTheme" parent="Theme.Material"> <style name="SplashTheme" parent="Theme.Base">
<item name="android:windowNoTitle">true</item> <item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item> <item name="android:windowFullscreen">true</item>
<!-- 单色填充背景 --> <!-- 单色填充背景 -->

View File

@ -76,4 +76,5 @@
<color name="color_ff2222">#FF2222</color> <color name="color_ff2222">#FF2222</color>
<color name="color_ff493c">#FF493C</color> <color name="color_ff493c">#FF493C</color>
<color name="color_ffb92d">#FFB92D</color> <color name="color_ffb92d">#FFB92D</color>
<color name="color_dddddd">#DDDDDD</color>
</resources> </resources>

View File

@ -85,5 +85,6 @@
<dimen name="dp_130">130dp</dimen> <dimen name="dp_130">130dp</dimen>
<dimen name="dp_42">42dp</dimen> <dimen name="dp_42">42dp</dimen>
<dimen name="dp_170">170dp</dimen> <dimen name="dp_170">170dp</dimen>
<dimen name="dp_132">132dp</dimen>
</resources> </resources>

View File

@ -1,6 +1,6 @@
<resources> <resources>
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Theme.Material" parent="Theme.MaterialComponents.Light.NoActionBar"> <style name="Theme.Base" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/color_2090fe</item> <item name="colorAccent">@color/color_2090fe</item>
@ -26,7 +26,7 @@
<item name="android:windowExitAnimation">@anim/dialog_exit</item> <item name="android:windowExitAnimation">@anim/dialog_exit</item>
</style> </style>
<style name="SplashTheme" parent="Theme.Material"> <style name="SplashTheme" parent="Theme.Base">
<item name="android:windowNoTitle">true</item> <item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item> <item name="android:windowFullscreen">true</item>
<item name="android:windowBackground">@drawable/layer_splash</item> <item name="android:windowBackground">@drawable/layer_splash</item>