设备相关

This commit is contained in:
fengjignqi
2026-09-19 08:41:53 +08:00
parent f7cf112dc9
commit 981cfae71c
26 changed files with 839 additions and 72 deletions

View File

@@ -0,0 +1,78 @@
package com.juhabi.birds.device
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import com.gyf.immersionbar.ImmersionBar
import com.juhabi.birds.R
import com.juhabi.birds.base.BaseActivity
import com.juhabi.birds.databinding.BindDeviceLayoutBinding
import com.juhabi.birds.device.entity.DeviceEntity
import com.juhabi.birds.device.mvp.DeviceContract
import com.juhabi.birds.device.mvp.DeviceImpl
import com.juhabi.birds.device.mvp.DevicePresenter
import kotlin.random.Random
/**
* 绑定设备
*/
class BindDeviceActivity: BaseActivity<BindDeviceLayoutBinding, DevicePresenter>() , DeviceContract.DeviceView,
View.OnClickListener {
override fun createBinding(inflater: LayoutInflater): BindDeviceLayoutBinding {
return BindDeviceLayoutBinding.inflate(inflater)
}
override fun createPresenter(): DevicePresenter? {
return DevicePresenter(DeviceImpl())
}
override fun initWindows() {
ImmersionBar.with(this)
.statusBarView(binding.statusBarView)
.statusBarDarkFont(true)
.navigationBarColor(R.color.color_zhu)
.navigationBarDarkIcon(true)
.init()
}
override fun initView(savedInstanceState: Bundle?) {
binding.includedTitle.tvTitle.setText(R.string.bind_device)
listOf(
binding.tvBind,
binding.includedTitle.imgBack,
).forEach { button ->
button.setOnClickListener(this)
}
}
override fun onClick(view: View) {
when (view.id) {
R.id.img_back ->{
finish()
}
R.id.tv_bind ->{//绑定设备
// val imei = "${System.currentTimeMillis()}${Random.nextInt(100).toString().padStart(2, '0')}"
// val name = "device001"
val imei = "860000000000005"
val name = "BM202609160005"
presenter?.bindDevice(imei, name)
}
}
}
override fun showError(message: String) {
showMessage(message)
}
override fun getBindDeviceListSuccess(devices: List<DeviceEntity>) {
}
/** 绑定设备成功后提示用户并关闭当前页面。 */
override fun bindDeviceSuccess(message: String) {
showMessage(message)
finish()
}
}

View File

@@ -0,0 +1,40 @@
package com.juhabi.birds.device
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import com.juhabi.birds.base.BaseActivity
import com.juhabi.birds.databinding.BindDeviceLayoutBinding
import com.juhabi.birds.device.entity.DeviceEntity
import com.juhabi.birds.device.mvp.DeviceContract
import com.juhabi.birds.device.mvp.DeviceImpl
import com.juhabi.birds.device.mvp.DevicePresenter
/**
* 设备详情
*/
class DeviceDetailActivity: BaseActivity<BindDeviceLayoutBinding, DevicePresenter>() , DeviceContract.DeviceView,
View.OnClickListener {
override fun createBinding(inflater: LayoutInflater): BindDeviceLayoutBinding {
return BindDeviceLayoutBinding.inflate(inflater)
}
override fun createPresenter(): DevicePresenter? {
return DevicePresenter(DeviceImpl())
}
override fun initView(savedInstanceState: Bundle?) {
}
override fun showError(message: String) {
}
override fun getBindDeviceListSuccess(devices: List<DeviceEntity>) {
}
override fun bindDeviceSuccess(message: String) {
}
override fun onClick(view: View) {
}
}

View File

@@ -0,0 +1,184 @@
package com.juhabi.birds.device
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.juhabi.birds.R
import com.juhabi.birds.base.BaseActivity
import com.juhabi.birds.base.BaseFragment
import com.juhabi.birds.custom.DeviceActionPopupWindow
import com.juhabi.birds.custom.CustomRefreshHeader
import com.juhabi.birds.databinding.FragmentHomeBinding
import com.juhabi.birds.device.entity.DeviceEntity
import com.juhabi.birds.device.mvp.DeviceContract
import com.juhabi.birds.device.mvp.DeviceImpl
import com.juhabi.birds.device.mvp.DevicePresenter
import com.juhabi.birds.main.fragment.home.mvp.HomeContract
import com.juhabi.birds.main.fragment.home.mvp.HomeImpl
import com.juhabi.birds.main.fragment.home.mvp.HomePresenter
import com.scwang.smart.refresh.footer.ClassicsFooter
class IndexFragment : BaseFragment<FragmentHomeBinding, DevicePresenter>(),
DeviceContract.DeviceView, View.OnClickListener {
private val deviceAdapter = DeviceAdapter()
private var currentPage = FIRST_PAGE
private var pendingUnbindPosition: Int? = null
override fun createBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentHomeBinding {
return FragmentHomeBinding.inflate(inflater, container, false)
}
override fun createPresenter(): DevicePresenter {
return DevicePresenter(DeviceImpl())
}
override fun initView(savedInstanceState: Bundle?) {
listOf(
binding.tvIndex,
).forEach { button ->
button.setOnClickListener(this)
}
binding.rvDevices.adapter = deviceAdapter
deviceAdapter.setOnItemChildClickListener { adapter, view, position ->
when (view.id) {
R.id.img_tips -> {
val device = deviceAdapter.data[position]
DeviceActionPopupWindow(requireContext()).show(
view,
onRename = {//重命名
showEditDialog(
"设备重命名", device.name, click = object : OnDialogClick {
override fun onCancelClick() {}
override fun onConfirmClick(content: String) {
presenter?.renameDevice(device.deviceNo, content)
}
}
)
},
onUnbind = {//解绑设备
showDialogtext(
"提示",
"确定要解绑该设备?",
"确定",
"取消",
object : OnDialogClick {
override fun onCancelClick() {
}
override fun onConfirmClick() {
// 用户确认后,按设备编号请求解绑
pendingUnbindPosition = position
presenter?.unbindDevice(device.deviceNo)
}
}
)
}
)
}
}
}
}
override fun initData(savedInstanceState: Bundle?) {
super.initData(savedInstanceState)
binding.refresh.setRefreshHeader(CustomRefreshHeader(requireContext()))
binding.refresh.setRefreshFooter(ClassicsFooter(requireContext()))
binding.refresh.setOnRefreshListener {
currentPage = FIRST_PAGE
requestDeviceList()
}
binding.refresh.setOnLoadMoreListener {
currentPage++
requestDeviceList()
}
requestDeviceList()
}
override fun onClick(view: View) {
when(view.id){
R.id.tv_index ->{
goTo(BindDeviceActivity::class.java,null)
}
}
}
override fun getBindDeviceListSuccess(devices: List<DeviceEntity>) {
if (currentPage == FIRST_PAGE) {
deviceAdapter.setList(devices)
} else {
deviceAdapter.addData(devices)
}
binding.refresh.finishRefresh()
binding.refresh.finishLoadMore()
binding.refresh.setNoMoreData(devices.size < PAGE_SIZE)
binding.relNoMore.visibility =
if (deviceAdapter.data.isEmpty()) View.VISIBLE else View.GONE
}
override fun bindDeviceSuccess(message: String) {
}
/** 设备重命名成功后提示用户并重新加载第一页数据。 */
override fun renameDeviceSuccess(message: String) {
showMessage(message)
currentPage = FIRST_PAGE
requestDeviceList()
}
/** 设备解绑成功后先播放删除动画,再延迟刷新第一页数据。 */
override fun unbindDeviceSuccess(message: String) {
showMessage(message)
val removedPosition = pendingUnbindPosition
pendingUnbindPosition = null
if (removedPosition != null && removedPosition in deviceAdapter.data.indices) {
deviceAdapter.data.removeAt(removedPosition)
deviceAdapter.notifyItemRemoved(removedPosition)
binding.relNoMore.visibility =
if (deviceAdapter.data.isEmpty()) View.VISIBLE else View.GONE
}
// 等待 RecyclerView 删除动画完成后再刷新,避免刷新结果立即覆盖动画。
binding.root.postDelayed({
if (!isAdded) return@postDelayed
currentPage = FIRST_PAGE
requestDeviceList()
}, REMOVE_ANIMATION_DELAY_MS)
}
/** 请求指定页的设备列表。 */
private fun requestDeviceList() {
presenter?.getBindDeviceList(
mapOf(
"pageNum" to currentPage.toString(),
"pageSize" to PAGE_SIZE.toString()
)
)
}
/** 请求失败时结束刷新状态并恢复上一次有效页码。 */
override fun showError(message: String) {
binding.refresh.finishRefresh(false)
binding.refresh.finishLoadMore(false)
if (currentPage > FIRST_PAGE) {
currentPage--
}
super.showError(message)
}
/** 接口暂无数据时提供临时设备,方便先验收列表布局。 */
private fun temporaryDevices(): List<DeviceEntity> = listOf(
DeviceEntity("暂无地址", "BM202609160005", null, "0", "已断开", "860000000000005", null, null, null, "BM202609160005", null, 0, "离线", "1"),
DeviceEntity("暂无地址", "BM202609160006", null, "0", "已断开", "860000000000006", null, null, null, "BM202609160006", null, 0, "离线", "1"),
DeviceEntity("暂无地址", "BM202609160007", null, "0", "已断开", "860000000000007", null, null, null, "BM202609160007", null, 0, "离线", "1")
)
private companion object {
const val FIRST_PAGE = 1
const val PAGE_SIZE = 10
const val REMOVE_ANIMATION_DELAY_MS = 300L
}
}

View File

@@ -0,0 +1,20 @@
package com.juhabi.birds.device.entity
import java.io.Serializable
data class DeviceEntity(
val address: String,
val deviceNo: String,
val hoodBattery: Int?,
val hoodConnected: String,
val hoodConnectedText: String,
val imei: String,
val lat: Double?,
val lng: Double?,
val model: String?,
val name: String,
val ringBattery: Int?,
val signalLevel: Int,
val signalText: String,
val status: String
) : Serializable