列表,个人中心
This commit is contained in:
@@ -11,7 +11,6 @@ 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
|
||||
|
||||
/**
|
||||
* 绑定设备
|
||||
@@ -51,16 +50,33 @@ class BindDeviceActivity: BaseActivity<BindDeviceLayoutBinding, DevicePresenter>
|
||||
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)
|
||||
R.id.tv_bind -> {
|
||||
bindDevice()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 校验设备编码和名称非空后,发起绑定请求。 */
|
||||
private fun bindDevice() {
|
||||
val imei = binding.etDeviceCode.text
|
||||
?.toString()
|
||||
?.trim()
|
||||
.orEmpty()
|
||||
val name = binding.etDeviceName.text
|
||||
?.toString()
|
||||
?.trim()
|
||||
.orEmpty()
|
||||
if (imei.isBlank()) {
|
||||
showMessage("请输入设备编码")
|
||||
return
|
||||
}
|
||||
if (name.isBlank()) {
|
||||
showMessage("请输入设备名称")
|
||||
return
|
||||
}
|
||||
presenter?.bindDevice(imei, name)
|
||||
}
|
||||
|
||||
override fun showError(message: String) {
|
||||
showMessage(message)
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.juhabi.birds.device
|
||||
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter
|
||||
import com.chad.library.adapter.base.viewholder.BaseViewHolder
|
||||
import com.juhabi.birds.R
|
||||
import com.juhabi.birds.device.entity.DeviceEntity
|
||||
|
||||
/** 临时设备列表适配器,后续可根据设计稿替换 item 展示。 */
|
||||
class DeviceAdapter : BaseQuickAdapter<DeviceEntity, BaseViewHolder>(R.layout.device_item) {
|
||||
init {
|
||||
addChildClickViewIds(R.id.img_tips)
|
||||
}
|
||||
|
||||
override fun convert(holder: BaseViewHolder, item: DeviceEntity) {
|
||||
holder.setText(R.id.tv_device_name, item.name.ifBlank { "未命名设备" })
|
||||
holder.setText(R.id.tv_device_status, item.signalText.ifBlank { "离线" })
|
||||
holder.setText(R.id.tv_device_no, "设备编号:${item.deviceNo}")
|
||||
holder.setText(R.id.tv_device_imei, "IMEI:${item.imei}")
|
||||
holder.setText(R.id.tv_device_detail, "型号:${item.model ?: "-"} 信号:${item.signalLevel} 头部电量:${item.hoodBattery ?: "-"} 戒指电量:${item.ringBattery ?: "-"}")
|
||||
holder.setText(R.id.tv_device_location, "连接:${item.hoodConnectedText} 地址:${item.address ?: "暂无地址"}")
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,17 @@ package com.juhabi.birds.device
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
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.BaseFragment
|
||||
import com.juhabi.birds.custom.AddDevicePopupWindow
|
||||
import com.juhabi.birds.custom.DeviceActionPopupWindow
|
||||
import com.juhabi.birds.custom.CustomRefreshHeader
|
||||
import com.juhabi.birds.databinding.FragmentHomeBinding
|
||||
import com.juhabi.birds.device.adapter.DeviceAdapter
|
||||
import com.juhabi.birds.device.entity.DeviceEntity
|
||||
import com.juhabi.birds.device.mvp.DeviceContract
|
||||
import com.juhabi.birds.device.mvp.DeviceImpl
|
||||
@@ -19,6 +20,7 @@ import com.juhabi.birds.device.mvp.DevicePresenter
|
||||
import com.juhabi.birds.util.ToastUtil
|
||||
import com.maning.mlkitscanner.scan.MNScanManager
|
||||
import com.maning.mlkitscanner.scan.callback.act.MNScanCallback
|
||||
import com.maning.mlkitscanner.scan.model.MNScanConfig
|
||||
import com.scwang.smart.refresh.footer.ClassicsFooter
|
||||
|
||||
class DeviceFragment : BaseFragment<FragmentHomeBinding, DevicePresenter>(),
|
||||
@@ -38,7 +40,6 @@ class DeviceFragment : BaseFragment<FragmentHomeBinding, DevicePresenter>(),
|
||||
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
listOf(
|
||||
binding.tvIndex,
|
||||
binding.imgScan,
|
||||
).forEach { button ->
|
||||
button.setOnClickListener(this)
|
||||
@@ -50,23 +51,29 @@ class DeviceFragment : BaseFragment<FragmentHomeBinding, DevicePresenter>(),
|
||||
putSerializable(DeviceDetailActivity.EXTRA_DEVICE, device)
|
||||
})
|
||||
}
|
||||
deviceAdapter.setOnItemChildClickListener { adapter, view, position ->
|
||||
deviceAdapter.setOnItemChildClickListener { _, view, position ->
|
||||
when (view.id) {
|
||||
R.id.img_tips -> {
|
||||
R.id.img_more -> {
|
||||
val device = deviceAdapter.data[position]
|
||||
DeviceActionPopupWindow(requireContext()).show(
|
||||
view,
|
||||
onRename = {//重命名
|
||||
onRename = {
|
||||
showEditDialog(
|
||||
"设备重命名", device.name, click = object : OnDialogClick {
|
||||
title = "重命名设备",
|
||||
label = "设备名称",
|
||||
hint = device.name,
|
||||
tip = "最多支持20个字符,支持中英文、数字和字符。",
|
||||
confirmText = "确认修改",
|
||||
click = object : OnDialogClick {
|
||||
override fun onCancelClick() {
|
||||
}
|
||||
|
||||
override fun onCancelClick() {}
|
||||
override fun onConfirmClick(content: String) {
|
||||
presenter?.renameDevice(device.deviceNo, content)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
onUnbind = {//解绑设备
|
||||
showDialogtext(
|
||||
"提示",
|
||||
@@ -87,6 +94,15 @@ class DeviceFragment : BaseFragment<FragmentHomeBinding, DevicePresenter>(),
|
||||
}
|
||||
)
|
||||
}
|
||||
R.id.tv_show_map -> {
|
||||
val device = deviceAdapter.data[position]
|
||||
// 没有经纬度时只展示空态,不要把空坐标传给地图
|
||||
if (device.lat.isNullOrBlank() || device.lng.isNullOrBlank()) {
|
||||
showMessage("暂无定位")
|
||||
return@setOnItemChildClickListener
|
||||
}
|
||||
// 地图页后续接入,这里先预留点击入口
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,17 +124,23 @@ class DeviceFragment : BaseFragment<FragmentHomeBinding, DevicePresenter>(),
|
||||
|
||||
override fun onClick(view: View) {
|
||||
when(view.id){
|
||||
R.id.tv_index ->{
|
||||
goTo(BindDeviceActivity::class.java,null)
|
||||
}
|
||||
|
||||
//扫一扫:先申请相机和相册权限,授权通过后再拉起扫码页。
|
||||
// 扫码页仅使用相机,隐藏旧库内部的相册入口。
|
||||
R.id.img_scan -> {
|
||||
getMorePermissionRequst(
|
||||
scanPermissions(),
|
||||
"相机和相册权限",
|
||||
"扫一扫功能需要使用相机及访问相册权限",
|
||||
REQUEST_CAMERA_AND_ALBUM
|
||||
AddDevicePopupWindow(requireContext()).show(view,
|
||||
onManualAdd = {
|
||||
// 手动添加:进入绑定设备页
|
||||
goTo(BindDeviceActivity::class.java, null)
|
||||
},
|
||||
onScan = {
|
||||
// 扫一扫:先申请相机权限,授权后再打开扫码页
|
||||
getMorePermissionRequst(
|
||||
scanPermissions(),
|
||||
"相机权限",
|
||||
"扫一扫功能需要使用相机权限",
|
||||
REQUEST_CAMERA_AND_ALBUM
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -206,7 +228,7 @@ class DeviceFragment : BaseFragment<FragmentHomeBinding, DevicePresenter>(),
|
||||
}
|
||||
|
||||
|
||||
/** 相机和相册均已授权后,自动打开扫一扫。 */
|
||||
/** 相机授权后打开扫码页,库内相册按钮已关闭。 */
|
||||
override fun onPermissionsGranted(permissions: Array<String>) {
|
||||
startDeviceScan()
|
||||
}
|
||||
@@ -215,36 +237,50 @@ class DeviceFragment : BaseFragment<FragmentHomeBinding, DevicePresenter>(),
|
||||
super.onPermissionsDenied(permissions, permanentlyDenied)
|
||||
}
|
||||
|
||||
/** Android 13 及以上申请读图权限,更低版本申请存储读取权限。 */
|
||||
/** 相册入口已隐藏,因此扫码流程只需要相机权限。 */
|
||||
private fun scanPermissions(): Array<String> {
|
||||
val albumPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
return arrayOf(Manifest.permission.CAMERA, albumPermission)
|
||||
return arrayOf(Manifest.permission.CAMERA)
|
||||
}
|
||||
|
||||
/** 使用 MNMLKitScanner 默认扫码页识别二维码或条形码。 */
|
||||
private fun startDeviceScan() {
|
||||
MNScanManager.startScan(mContext, object : MNScanCallback {
|
||||
override fun onActivityResult(resultCode: Int, data: Intent) {
|
||||
when (resultCode) {
|
||||
MNScanManager.RESULT_SUCCESS -> {
|
||||
val results = data.getStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS)
|
||||
val content = results?.filter { it.isNotBlank() }?.joinToString("\n").orEmpty()
|
||||
val config = MNScanConfig.Builder()
|
||||
.isShowPhotoAlbum(false)
|
||||
.builder()
|
||||
|
||||
MNScanManager.startScan(mContext, config, object : MNScanCallback {
|
||||
override fun onActivityResult(resultCode: Int, data: Intent?) {
|
||||
if (!isAdded) {
|
||||
return
|
||||
}
|
||||
// 库把 RESULT_SUCCESS 定义为 0,和系统返回键的 RESULT_CANCELED 相同。
|
||||
// 点关闭会走 RESULT_CANCLE=2 并带回空 Intent;按返回键 data 为 null。
|
||||
when {
|
||||
resultCode == MNScanManager.RESULT_SUCCESS && data != null -> {
|
||||
val results = data.getStringArrayListExtra(
|
||||
MNScanManager.INTENT_KEY_RESULT_SUCCESS
|
||||
)
|
||||
val content = results
|
||||
?.filter { it.isNotBlank() }
|
||||
?.joinToString("\n")
|
||||
.orEmpty()
|
||||
if (content.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "未识别到内容")
|
||||
} else {
|
||||
ToastUtil.showShort(mContext, content)
|
||||
}
|
||||
}
|
||||
MNScanManager.RESULT_FAIL -> {
|
||||
val resultError = data.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR)
|
||||
ToastUtil.showShort(mContext, resultError.takeUnless { it.isNullOrBlank() } ?: "扫码失败")
|
||||
resultCode == MNScanManager.RESULT_FAIL -> {
|
||||
val resultError = data?.getStringExtra(
|
||||
MNScanManager.INTENT_KEY_RESULT_ERROR
|
||||
)
|
||||
ToastUtil.showShort(
|
||||
mContext,
|
||||
resultError.takeUnless { it.isNullOrBlank() } ?: "扫码失败"
|
||||
)
|
||||
}
|
||||
MNScanManager.RESULT_CANCLE -> {
|
||||
ToastUtil.showShort(mContext, getString(R.string.cancel_scan))
|
||||
else -> {
|
||||
// 关闭按钮或系统返回,按取消处理
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
package com.juhabi.birds.device.adapter
|
||||
|
||||
import android.widget.ProgressBar
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter
|
||||
import com.chad.library.adapter.base.viewholder.BaseViewHolder
|
||||
import com.juhabi.birds.R
|
||||
import com.juhabi.birds.device.entity.DeviceEntity
|
||||
|
||||
/** 临时设备列表适配器,后续可根据设计稿替换 item 展示。 */
|
||||
class DeviceAdapter : BaseQuickAdapter<DeviceEntity, BaseViewHolder>(R.layout.device_item) {
|
||||
init {
|
||||
addChildClickViewIds(R.id.img_more)
|
||||
}
|
||||
|
||||
override fun convert(holder: BaseViewHolder, item: DeviceEntity) {
|
||||
//设备名字
|
||||
holder.setText(R.id.tv_dev_name, item.name.ifBlank { "未命名设备" })
|
||||
//在线状态
|
||||
if (item.status == "1") {
|
||||
holder.setText(R.id.tv_dev_online_status, "在线")
|
||||
} else {
|
||||
holder.setText(R.id.tv_dev_online_status, "离线")
|
||||
}
|
||||
val statusRes = if (item.status == "1") {
|
||||
R.drawable.shape_device_online_bg
|
||||
} else {
|
||||
R.drawable.shape_device_offline_bg
|
||||
}
|
||||
holder.setBackgroundResource(
|
||||
R.id.tv_dev_online_status,
|
||||
statusRes
|
||||
)
|
||||
|
||||
holder.setText(R.id.tv_dev_number, "IMEI:${item.deviceNo}")
|
||||
|
||||
if (item.status == "1") {
|
||||
// 信号:0 离线、1 弱、2 一般、3 强。资源 id 必须赋给变量才会生效。
|
||||
val imgResource: Int
|
||||
val signalText: String
|
||||
val wifiTextColor: Int
|
||||
if (item.signalLevel == 0) {
|
||||
imgResource = R.mipmap.icon_dev_wifi_offline
|
||||
signalText = "离线"
|
||||
wifiTextColor = R.color.color_999999
|
||||
} else if (item.signalLevel == 1) {
|
||||
imgResource = R.mipmap.icon_dev_wifi_low
|
||||
signalText = "弱"
|
||||
wifiTextColor = R.color.color_e34d59
|
||||
} else if (item.signalLevel == 2) {
|
||||
imgResource = R.mipmap.icon_dev_wifi_mid
|
||||
signalText = "一般"
|
||||
wifiTextColor = R.color.color_ff942a
|
||||
} else {
|
||||
imgResource = R.mipmap.icon_dev_wifi_hight
|
||||
signalText = "强"
|
||||
wifiTextColor = R.color.color_zhu
|
||||
}
|
||||
|
||||
holder.setImageResource(R.id.img_signal, imgResource)
|
||||
holder.setText(R.id.tv_signal_text, signalText)
|
||||
holder.setTextColor(R.id.tv_signal_text,wifiTextColor)
|
||||
holder.setText(
|
||||
R.id.tv_head_foot_connect_status,
|
||||
if (item.hoodConnected == "0") "断开" else "已连接"
|
||||
)
|
||||
}else{
|
||||
holder.setImageResource(R.id.img_signal, R.mipmap.icon_dev_wifi_offline)
|
||||
holder.setText(R.id.tv_signal_text, "离线")
|
||||
holder.setTextColor(R.id.tv_signal_text, R.color.color_999999)
|
||||
holder.setText(
|
||||
R.id.tv_head_foot_connect_status,
|
||||
if (item.hoodConnected == "0") "断开" else "已连接"
|
||||
)
|
||||
}
|
||||
|
||||
holder.setText(R.id.tv_head_power_value, "${item.hoodBattery}%")
|
||||
holder.setText(R.id.tv_foot_power_value, "${item.ringBattery}%")
|
||||
|
||||
// 电量三档:0-30 低,31-70 中,71-100 高
|
||||
val headBattery = (item.hoodBattery ?: 0).coerceIn(0, 100)
|
||||
val footBattery = (item.ringBattery ?: 0).coerceIn(0, 100)
|
||||
val isOnline = item.status == "1"
|
||||
|
||||
if (isOnline) {
|
||||
holder.setImageResource(
|
||||
R.id.img_head_power_icon,
|
||||
getBatteryIcon(
|
||||
battery = headBattery,
|
||||
highIcon = R.mipmap.icon_power_head_high,
|
||||
midIcon = R.mipmap.icon_power_head_mid
|
||||
)
|
||||
)
|
||||
holder.setImageResource(
|
||||
R.id.img_foot_power_icon,
|
||||
getBatteryIcon(
|
||||
battery = footBattery,
|
||||
highIcon = R.mipmap.icon_power_foot_high,
|
||||
midIcon = R.mipmap.icon_power_foot_mid
|
||||
)
|
||||
)
|
||||
} else {
|
||||
// 离线时头套、脚环电量图标统一显示离线态
|
||||
holder.setImageResource(
|
||||
R.id.img_head_power_icon,
|
||||
R.mipmap.icon_dev_power_offline
|
||||
)
|
||||
holder.setImageResource(
|
||||
R.id.img_foot_power_icon,
|
||||
R.mipmap.icon_dev_power_offline
|
||||
)
|
||||
}
|
||||
|
||||
val progressHead = holder.getView<ProgressBar>(R.id.progress_head)
|
||||
val progressFoot = holder.getView<ProgressBar>(R.id.progress_foot)
|
||||
val headProgressRes = if (isOnline) {
|
||||
R.drawable.progress_head_bg
|
||||
} else {
|
||||
R.drawable.progress_offline_bg
|
||||
}
|
||||
val footProgressRes = if (isOnline) {
|
||||
R.drawable.progress_foot_bg
|
||||
} else {
|
||||
R.drawable.progress_offline_bg
|
||||
}
|
||||
// mutate 避免两条进度条共用同一份离线 drawable 状态
|
||||
progressHead.progressDrawable = ContextCompat.getDrawable(
|
||||
context,
|
||||
headProgressRes
|
||||
)?.mutate()
|
||||
progressFoot.progressDrawable = ContextCompat.getDrawable(
|
||||
context,
|
||||
footProgressRes
|
||||
)?.mutate()
|
||||
// 替换 drawable 后进度会被重置,需要重新写入
|
||||
progressHead.max = 100
|
||||
progressHead.progress = headBattery
|
||||
progressFoot.max = 100
|
||||
progressFoot.progress = footBattery
|
||||
|
||||
//tv_location_detail 显示地址
|
||||
holder.setText(R.id.tv_location_detail, item.address)
|
||||
}
|
||||
|
||||
/**
|
||||
* 按电量返回对应档位图标。
|
||||
* 低电量头套、脚环共用 icon_power_low。
|
||||
*/
|
||||
private fun getBatteryIcon(
|
||||
battery: Int,
|
||||
highIcon: Int,
|
||||
midIcon: Int
|
||||
): Int {
|
||||
return when {
|
||||
battery <= BATTERY_LOW_MAX -> R.mipmap.icon_power_low
|
||||
battery <= BATTERY_MID_MAX -> midIcon
|
||||
else -> highIcon
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val BATTERY_LOW_MAX = 30
|
||||
const val BATTERY_MID_MAX = 70
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,19 @@ 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,
|
||||
val hoodCoverOn: String
|
||||
val address: String = "",
|
||||
val deviceNo: String = "",
|
||||
val hoodBattery: Int? = null,
|
||||
val hoodConnected: String = "",
|
||||
val hoodConnectedText: String = "",
|
||||
val imei: String = "",
|
||||
val lat: String? = null,
|
||||
val lng: String? = null,
|
||||
val model: String? = null,
|
||||
val name: String = "",
|
||||
val ringBattery: Int? = null,
|
||||
val signalLevel: Int = 0,
|
||||
val signalText: String = "",
|
||||
val status: String = "",
|
||||
val hoodCoverOn: String = ""
|
||||
) : Serializable
|
||||
|
||||
Reference in New Issue
Block a user