From 3f42536710f47be00780697a216dcd667af9eb4f Mon Sep 17 00:00:00 2001
From: fengjignqi <15192412330@163.com>
Date: Sun, 20 Sep 2026 09:18:26 +0800
Subject: [PATCH] =?UTF-8?q?=E6=89=AB=E4=B8=80=E6=89=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/build.gradle | 8 +
app/src/main/AndroidManifest.xml | 12 +
.../com/juhabi/birds/device/DeviceAdapter.kt | 22 ++
.../birds/device/DeviceDetailActivity.kt | 89 +++++-
.../{IndexFragment.kt => DeviceFragment.kt} | 92 +++++-
.../birds/device/entity/DeviceEntity.kt | 3 +-
.../juhabi/birds/device/mvp/DeviceContract.kt | 55 ++++
.../com/juhabi/birds/device/mvp/DeviceImpl.kt | 276 ++++++++++++++++++
.../birds/device/mvp/DevicePresenter.kt | 166 +++++++++++
.../com/juhabi/birds/main/MainActivity.kt | 37 +--
.../juhabi/birds/mine/MineCenterActivity.kt | 18 +-
.../juhabi/birds/mine/ModifyPsdActivity.kt | 130 +++++++++
.../com/juhabi/birds/mine/mvp/MineContract.kt | 3 +
.../com/juhabi/birds/mine/mvp/MineImpl.kt | 44 +++
.../juhabi/birds/mine/mvp/MinePresenter.kt | 21 ++
.../com/juhabi/birds/network/ApiService.kt | 23 ++
app/src/main/res/layout/activity_main.xml | 12 -
.../main/res/layout/device_detail_layout.xml | 33 +++
app/src/main/res/layout/device_item.xml | 6 -
app/src/main/res/layout/fragment_home.xml | 26 +-
app/src/main/res/layout/modify_psd_layout.xml | 212 ++++++++++++++
.../main/res/layout/popup_device_action.xml | 53 ++++
.../main/res/menu/bottom_navigation_menu.xml | 10 -
app/src/main/res/values/strings.xml | 1 +
gradle.properties | 2 +-
25 files changed, 1258 insertions(+), 96 deletions(-)
create mode 100644 app/src/main/java/com/juhabi/birds/device/DeviceAdapter.kt
rename app/src/main/java/com/juhabi/birds/device/{IndexFragment.kt => DeviceFragment.kt} (64%)
create mode 100644 app/src/main/java/com/juhabi/birds/device/mvp/DeviceContract.kt
create mode 100644 app/src/main/java/com/juhabi/birds/device/mvp/DeviceImpl.kt
create mode 100644 app/src/main/java/com/juhabi/birds/device/mvp/DevicePresenter.kt
create mode 100644 app/src/main/java/com/juhabi/birds/mine/ModifyPsdActivity.kt
create mode 100644 app/src/main/res/layout/device_detail_layout.xml
create mode 100644 app/src/main/res/layout/modify_psd_layout.xml
create mode 100644 app/src/main/res/layout/popup_device_action.xml
diff --git a/app/build.gradle b/app/build.gradle
index e009301..73f18ca 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -70,4 +70,12 @@ dependencies {
implementation 'io.github.scwang90:refresh-layout-kernel:2.1.1'
implementation 'io.github.scwang90:refresh-header-classics:2.1.1'
implementation 'io.github.scwang90:refresh-footer-classics:2.1.1'
+
+ implementation 'com.github.maning0303:MNMLKitScanner:V1.0.4'
+ //下面版本自己控制,barcode-scanning>=17.0.2
+ implementation 'com.google.mlkit:barcode-scanning:17.0.2'
+ implementation "androidx.camera:camera-core:1.0.2"
+ implementation "androidx.camera:camera-camera2:1.0.2"
+ implementation "androidx.camera:camera-lifecycle:1.0.2"
+ implementation "androidx.camera:camera-view:1.0.0-alpha25"
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9e1cb4d..158d84d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -8,6 +8,10 @@
+
+
+
+
+
+
(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 ?: "暂无地址"}")
+ }
+}
diff --git a/app/src/main/java/com/juhabi/birds/device/DeviceDetailActivity.kt b/app/src/main/java/com/juhabi/birds/device/DeviceDetailActivity.kt
index 758de85..9238a7b 100644
--- a/app/src/main/java/com/juhabi/birds/device/DeviceDetailActivity.kt
+++ b/app/src/main/java/com/juhabi/birds/device/DeviceDetailActivity.kt
@@ -3,8 +3,11 @@ 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.databinding.DeviceDetailLayoutBinding
import com.juhabi.birds.device.entity.DeviceEntity
import com.juhabi.birds.device.mvp.DeviceContract
import com.juhabi.birds.device.mvp.DeviceImpl
@@ -13,28 +16,100 @@ import com.juhabi.birds.device.mvp.DevicePresenter
/**
* 设备详情
*/
-class DeviceDetailActivity: BaseActivity() , DeviceContract.DeviceView,
+class DeviceDetailActivity :
+ BaseActivity(), DeviceContract.DeviceView,
View.OnClickListener {
- override fun createBinding(inflater: LayoutInflater): BindDeviceLayoutBinding {
- return BindDeviceLayoutBinding.inflate(inflater)
+ companion object {
+ const val EXTRA_DEVICE = "extra_device"
+ const val HOOD_COVER_ON = "0"
+ const val HOOD_COVER_OFF = "1"
+ }
+
+ private var device: DeviceEntity? = null
+ override fun createBinding(inflater: LayoutInflater): DeviceDetailLayoutBinding {
+ return DeviceDetailLayoutBinding.inflate(inflater)
}
override fun createPresenter(): DevicePresenter? {
return DevicePresenter(DeviceImpl())
}
- override fun initView(savedInstanceState: Bundle?) {
+ override fun initWindows() {
+ ImmersionBar.with(this)
+ .statusBarView(binding.statusBarView)
+ .statusBarDarkFont(true)
+ .navigationBarColor(R.color.color_zhu)
+ .navigationBarDarkIcon(true)
+ .init()
}
+
+ override fun initView(savedInstanceState: Bundle?) {
+ device = intent.getSerializableExtra(EXTRA_DEVICE) as? DeviceEntity
+ binding.includedTitle.tvTitle.text = device?.name ?: "设备详情"
+ val deviceNo = device?.deviceNo
+ if (deviceNo.isNullOrBlank()) {
+ showError("设备信息无效")
+ } else {
+ presenter?.getDeviceDetail(deviceNo)
+ }
+
+ listOf(
+ binding.tvBind,
+ binding.switchCtrl,
+ binding.includedTitle.imgBack,
+ ).forEach { button ->
+ button.setOnClickListener(this)
+ }
+ }
+
+ override fun onClick(view: View) {
+ when(view.id){
+ R.id.img_back ->{
+ finish()
+ }
+ R.id.switch_ctrl ->{
+ if(device?.status == "0"){
+ showMessage("设备已经离线")
+ return;
+ }
+ val currentDevice = device ?: return
+ // hoodCoverOn:0 表示打开,1 表示关闭;点击后发送切换后的目标状态。
+ val coverOn = currentDevice.hoodCoverOn != HOOD_COVER_ON
+ presenter?.controlEye(currentDevice.deviceNo, coverOn)
+ }
+ }
+ }
+
+
+
override fun showError(message: String) {
}
override fun getBindDeviceListSuccess(devices: List) {
}
+ override fun getDeviceDetailSuccess(device: DeviceEntity) {
+ this.device = device
+ binding.includedTitle.tvTitle.text = device.name
+ binding.tvBind.text = "设备编号:${device.deviceNo}"
+ binding.switchCtrl.isChecked = device.hoodCoverOn == HOOD_COVER_ON
+ }
+
+ override fun controlEyeSuccess(message: String) {
+ showMessage(message)
+ device = device?.copy(
+ hoodCoverOn = if (binding.switchCtrl.isChecked) {
+ HOOD_COVER_ON
+ } else {
+ HOOD_COVER_OFF
+ }
+ )
+ }
+
override fun bindDeviceSuccess(message: String) {
}
- override fun onClick(view: View) {
- }
-}
\ No newline at end of file
+
+
+}
diff --git a/app/src/main/java/com/juhabi/birds/device/IndexFragment.kt b/app/src/main/java/com/juhabi/birds/device/DeviceFragment.kt
similarity index 64%
rename from app/src/main/java/com/juhabi/birds/device/IndexFragment.kt
rename to app/src/main/java/com/juhabi/birds/device/DeviceFragment.kt
index 795e720..2886094 100644
--- a/app/src/main/java/com/juhabi/birds/device/IndexFragment.kt
+++ b/app/src/main/java/com/juhabi/birds/device/DeviceFragment.kt
@@ -1,11 +1,13 @@
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.BaseActivity
import com.juhabi.birds.base.BaseFragment
import com.juhabi.birds.custom.DeviceActionPopupWindow
import com.juhabi.birds.custom.CustomRefreshHeader
@@ -14,12 +16,12 @@ 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.juhabi.birds.util.ToastUtil
+import com.maning.mlkitscanner.scan.MNScanManager
+import com.maning.mlkitscanner.scan.callback.act.MNScanCallback
import com.scwang.smart.refresh.footer.ClassicsFooter
-class IndexFragment : BaseFragment(),
+class DeviceFragment : BaseFragment(),
DeviceContract.DeviceView, View.OnClickListener {
private val deviceAdapter = DeviceAdapter()
@@ -37,10 +39,17 @@ class IndexFragment : BaseFragment(),
override fun initView(savedInstanceState: Bundle?) {
listOf(
binding.tvIndex,
+ binding.imgScan,
).forEach { button ->
button.setOnClickListener(this)
}
binding.rvDevices.adapter = deviceAdapter
+ deviceAdapter.setOnItemClickListener { _, _, position ->
+ val device = deviceAdapter.data[position]
+ goTo(DeviceDetailActivity::class.java, Bundle().apply {
+ putSerializable(DeviceDetailActivity.EXTRA_DEVICE, device)
+ })
+ }
deviceAdapter.setOnItemChildClickListener { adapter, view, position ->
when (view.id) {
R.id.img_tips -> {
@@ -102,6 +111,17 @@ class IndexFragment : BaseFragment(),
R.id.tv_index ->{
goTo(BindDeviceActivity::class.java,null)
}
+
+ //扫一扫:先申请相机和相册权限,授权通过后再拉起扫码页。
+ R.id.img_scan -> {
+ getMorePermissionRequst(
+ scanPermissions(),
+ "相机和相册权限",
+ "扫一扫功能需要使用相机及访问相册权限",
+ REQUEST_CAMERA_AND_ALBUM
+ )
+ }
+
}
}
@@ -168,17 +188,67 @@ class IndexFragment : BaseFragment(),
super.showError(message)
}
- /** 接口暂无数据时提供临时设备,方便先验收列表布局。 */
- private fun temporaryDevices(): List = 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
+ const val REQUEST_CAMERA_AND_ALBUM = 1001
+ }
+
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ }
+
+
+ /** 相机和相册均已授权后,自动打开扫一扫。 */
+ override fun onPermissionsGranted(permissions: Array) {
+ startDeviceScan()
+ }
+
+ override fun onPermissionsDenied(permissions: Array, permanentlyDenied: Boolean) {
+ super.onPermissionsDenied(permissions, permanentlyDenied)
+ }
+
+ /** Android 13 及以上申请读图权限,更低版本申请存储读取权限。 */
+ private fun scanPermissions(): Array {
+ 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)
+ }
+
+ /** 使用 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()
+ 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() } ?: "扫码失败")
+ }
+ MNScanManager.RESULT_CANCLE -> {
+ ToastUtil.showShort(mContext, getString(R.string.cancel_scan))
+ }
+ }
+ }
+ })
}
}
diff --git a/app/src/main/java/com/juhabi/birds/device/entity/DeviceEntity.kt b/app/src/main/java/com/juhabi/birds/device/entity/DeviceEntity.kt
index a6ccb1e..5802ead 100644
--- a/app/src/main/java/com/juhabi/birds/device/entity/DeviceEntity.kt
+++ b/app/src/main/java/com/juhabi/birds/device/entity/DeviceEntity.kt
@@ -16,5 +16,6 @@ data class DeviceEntity(
val ringBattery: Int?,
val signalLevel: Int,
val signalText: String,
- val status: String
+ val status: String,
+ val hoodCoverOn: String
) : Serializable
diff --git a/app/src/main/java/com/juhabi/birds/device/mvp/DeviceContract.kt b/app/src/main/java/com/juhabi/birds/device/mvp/DeviceContract.kt
new file mode 100644
index 0000000..b7dfb8f
--- /dev/null
+++ b/app/src/main/java/com/juhabi/birds/device/mvp/DeviceContract.kt
@@ -0,0 +1,55 @@
+package com.juhabi.birds.device.mvp
+
+import com.juhabi.birds.base.IView
+import com.juhabi.birds.device.entity.DeviceEntity
+import com.juhabi.birds.login.model.UserEntity
+import com.juhabi.birds.login.mvp.LoginContract
+import com.juhabi.birds.network.BaseBean
+import org.json.JSONObject
+
+interface DeviceContract {
+ interface Callback {
+ fun success(data: T)
+ fun fail(message: String)
+ }
+
+ interface DataModel {
+ /** 查询已绑定的设备列表。 */
+ fun getBindDeviceList(params: Map, callback: Callback>)
+ fun getDeviceDetail(deviceNo: String, callback: Callback)
+
+ /** 控制设备眼罩开关。 */
+ fun controlEye(deviceNo: String, coverOn: Boolean, callback: Callback>)
+
+ /** 根据 IMEI 和设备名称绑定设备。 */
+ fun bindDevice(json: JSONObject, callback: Callback>)
+
+ /** 根据设备编号修改设备名称。 */
+ fun renameDevice(
+ deviceNo: String,
+ json: JSONObject,
+ callback: Callback>
+ )
+
+ /** 根据设备编号解绑设备。 */
+ fun unbindDevice(deviceNo: String, callback: Callback>)
+
+ /** 取消设备模块中尚未完成的网络请求。 */
+ fun cancel()
+ }
+
+ interface DeviceView : IView {
+ fun getBindDeviceListSuccess(devices: List)
+ fun getDeviceDetailSuccess(device: DeviceEntity) {}
+ fun controlEyeSuccess(message: String) {}
+ fun bindDeviceSuccess(message: String)
+
+ /** 设备重命名成功回调,不关心该事件的页面可以不实现。 */
+ fun renameDeviceSuccess(message: String) {
+ }
+
+ /** 设备解绑成功回调,不关心该事件的页面可以不实现。 */
+ fun unbindDeviceSuccess(message: String) {
+ }
+ }
+}
diff --git a/app/src/main/java/com/juhabi/birds/device/mvp/DeviceImpl.kt b/app/src/main/java/com/juhabi/birds/device/mvp/DeviceImpl.kt
new file mode 100644
index 0000000..e17c390
--- /dev/null
+++ b/app/src/main/java/com/juhabi/birds/device/mvp/DeviceImpl.kt
@@ -0,0 +1,276 @@
+package com.juhabi.birds.device.mvp
+
+import android.os.Handler
+import android.os.Looper
+import com.juhabi.birds.device.entity.DeviceEntity
+import com.juhabi.birds.network.ApiClient
+import com.juhabi.birds.network.BaseBean
+import com.juhabi.birds.network.NetworkManager
+import org.json.JSONObject
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+
+class DeviceImpl : DeviceContract.DataModel {
+ private val mainHandler = Handler(Looper.getMainLooper())
+ private var deviceListCall: Call>>? = null
+ private var deviceDetailCall: Call>? = null
+ private var controlEyeCall: Call>? = null
+ private var bindDeviceCall: Call>? = null
+ private var renameDeviceCall: Call>? = null
+ private var unbindDeviceCall: Call>? = null
+
+ /** 请求当前账号已绑定的设备列表。 */
+ override fun getBindDeviceList(params: Map, callback: DeviceContract.Callback>) {
+ deviceListCall?.cancel()
+ deviceListCall = ApiClient.apiService
+ .getBindDeviceList(NetworkManager.getToken(), params)
+ .also { call ->
+ call.enqueue(object : Callback>> {
+ override fun onResponse(
+ call: Call>>,
+ response: Response>>
+ ) {
+ mainHandler.post {
+ val bean = response.body()
+ val devices = bean?.rows ?: bean?.data
+ if (
+ response.isSuccessful &&
+ (bean?.code == 0 || bean?.code == 200) &&
+ devices != null
+ ) {
+ callback.success(devices)
+ } else {
+ callback.fail(
+ bean?.message?.ifBlank { null } ?: "获取设备列表失败"
+ )
+ }
+ }
+ }
+
+ override fun onFailure(
+ call: Call>>,
+ error: Throwable
+ ) {
+ if (!call.isCanceled) {
+ mainHandler.post {
+ callback.fail(error.message ?: "网络请求失败")
+ }
+ }
+ }
+ })
+ }
+ }
+
+ override fun getDeviceDetail(
+ deviceNo: String,
+ callback: DeviceContract.Callback
+ ) {
+ deviceDetailCall?.cancel()
+ deviceDetailCall = ApiClient.apiService
+ .getDeviceDetail(NetworkManager.getToken(), deviceNo)
+ .also { call ->
+ call.enqueue(object : Callback> {
+ override fun onResponse(
+ call: Call>,
+ response: Response>
+ ) {
+ mainHandler.post {
+ val bean = response.body()
+ val device = bean?.data
+ if (
+ response.isSuccessful &&
+ (bean?.code == 0 || bean?.code == 200) &&
+ device != null
+ ) {
+ callback.success(device)
+ } else {
+ callback.fail(
+ bean?.message?.ifBlank { null } ?: "获取设备详情失败"
+ )
+ }
+ }
+ }
+
+ override fun onFailure(
+ call: Call>,
+ error: Throwable
+ ) {
+ if (!call.isCanceled) {
+ mainHandler.post {
+ callback.fail(error.message ?: "网络请求失败")
+ }
+ }
+ }
+ })
+ }
+ }
+
+ /** 请求服务端控制设备眼罩开关。 */
+ override fun controlEye(
+ deviceNo: String,
+ coverOn: Boolean,
+ callback: DeviceContract.Callback>
+ ) {
+ controlEyeCall?.cancel()
+ val json = JSONObject().apply {
+ put("deviceNo", deviceNo)
+ put("coverOn", coverOn)
+ }
+ controlEyeCall = ApiClient.apiService
+ .controlEye(NetworkManager.getToken(), deviceNo, NetworkManager.toRequestBody(json))
+ .also { call ->
+ call.enqueue(object : Callback> {
+ override fun onResponse(
+ call: Call>,
+ response: Response>
+ ) {
+ mainHandler.post {
+ val bean = response.body()
+ if (response.isSuccessful && (bean?.code == 0 || bean?.code == 200)) {
+ callback.success(bean)
+ } else {
+ callback.fail(bean?.message?.ifBlank { null } ?: "控制眼罩失败")
+ }
+ }
+ }
+
+ override fun onFailure(call: Call>, error: Throwable) {
+ if (!call.isCanceled) {
+ mainHandler.post {
+ callback.fail(error.message ?: "网络请求失败")
+ }
+ }
+ }
+ })
+ }
+ }
+
+ /** 将设备 IMEI 和名称提交到服务器完成绑定。 */
+ override fun bindDevice(
+ json: JSONObject,
+ callback: DeviceContract.Callback>
+ ) {
+ bindDeviceCall?.cancel()
+ bindDeviceCall = ApiClient.apiService
+ .bindDevice(NetworkManager.getToken(), NetworkManager.toRequestBody(json))
+ .also { call ->
+ call.enqueue(object : Callback> {
+ override fun onResponse(
+ call: Call>,
+ response: Response>
+ ) {
+ mainHandler.post {
+ val bean = response.body()
+ if (
+ response.isSuccessful &&
+ (bean?.code == 0 || bean?.code == 200)
+ ) {
+ callback.success(bean)
+ } else {
+ callback.fail(
+ bean?.message?.ifBlank { null } ?: "绑定设备失败"
+ )
+ }
+ }
+ }
+
+ override fun onFailure(call: Call>, error: Throwable) {
+ if (!call.isCanceled) {
+ mainHandler.post {
+ callback.fail(error.message ?: "网络请求失败")
+ }
+ }
+ }
+ })
+ }
+ }
+
+ /** 将新的设备名称提交到服务器。 */
+ override fun renameDevice(
+ deviceNo: String,
+ json: JSONObject,
+ callback: DeviceContract.Callback>
+ ) {
+ renameDeviceCall?.cancel()
+ renameDeviceCall = ApiClient.apiService
+ .deviceRename(deviceNo = deviceNo, headers = NetworkManager.getToken(), requestBody = NetworkManager.toRequestBody(json))
+ .also { call ->
+ call.enqueue(object : Callback> {
+ override fun onResponse(
+ call: Call>,
+ response: Response>
+ ) {
+ mainHandler.post {
+ val bean = response.body()
+ if (response.isSuccessful && (bean?.code == 0 || bean?.code == 200)) {
+ callback.success(bean)
+ } else {
+ callback.fail(bean?.message?.ifBlank { null } ?: "设备重命名失败")
+ }
+ }
+ }
+
+ override fun onFailure(call: Call>, error: Throwable) {
+ if (!call.isCanceled) {
+ mainHandler.post {
+ callback.fail(error.message ?: "网络请求失败")
+ }
+ }
+ }
+ })
+ }
+ }
+
+ /** 按设备编号请求服务端解绑。 */
+ override fun unbindDevice(
+ deviceNo: String,
+ callback: DeviceContract.Callback>
+ ) {
+ unbindDeviceCall?.cancel()
+ unbindDeviceCall = ApiClient.apiService
+ .unbindDevice(headers = NetworkManager.getToken(), deviceNo = deviceNo)
+ .also { call ->
+ call.enqueue(object : Callback> {
+ override fun onResponse(
+ call: Call>,
+ response: Response>
+ ) {
+ mainHandler.post {
+ val bean = response.body()
+ if (response.isSuccessful && (bean?.code == 0 || bean?.code == 200)) {
+ callback.success(bean)
+ } else {
+ callback.fail(bean?.message?.ifBlank { null } ?: "设备解绑失败")
+ }
+ }
+ }
+
+ override fun onFailure(call: Call>, error: Throwable) {
+ if (!call.isCanceled) {
+ mainHandler.post {
+ callback.fail(error.message ?: "网络请求失败")
+ }
+ }
+ }
+ })
+ }
+ }
+
+ /** 取消所有设备请求并清理主线程回调。 */
+ override fun cancel() {
+ deviceListCall?.cancel()
+ deviceListCall = null
+ deviceDetailCall?.cancel()
+ deviceDetailCall = null
+ controlEyeCall?.cancel()
+ controlEyeCall = null
+ bindDeviceCall?.cancel()
+ bindDeviceCall = null
+ renameDeviceCall?.cancel()
+ renameDeviceCall = null
+ unbindDeviceCall?.cancel()
+ unbindDeviceCall = null
+ mainHandler.removeCallbacksAndMessages(null)
+ }
+}
diff --git a/app/src/main/java/com/juhabi/birds/device/mvp/DevicePresenter.kt b/app/src/main/java/com/juhabi/birds/device/mvp/DevicePresenter.kt
new file mode 100644
index 0000000..e8fc9f1
--- /dev/null
+++ b/app/src/main/java/com/juhabi/birds/device/mvp/DevicePresenter.kt
@@ -0,0 +1,166 @@
+package com.juhabi.birds.device.mvp
+
+import com.juhabi.birds.base.BasePresenter
+import com.juhabi.birds.device.entity.DeviceEntity
+import com.juhabi.birds.network.BaseBean
+import org.json.JSONObject
+
+class DevicePresenter(
+ private val deviceImpl: DeviceImpl
+) : BasePresenter() {
+
+ /** 获取当前账号已经绑定的设备列表。 */
+ fun getBindDeviceList(params: Map = emptyMap()) {
+ val currentView = view ?: return
+ currentView.showLoading()
+ deviceImpl.getBindDeviceList(params, object : DeviceContract.Callback> {
+ override fun success(data: List) {
+ view?.apply {
+ hideLoading()
+ getBindDeviceListSuccess(data)
+ }
+ }
+
+ override fun fail(message: String) {
+ view?.apply {
+ hideLoading()
+ showError(message)
+ }
+ }
+ }
+ )
+ }
+
+ /**
+ * 获取设备详情
+ */
+ fun getDeviceDetail(deviceNo: String) {
+ val currentView = view ?: return
+ currentView.showLoading()
+ deviceImpl.getDeviceDetail(
+ deviceNo,
+ object : DeviceContract.Callback {
+ override fun success(data: DeviceEntity) {
+ view?.apply {
+ hideLoading()
+ getDeviceDetailSuccess(data)
+ }
+ }
+
+ override fun fail(message: String) {
+ view?.apply {
+ hideLoading()
+ showError(message)
+ }
+ }
+ }
+ )
+ }
+
+ /** 根据目标状态控制设备眼罩开关。 */
+ fun controlEye(deviceNo: String, coverOn: Boolean) {
+ val currentView = view ?: return
+ currentView.showLoading()
+ deviceImpl.controlEye(deviceNo, coverOn, object : DeviceContract.Callback> {
+ override fun success(data: BaseBean) {
+ view?.apply {
+ hideLoading()
+ controlEyeSuccess(data.message.ifBlank { "眼罩状态已更新" })
+ }
+ }
+
+ override fun fail(message: String) {
+ view?.apply {
+ hideLoading()
+ showError(message)
+ }
+ }
+ })
+ }
+
+ /** 使用设备 IMEI 和名称发起绑定请求。 */
+ fun bindDevice(imei: String, name: String) {
+ val currentView = view ?: return
+ currentView.showLoading()
+ val json = JSONObject().apply {
+ put("imei", imei)
+ put("name", name)
+ }
+ deviceImpl.bindDevice(json, object : DeviceContract.Callback> {
+ override fun success(data: BaseBean) {
+ view?.apply {
+ hideLoading()
+ bindDeviceSuccess(data.message.ifBlank { "设备绑定成功" })
+ }
+ }
+
+ override fun fail(message: String) {
+ view?.apply {
+ hideLoading()
+ showError(message)
+ }
+ }
+ })
+ }
+
+ /** 根据设备编号修改设备名称。 */
+ fun renameDevice(deviceNo: String, name: String) {
+ val currentView = view ?: return
+ val trimmedName = name.trim()
+ if (deviceNo.isBlank() || trimmedName.isBlank()) {
+ currentView.showError("设备编号和名称不能为空")
+ return
+ }
+ currentView.showLoading()
+ val json = JSONObject().apply {
+ put("deviceNo", deviceNo)
+ put("name", trimmedName)
+ }
+ deviceImpl.renameDevice(deviceNo, json, object : DeviceContract.Callback> {
+ override fun success(data: BaseBean) {
+ view?.apply {
+ hideLoading()
+ renameDeviceSuccess(data.message.ifBlank { "设备重命名成功" })
+ }
+ }
+
+ override fun fail(message: String) {
+ view?.apply {
+ hideLoading()
+ showError(message)
+ }
+ }
+ })
+ }
+
+ /** 根据设备编号发起解绑请求。 */
+ fun unbindDevice(deviceNo: String) {
+ val currentView = view ?: return
+ if (deviceNo.isBlank()) {
+ currentView.showError("设备编号不能为空")
+ return
+ }
+ currentView.showLoading()
+ deviceImpl.unbindDevice(deviceNo, object : DeviceContract.Callback> {
+ override fun success(data: BaseBean) {
+ view?.apply {
+ hideLoading()
+ unbindDeviceSuccess(data.message.ifBlank { "设备解绑成功" })
+ }
+ }
+
+ override fun fail(message: String) {
+ view?.apply {
+ hideLoading()
+ showError(message)
+ }
+ }
+ })
+ }
+
+ /** 销毁页面时取消设备模块发起的网络请求。 */
+ override fun onDestroy() {
+ deviceImpl.cancel()
+ super.onDestroy()
+ }
+}
diff --git a/app/src/main/java/com/juhabi/birds/main/MainActivity.kt b/app/src/main/java/com/juhabi/birds/main/MainActivity.kt
index 3d6d159..d68f1b5 100644
--- a/app/src/main/java/com/juhabi/birds/main/MainActivity.kt
+++ b/app/src/main/java/com/juhabi/birds/main/MainActivity.kt
@@ -2,17 +2,14 @@ package com.juhabi.birds.main
import android.os.Bundle
import android.view.LayoutInflater
-import android.view.View
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
import com.juhabi.birds.R
import com.juhabi.birds.base.BaseActivity
import com.juhabi.birds.databinding.ActivityMainBinding
import com.juhabi.birds.main.adapter.MainPagerAdapter
-import com.juhabi.birds.main.fragment.HistoryFragment
-import com.juhabi.birds.device.IndexFragment
+import com.juhabi.birds.device.DeviceFragment
import com.juhabi.birds.mine.MineFragment
-import com.juhabi.birds.main.fragment.PlanFragment
import com.juhabi.birds.main.model.AppVersionInfo
import com.juhabi.birds.main.mvp.MainContract
import com.juhabi.birds.main.mvp.MainImpl
@@ -42,7 +39,7 @@ class MainActivity : BaseActivity(),
override fun initView(savedInstanceState: Bundle?) {
binding.viewPager.adapter = MainPagerAdapter(
this,
- listOf(IndexFragment(), PlanFragment(), HistoryFragment(), MineFragment())
+ listOf(DeviceFragment(), MineFragment())
)
binding.viewPager.offscreenPageLimit = 1
binding.viewPager.registerOnPageChangeCallback(object : androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback() {
@@ -60,8 +57,6 @@ class MainActivity : BaseActivity(),
private fun onNavigationItemSelected(itemId: Int): Boolean {
return when (itemId) {
R.id.navigation_home -> onHomeSelected()
- R.id.navigation_plan -> onPlanSelected()
- R.id.navigation_history -> onHistorySelected()
R.id.navigation_mine -> onMineSelected()
else -> false
}
@@ -69,25 +64,11 @@ class MainActivity : BaseActivity(),
private fun onHomeSelected(): Boolean {
switchPage(PAGE_HOME)
- // Add Home-specific status bar, refresh, or Fragment communication here.
- return true
- }
-
- private fun onPlanSelected(): Boolean {
- switchPage(PAGE_PLAN)
- // Add Plan-specific status bar, refresh, or Fragment communication here.
- return true
- }
-
- private fun onHistorySelected(): Boolean {
- switchPage(PAGE_HISTORY)
- // Add History-specific status bar, refresh, or Fragment communication here.
return true
}
private fun onMineSelected(): Boolean {
switchPage(PAGE_MINE)
- // Add Mine-specific status bar, refresh, or Fragment communication here.
return true
}
@@ -99,18 +80,8 @@ class MainActivity : BaseActivity(),
}
private fun updateTopBarColor(position: Int) {
- if (position == PAGE_PLAN) {
- binding.immersiveTopImageView.visibility = View.VISIBLE
- binding.statusBarView.setBackgroundColor(
- ContextCompat.getColor(this, android.R.color.transparent)
- )
- return
- }
-
- binding.immersiveTopImageView.visibility = View.GONE
@ColorRes val colorRes = when (position) {
PAGE_HOME -> R.color.color_zhu
- PAGE_HISTORY -> R.color.color_E9A01C
PAGE_MINE -> R.color.color_B85CE6
else -> R.color.color_zhu
}
@@ -131,8 +102,6 @@ class MainActivity : BaseActivity(),
private companion object {
const val PAGE_HOME = 0
- const val PAGE_PLAN = 1
- const val PAGE_HISTORY = 2
- const val PAGE_MINE = 3
+ const val PAGE_MINE = 1
}
}
diff --git a/app/src/main/java/com/juhabi/birds/mine/MineCenterActivity.kt b/app/src/main/java/com/juhabi/birds/mine/MineCenterActivity.kt
index 97a65a2..7b976cc 100644
--- a/app/src/main/java/com/juhabi/birds/mine/MineCenterActivity.kt
+++ b/app/src/main/java/com/juhabi/birds/mine/MineCenterActivity.kt
@@ -167,14 +167,6 @@ class MineCenterActivity : BaseActivity,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- appUpdateManager.onRequestPermissionsResult(requestCode, grantResults)
- }
/**
* 日期、时间和日期时间共用同一个组件调用入口。
@@ -211,6 +203,16 @@ class MineCenterActivity : BaseActivity,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ appUpdateManager.onRequestPermissionsResult(requestCode, grantResults)
+ }
+
+
override fun onPermissionsGranted(permissions: Array) {
showMessage("权限获取成功:${permissions.joinToString { it.substringAfterLast('.') }}")
}
diff --git a/app/src/main/java/com/juhabi/birds/mine/ModifyPsdActivity.kt b/app/src/main/java/com/juhabi/birds/mine/ModifyPsdActivity.kt
new file mode 100644
index 0000000..94f2870
--- /dev/null
+++ b/app/src/main/java/com/juhabi/birds/mine/ModifyPsdActivity.kt
@@ -0,0 +1,130 @@
+package com.juhabi.birds.mine
+
+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.ActivityMineCenterBinding
+import com.juhabi.birds.databinding.ModifyPsdLayoutBinding
+import com.juhabi.birds.main.model.AppVersionInfo
+import com.juhabi.birds.mine.model.MineUserInfo
+import com.juhabi.birds.mine.mvp.MineContract
+import com.juhabi.birds.mine.mvp.MineImpl
+import com.juhabi.birds.mine.mvp.MinePresenter
+import com.juhabi.birds.util.ToastUtil
+
+/**
+ * 旧密码,修改新密码
+ */
+class ModifyPsdActivity : BaseActivity(),
+ MineContract.MineView, View.OnClickListener {
+ override fun createBinding(inflater: LayoutInflater): ModifyPsdLayoutBinding {
+ return ModifyPsdLayoutBinding.inflate(inflater)
+ }
+
+ override fun createPresenter(): MinePresenter? {
+ return MinePresenter(MineImpl())
+ }
+
+ override fun initWindows() {
+ ImmersionBar.with(this)
+ .statusBarView(binding.statusBarView)
+ .statusBarDarkFont(true)
+ .navigationBarColor(R.color.color_zhu)
+ .navigationBarDarkIcon(true)
+ .init()
+ }
+
+
+ override fun initView(savedInstanceState: Bundle?) {
+ listOf(
+ binding.oldPsdVisibilityButton,
+ binding.passwordVisibilityButton,
+ binding.confirmPasswordVisibilityButton,
+ binding.confirmButton,
+ binding.includedTitle.imgBack,
+ ).forEach { button ->
+ button.setOnClickListener(this)
+ }
+ }
+
+ override fun onClick(view: View) {
+ when(view.id){
+ R.id.img_back ->{
+ finish()
+ }
+
+ R.id.confirmButton ->{//确认修改
+ val oldPassword = binding.oldPasswordEditText.text.toString()
+ val newPassword = binding.passwordEditText.text.toString()
+ val confirmPassword = binding.confirmPasswordEditText.text.toString()
+
+ // 按顺序校验输入项,避免无效数据提交到服务端。
+ if (oldPassword.isBlank()) {
+ ToastUtil.showShort(mContext, "当前密码不能为空")
+ return
+ }
+ if (newPassword.isBlank()) {
+ ToastUtil.showShort(mContext, "新密码不能为空")
+ return
+ }
+ if (confirmPassword.isBlank()) {
+ ToastUtil.showShort(mContext, "请再次输入新密码")
+ return
+ }
+ if (oldPassword == newPassword) {
+ ToastUtil.showShort(mContext, "新密码不能与当前密码相同")
+ return
+ }
+ if (newPassword != confirmPassword) {
+ ToastUtil.showShort(mContext, "两次输入的新密码不一致")
+ return
+ }
+ if (!isValidPassword(newPassword)) {
+ ToastUtil.showShort(mContext, "密码需为8-20位,且包含大小写字母和数字")
+ return
+ }
+
+ presenter?.modifyPassword(oldPassword, newPassword)
+
+ }
+
+
+ }
+ }
+
+
+ override fun showError(message: String) {
+ hideLoading()
+ ToastUtil.showShort(mContext, message)
+ }
+
+ override fun onModifyPasswordSuccess(message: String) {
+ hideLoading()
+ ToastUtil.showShort(mContext, message.ifBlank { "密码修改成功" })
+ finish()
+ }
+
+ /** 8-20 位,且同时包含大写、小写字母和数字。 */
+ private fun isValidPassword(password: String): Boolean {
+ if (password.length !in PASSWORD_MIN_LENGTH..PASSWORD_MAX_LENGTH) return false
+ return password.any { it.isUpperCase() } &&
+ password.any { it.isLowerCase() } &&
+ password.any { it.isDigit() }
+ }
+
+ private companion object {
+ const val PASSWORD_MIN_LENGTH = 8
+ const val PASSWORD_MAX_LENGTH = 20
+ }
+
+ override fun getUserInfoSuccess(userInfo: MineUserInfo) {
+ }
+
+ override fun onVersionChecked(versionInfo: AppVersionInfo) {
+ }
+
+
+}
diff --git a/app/src/main/java/com/juhabi/birds/mine/mvp/MineContract.kt b/app/src/main/java/com/juhabi/birds/mine/mvp/MineContract.kt
index 802b874..434b525 100644
--- a/app/src/main/java/com/juhabi/birds/mine/mvp/MineContract.kt
+++ b/app/src/main/java/com/juhabi/birds/mine/mvp/MineContract.kt
@@ -16,11 +16,14 @@ interface MineContract {
params: Map,
callback: Callback
)
+ fun modifyPassword(oldPassword: String, newPassword: String, callback: Callback)
fun cancel()
}
interface MineView : IView {
fun getUserInfoSuccess(userInfo: MineUserInfo)
fun onVersionChecked(versionInfo: AppVersionInfo)
+ /** 修改密码成功回调,非修改密码页面无需处理。 */
+ fun onModifyPasswordSuccess(message: String) {}
}
}
diff --git a/app/src/main/java/com/juhabi/birds/mine/mvp/MineImpl.kt b/app/src/main/java/com/juhabi/birds/mine/mvp/MineImpl.kt
index bfa92a3..931e0f3 100644
--- a/app/src/main/java/com/juhabi/birds/mine/mvp/MineImpl.kt
+++ b/app/src/main/java/com/juhabi/birds/mine/mvp/MineImpl.kt
@@ -10,11 +10,13 @@ import com.juhabi.birds.network.NetworkManager
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
+import org.json.JSONObject
class MineImpl : MineContract.DataModel {
private val mainHandler = Handler(Looper.getMainLooper())
private var userInfoCall: Call>? = null
private var versionCall: Call>? = null
+ private var modifyPasswordCall: Call>? = null
override fun getUserInfo(
params: Map,
@@ -96,11 +98,53 @@ class MineImpl : MineContract.DataModel {
}
}
+ /**
+ * 通过旧密码修改原密码
+ */
+ override fun modifyPassword(
+ oldPassword: String,
+ newPassword: String,
+ callback: MineContract.Callback
+ ) {
+ modifyPasswordCall?.cancel()
+ val requestBody = JSONObject().apply {
+ put("oldPassword", oldPassword)
+ put("newPassword", newPassword)
+ }
+ modifyPasswordCall = ApiClient.apiService
+ .modifyPassword(NetworkManager.getToken(), NetworkManager.toRequestBody(requestBody))
+ .also { call ->
+ call.enqueue(object : Callback> {
+ override fun onResponse(
+ call: Call>,
+ response: Response>
+ ) {
+ mainHandler.post {
+ val bean = response.body()
+ if (response.isSuccessful && bean?.code == 200) {
+ callback.success(bean.message.orEmpty())
+ } else {
+ callback.fail(bean?.message?.ifBlank { null } ?: "密码修改失败")
+ }
+ }
+ }
+
+ override fun onFailure(call: Call>, error: Throwable) {
+ if (!call.isCanceled) {
+ mainHandler.post { callback.fail(error.message ?: "网络请求失败") }
+ }
+ }
+ })
+ }
+ }
+
override fun cancel() {
userInfoCall?.cancel()
userInfoCall = null
versionCall?.cancel()
versionCall = null
+ modifyPasswordCall?.cancel()
+ modifyPasswordCall = null
mainHandler.removeCallbacksAndMessages(null)
}
}
diff --git a/app/src/main/java/com/juhabi/birds/mine/mvp/MinePresenter.kt b/app/src/main/java/com/juhabi/birds/mine/mvp/MinePresenter.kt
index daf793e..b383613 100644
--- a/app/src/main/java/com/juhabi/birds/mine/mvp/MinePresenter.kt
+++ b/app/src/main/java/com/juhabi/birds/mine/mvp/MinePresenter.kt
@@ -46,6 +46,27 @@ class MinePresenter(private val mineImpl: MineImpl) : BasePresenter {
+ override fun success(data: String) {
+ view?.apply {
+ hideLoading()
+ onModifyPasswordSuccess(data)
+ }
+ }
+
+ override fun fail(message: String) {
+ view?.apply {
+ hideLoading()
+ showError(message)
+ }
+ }
+ })
+ }
+
override fun onDestroy() {
mineImpl.cancel()
super.onDestroy()
diff --git a/app/src/main/java/com/juhabi/birds/network/ApiService.kt b/app/src/main/java/com/juhabi/birds/network/ApiService.kt
index b4d88c2..e661577 100644
--- a/app/src/main/java/com/juhabi/birds/network/ApiService.kt
+++ b/app/src/main/java/com/juhabi/birds/network/ApiService.kt
@@ -126,6 +126,15 @@ interface ApiService {
fun getBindDeviceList(@HeaderMap headers: Map, @QueryMap params: Map): Call>>
+ /**
+ * 获取设备详情
+ *
+ */
+ @GET("app/device/{deviceNo}")
+ fun getDeviceDetail(@HeaderMap headers: Map, @Path("deviceNo") deviceNo: String): Call>
+
+
+
/**
* 绑定设备
{
@@ -173,6 +182,20 @@ interface ApiService {
fun getMineUserInfo(@HeaderMap headers: Map, @QueryMap params: Map): Call>
+
+ /**
+ * 通过旧密码修改新密码
+ {
+ "oldPassword": "string",
+ "newPassword": "string"
+ }
+ */
+ @PUT("app/user/password")
+ fun modifyPassword(@HeaderMap headers: Map, @Body requestBody: RequestBody): Call>
+
+
+
+
@GET("app/v1/checkVersion")
fun checkVersionCode(@HeaderMap headers: Map, @QueryMap params: Map): Call>
}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index bfe34c9..b783ea9 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -4,18 +4,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/device_item.xml b/app/src/main/res/layout/device_item.xml
index bc63ddf..925b1bf 100644
--- a/app/src/main/res/layout/device_item.xml
+++ b/app/src/main/res/layout/device_item.xml
@@ -20,12 +20,6 @@
android:src="@mipmap/ic_launcher"
android:layout_gravity="end"/>
-
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index b04312b..efda55c 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -14,13 +14,27 @@
android:id="@+id/included_title"
layout="@layout/include_title_home_layout" />
-
+ android:orientation="horizontal">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/popup_device_action.xml b/app/src/main/res/layout/popup_device_action.xml
new file mode 100644
index 0000000..9b50f95
--- /dev/null
+++ b/app/src/main/res/layout/popup_device_action.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/bottom_navigation_menu.xml b/app/src/main/res/menu/bottom_navigation_menu.xml
index f146994..16f21a1 100644
--- a/app/src/main/res/menu/bottom_navigation_menu.xml
+++ b/app/src/main/res/menu/bottom_navigation_menu.xml
@@ -4,16 +4,6 @@
android:id="@+id/navigation_home"
android:icon="@drawable/ic_nav_home"
android:title="@string/tab_home" />
-
-
- 首页
重命名
解绑设备
+ 取消扫码
计划
历史
我的
diff --git a/gradle.properties b/gradle.properties
index 837592e..eecc11d 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,7 +6,7 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. For more details, visit
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects