扫一扫
This commit is contained in:
@@ -70,4 +70,12 @@ dependencies {
|
|||||||
implementation 'io.github.scwang90:refresh-layout-kernel:2.1.1'
|
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-header-classics:2.1.1'
|
||||||
implementation 'io.github.scwang90:refresh-footer-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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||||
|
android:maxSdkVersion="32" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".MyApplication"
|
android:name=".MyApplication"
|
||||||
@@ -69,6 +73,14 @@
|
|||||||
android:name=".device.BindDeviceActivity"
|
android:name=".device.BindDeviceActivity"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".device.DeviceDetailActivity"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".mine.ModifyPsdActivity"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
|
|||||||
22
app/src/main/java/com/juhabi/birds/device/DeviceAdapter.kt
Normal file
22
app/src/main/java/com/juhabi/birds/device/DeviceAdapter.kt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
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 ?: "暂无地址"}")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,8 +3,11 @@ package com.juhabi.birds.device
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import com.gyf.immersionbar.ImmersionBar
|
||||||
|
import com.juhabi.birds.R
|
||||||
import com.juhabi.birds.base.BaseActivity
|
import com.juhabi.birds.base.BaseActivity
|
||||||
import com.juhabi.birds.databinding.BindDeviceLayoutBinding
|
import com.juhabi.birds.databinding.BindDeviceLayoutBinding
|
||||||
|
import com.juhabi.birds.databinding.DeviceDetailLayoutBinding
|
||||||
import com.juhabi.birds.device.entity.DeviceEntity
|
import com.juhabi.birds.device.entity.DeviceEntity
|
||||||
import com.juhabi.birds.device.mvp.DeviceContract
|
import com.juhabi.birds.device.mvp.DeviceContract
|
||||||
import com.juhabi.birds.device.mvp.DeviceImpl
|
import com.juhabi.birds.device.mvp.DeviceImpl
|
||||||
@@ -13,28 +16,100 @@ import com.juhabi.birds.device.mvp.DevicePresenter
|
|||||||
/**
|
/**
|
||||||
* 设备详情
|
* 设备详情
|
||||||
*/
|
*/
|
||||||
class DeviceDetailActivity: BaseActivity<BindDeviceLayoutBinding, DevicePresenter>() , DeviceContract.DeviceView,
|
class DeviceDetailActivity :
|
||||||
|
BaseActivity<DeviceDetailLayoutBinding, DevicePresenter>(), DeviceContract.DeviceView,
|
||||||
View.OnClickListener {
|
View.OnClickListener {
|
||||||
override fun createBinding(inflater: LayoutInflater): BindDeviceLayoutBinding {
|
companion object {
|
||||||
return BindDeviceLayoutBinding.inflate(inflater)
|
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? {
|
override fun createPresenter(): DevicePresenter? {
|
||||||
return DevicePresenter(DeviceImpl())
|
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 showError(message: String) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getBindDeviceListSuccess(devices: List<DeviceEntity>) {
|
override fun getBindDeviceListSuccess(devices: List<DeviceEntity>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 bindDeviceSuccess(message: String) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClick(view: View) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
package com.juhabi.birds.device
|
package com.juhabi.birds.device
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import com.juhabi.birds.R
|
import com.juhabi.birds.R
|
||||||
import com.juhabi.birds.base.BaseActivity
|
|
||||||
import com.juhabi.birds.base.BaseFragment
|
import com.juhabi.birds.base.BaseFragment
|
||||||
import com.juhabi.birds.custom.DeviceActionPopupWindow
|
import com.juhabi.birds.custom.DeviceActionPopupWindow
|
||||||
import com.juhabi.birds.custom.CustomRefreshHeader
|
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.DeviceContract
|
||||||
import com.juhabi.birds.device.mvp.DeviceImpl
|
import com.juhabi.birds.device.mvp.DeviceImpl
|
||||||
import com.juhabi.birds.device.mvp.DevicePresenter
|
import com.juhabi.birds.device.mvp.DevicePresenter
|
||||||
import com.juhabi.birds.main.fragment.home.mvp.HomeContract
|
import com.juhabi.birds.util.ToastUtil
|
||||||
import com.juhabi.birds.main.fragment.home.mvp.HomeImpl
|
import com.maning.mlkitscanner.scan.MNScanManager
|
||||||
import com.juhabi.birds.main.fragment.home.mvp.HomePresenter
|
import com.maning.mlkitscanner.scan.callback.act.MNScanCallback
|
||||||
import com.scwang.smart.refresh.footer.ClassicsFooter
|
import com.scwang.smart.refresh.footer.ClassicsFooter
|
||||||
|
|
||||||
class IndexFragment : BaseFragment<FragmentHomeBinding, DevicePresenter>(),
|
class DeviceFragment : BaseFragment<FragmentHomeBinding, DevicePresenter>(),
|
||||||
DeviceContract.DeviceView, View.OnClickListener {
|
DeviceContract.DeviceView, View.OnClickListener {
|
||||||
|
|
||||||
private val deviceAdapter = DeviceAdapter()
|
private val deviceAdapter = DeviceAdapter()
|
||||||
@@ -37,10 +39,17 @@ class IndexFragment : BaseFragment<FragmentHomeBinding, DevicePresenter>(),
|
|||||||
override fun initView(savedInstanceState: Bundle?) {
|
override fun initView(savedInstanceState: Bundle?) {
|
||||||
listOf(
|
listOf(
|
||||||
binding.tvIndex,
|
binding.tvIndex,
|
||||||
|
binding.imgScan,
|
||||||
).forEach { button ->
|
).forEach { button ->
|
||||||
button.setOnClickListener(this)
|
button.setOnClickListener(this)
|
||||||
}
|
}
|
||||||
binding.rvDevices.adapter = deviceAdapter
|
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 ->
|
deviceAdapter.setOnItemChildClickListener { adapter, view, position ->
|
||||||
when (view.id) {
|
when (view.id) {
|
||||||
R.id.img_tips -> {
|
R.id.img_tips -> {
|
||||||
@@ -102,6 +111,17 @@ class IndexFragment : BaseFragment<FragmentHomeBinding, DevicePresenter>(),
|
|||||||
R.id.tv_index ->{
|
R.id.tv_index ->{
|
||||||
goTo(BindDeviceActivity::class.java,null)
|
goTo(BindDeviceActivity::class.java,null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//扫一扫:先申请相机和相册权限,授权通过后再拉起扫码页。
|
||||||
|
R.id.img_scan -> {
|
||||||
|
getMorePermissionRequst(
|
||||||
|
scanPermissions(),
|
||||||
|
"相机和相册权限",
|
||||||
|
"扫一扫功能需要使用相机及访问相册权限",
|
||||||
|
REQUEST_CAMERA_AND_ALBUM
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,17 +188,67 @@ class IndexFragment : BaseFragment<FragmentHomeBinding, DevicePresenter>(),
|
|||||||
super.showError(message)
|
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 {
|
private companion object {
|
||||||
const val FIRST_PAGE = 1
|
const val FIRST_PAGE = 1
|
||||||
const val PAGE_SIZE = 10
|
const val PAGE_SIZE = 10
|
||||||
const val REMOVE_ANIMATION_DELAY_MS = 300L
|
const val REMOVE_ANIMATION_DELAY_MS = 300L
|
||||||
|
const val REQUEST_CAMERA_AND_ALBUM = 1001
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(
|
||||||
|
requestCode: Int,
|
||||||
|
permissions: Array<out String>,
|
||||||
|
grantResults: IntArray
|
||||||
|
) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 相机和相册均已授权后,自动打开扫一扫。 */
|
||||||
|
override fun onPermissionsGranted(permissions: Array<String>) {
|
||||||
|
startDeviceScan()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPermissionsDenied(permissions: Array<String>, permanentlyDenied: Boolean) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 使用 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -16,5 +16,6 @@ data class DeviceEntity(
|
|||||||
val ringBattery: Int?,
|
val ringBattery: Int?,
|
||||||
val signalLevel: Int,
|
val signalLevel: Int,
|
||||||
val signalText: String,
|
val signalText: String,
|
||||||
val status: String
|
val status: String,
|
||||||
|
val hoodCoverOn: String
|
||||||
) : Serializable
|
) : Serializable
|
||||||
|
|||||||
@@ -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<T> {
|
||||||
|
fun success(data: T)
|
||||||
|
fun fail(message: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DataModel {
|
||||||
|
/** 查询已绑定的设备列表。 */
|
||||||
|
fun getBindDeviceList(params: Map<String, String>, callback: Callback<List<DeviceEntity>>)
|
||||||
|
fun getDeviceDetail(deviceNo: String, callback: Callback<DeviceEntity>)
|
||||||
|
|
||||||
|
/** 控制设备眼罩开关。 */
|
||||||
|
fun controlEye(deviceNo: String, coverOn: Boolean, callback: Callback<BaseBean<Any>>)
|
||||||
|
|
||||||
|
/** 根据 IMEI 和设备名称绑定设备。 */
|
||||||
|
fun bindDevice(json: JSONObject, callback: Callback<BaseBean<Any>>)
|
||||||
|
|
||||||
|
/** 根据设备编号修改设备名称。 */
|
||||||
|
fun renameDevice(
|
||||||
|
deviceNo: String,
|
||||||
|
json: JSONObject,
|
||||||
|
callback: Callback<BaseBean<Any>>
|
||||||
|
)
|
||||||
|
|
||||||
|
/** 根据设备编号解绑设备。 */
|
||||||
|
fun unbindDevice(deviceNo: String, callback: Callback<BaseBean<Any>>)
|
||||||
|
|
||||||
|
/** 取消设备模块中尚未完成的网络请求。 */
|
||||||
|
fun cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeviceView : IView {
|
||||||
|
fun getBindDeviceListSuccess(devices: List<DeviceEntity>)
|
||||||
|
fun getDeviceDetailSuccess(device: DeviceEntity) {}
|
||||||
|
fun controlEyeSuccess(message: String) {}
|
||||||
|
fun bindDeviceSuccess(message: String)
|
||||||
|
|
||||||
|
/** 设备重命名成功回调,不关心该事件的页面可以不实现。 */
|
||||||
|
fun renameDeviceSuccess(message: String) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 设备解绑成功回调,不关心该事件的页面可以不实现。 */
|
||||||
|
fun unbindDeviceSuccess(message: String) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
276
app/src/main/java/com/juhabi/birds/device/mvp/DeviceImpl.kt
Normal file
276
app/src/main/java/com/juhabi/birds/device/mvp/DeviceImpl.kt
Normal file
@@ -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<BaseBean<List<DeviceEntity>>>? = null
|
||||||
|
private var deviceDetailCall: Call<BaseBean<DeviceEntity>>? = null
|
||||||
|
private var controlEyeCall: Call<BaseBean<Any>>? = null
|
||||||
|
private var bindDeviceCall: Call<BaseBean<Any>>? = null
|
||||||
|
private var renameDeviceCall: Call<BaseBean<Any>>? = null
|
||||||
|
private var unbindDeviceCall: Call<BaseBean<Any>>? = null
|
||||||
|
|
||||||
|
/** 请求当前账号已绑定的设备列表。 */
|
||||||
|
override fun getBindDeviceList(params: Map<String, String>, callback: DeviceContract.Callback<List<DeviceEntity>>) {
|
||||||
|
deviceListCall?.cancel()
|
||||||
|
deviceListCall = ApiClient.apiService
|
||||||
|
.getBindDeviceList(NetworkManager.getToken(), params)
|
||||||
|
.also { call ->
|
||||||
|
call.enqueue(object : Callback<BaseBean<List<DeviceEntity>>> {
|
||||||
|
override fun onResponse(
|
||||||
|
call: Call<BaseBean<List<DeviceEntity>>>,
|
||||||
|
response: Response<BaseBean<List<DeviceEntity>>>
|
||||||
|
) {
|
||||||
|
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<BaseBean<List<DeviceEntity>>>,
|
||||||
|
error: Throwable
|
||||||
|
) {
|
||||||
|
if (!call.isCanceled) {
|
||||||
|
mainHandler.post {
|
||||||
|
callback.fail(error.message ?: "网络请求失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDeviceDetail(
|
||||||
|
deviceNo: String,
|
||||||
|
callback: DeviceContract.Callback<DeviceEntity>
|
||||||
|
) {
|
||||||
|
deviceDetailCall?.cancel()
|
||||||
|
deviceDetailCall = ApiClient.apiService
|
||||||
|
.getDeviceDetail(NetworkManager.getToken(), deviceNo)
|
||||||
|
.also { call ->
|
||||||
|
call.enqueue(object : Callback<BaseBean<DeviceEntity>> {
|
||||||
|
override fun onResponse(
|
||||||
|
call: Call<BaseBean<DeviceEntity>>,
|
||||||
|
response: Response<BaseBean<DeviceEntity>>
|
||||||
|
) {
|
||||||
|
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<BaseBean<DeviceEntity>>,
|
||||||
|
error: Throwable
|
||||||
|
) {
|
||||||
|
if (!call.isCanceled) {
|
||||||
|
mainHandler.post {
|
||||||
|
callback.fail(error.message ?: "网络请求失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 请求服务端控制设备眼罩开关。 */
|
||||||
|
override fun controlEye(
|
||||||
|
deviceNo: String,
|
||||||
|
coverOn: Boolean,
|
||||||
|
callback: DeviceContract.Callback<BaseBean<Any>>
|
||||||
|
) {
|
||||||
|
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<BaseBean<Any>> {
|
||||||
|
override fun onResponse(
|
||||||
|
call: Call<BaseBean<Any>>,
|
||||||
|
response: Response<BaseBean<Any>>
|
||||||
|
) {
|
||||||
|
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<BaseBean<Any>>, error: Throwable) {
|
||||||
|
if (!call.isCanceled) {
|
||||||
|
mainHandler.post {
|
||||||
|
callback.fail(error.message ?: "网络请求失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 将设备 IMEI 和名称提交到服务器完成绑定。 */
|
||||||
|
override fun bindDevice(
|
||||||
|
json: JSONObject,
|
||||||
|
callback: DeviceContract.Callback<BaseBean<Any>>
|
||||||
|
) {
|
||||||
|
bindDeviceCall?.cancel()
|
||||||
|
bindDeviceCall = ApiClient.apiService
|
||||||
|
.bindDevice(NetworkManager.getToken(), NetworkManager.toRequestBody(json))
|
||||||
|
.also { call ->
|
||||||
|
call.enqueue(object : Callback<BaseBean<Any>> {
|
||||||
|
override fun onResponse(
|
||||||
|
call: Call<BaseBean<Any>>,
|
||||||
|
response: Response<BaseBean<Any>>
|
||||||
|
) {
|
||||||
|
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<BaseBean<Any>>, error: Throwable) {
|
||||||
|
if (!call.isCanceled) {
|
||||||
|
mainHandler.post {
|
||||||
|
callback.fail(error.message ?: "网络请求失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 将新的设备名称提交到服务器。 */
|
||||||
|
override fun renameDevice(
|
||||||
|
deviceNo: String,
|
||||||
|
json: JSONObject,
|
||||||
|
callback: DeviceContract.Callback<BaseBean<Any>>
|
||||||
|
) {
|
||||||
|
renameDeviceCall?.cancel()
|
||||||
|
renameDeviceCall = ApiClient.apiService
|
||||||
|
.deviceRename(deviceNo = deviceNo, headers = NetworkManager.getToken(), requestBody = NetworkManager.toRequestBody(json))
|
||||||
|
.also { call ->
|
||||||
|
call.enqueue(object : Callback<BaseBean<Any>> {
|
||||||
|
override fun onResponse(
|
||||||
|
call: Call<BaseBean<Any>>,
|
||||||
|
response: Response<BaseBean<Any>>
|
||||||
|
) {
|
||||||
|
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<BaseBean<Any>>, error: Throwable) {
|
||||||
|
if (!call.isCanceled) {
|
||||||
|
mainHandler.post {
|
||||||
|
callback.fail(error.message ?: "网络请求失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 按设备编号请求服务端解绑。 */
|
||||||
|
override fun unbindDevice(
|
||||||
|
deviceNo: String,
|
||||||
|
callback: DeviceContract.Callback<BaseBean<Any>>
|
||||||
|
) {
|
||||||
|
unbindDeviceCall?.cancel()
|
||||||
|
unbindDeviceCall = ApiClient.apiService
|
||||||
|
.unbindDevice(headers = NetworkManager.getToken(), deviceNo = deviceNo)
|
||||||
|
.also { call ->
|
||||||
|
call.enqueue(object : Callback<BaseBean<Any>> {
|
||||||
|
override fun onResponse(
|
||||||
|
call: Call<BaseBean<Any>>,
|
||||||
|
response: Response<BaseBean<Any>>
|
||||||
|
) {
|
||||||
|
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<BaseBean<Any>>, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
166
app/src/main/java/com/juhabi/birds/device/mvp/DevicePresenter.kt
Normal file
166
app/src/main/java/com/juhabi/birds/device/mvp/DevicePresenter.kt
Normal file
@@ -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<DeviceContract.DeviceView>() {
|
||||||
|
|
||||||
|
/** 获取当前账号已经绑定的设备列表。 */
|
||||||
|
fun getBindDeviceList(params: Map<String, String> = emptyMap()) {
|
||||||
|
val currentView = view ?: return
|
||||||
|
currentView.showLoading()
|
||||||
|
deviceImpl.getBindDeviceList(params, object : DeviceContract.Callback<List<DeviceEntity>> {
|
||||||
|
override fun success(data: List<DeviceEntity>) {
|
||||||
|
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<DeviceEntity> {
|
||||||
|
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<BaseBean<Any>> {
|
||||||
|
override fun success(data: BaseBean<Any>) {
|
||||||
|
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<BaseBean<Any>> {
|
||||||
|
override fun success(data: BaseBean<Any>) {
|
||||||
|
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<BaseBean<Any>> {
|
||||||
|
override fun success(data: BaseBean<Any>) {
|
||||||
|
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<BaseBean<Any>> {
|
||||||
|
override fun success(data: BaseBean<Any>) {
|
||||||
|
view?.apply {
|
||||||
|
hideLoading()
|
||||||
|
unbindDeviceSuccess(data.message.ifBlank { "设备解绑成功" })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fail(message: String) {
|
||||||
|
view?.apply {
|
||||||
|
hideLoading()
|
||||||
|
showError(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 销毁页面时取消设备模块发起的网络请求。 */
|
||||||
|
override fun onDestroy() {
|
||||||
|
deviceImpl.cancel()
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,17 +2,14 @@ package com.juhabi.birds.main
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
|
||||||
import androidx.annotation.ColorRes
|
import androidx.annotation.ColorRes
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.juhabi.birds.R
|
import com.juhabi.birds.R
|
||||||
import com.juhabi.birds.base.BaseActivity
|
import com.juhabi.birds.base.BaseActivity
|
||||||
import com.juhabi.birds.databinding.ActivityMainBinding
|
import com.juhabi.birds.databinding.ActivityMainBinding
|
||||||
import com.juhabi.birds.main.adapter.MainPagerAdapter
|
import com.juhabi.birds.main.adapter.MainPagerAdapter
|
||||||
import com.juhabi.birds.main.fragment.HistoryFragment
|
import com.juhabi.birds.device.DeviceFragment
|
||||||
import com.juhabi.birds.device.IndexFragment
|
|
||||||
import com.juhabi.birds.mine.MineFragment
|
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.model.AppVersionInfo
|
||||||
import com.juhabi.birds.main.mvp.MainContract
|
import com.juhabi.birds.main.mvp.MainContract
|
||||||
import com.juhabi.birds.main.mvp.MainImpl
|
import com.juhabi.birds.main.mvp.MainImpl
|
||||||
@@ -42,7 +39,7 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainPresenter>(),
|
|||||||
override fun initView(savedInstanceState: Bundle?) {
|
override fun initView(savedInstanceState: Bundle?) {
|
||||||
binding.viewPager.adapter = MainPagerAdapter(
|
binding.viewPager.adapter = MainPagerAdapter(
|
||||||
this,
|
this,
|
||||||
listOf(IndexFragment(), PlanFragment(), HistoryFragment(), MineFragment())
|
listOf(DeviceFragment(), MineFragment())
|
||||||
)
|
)
|
||||||
binding.viewPager.offscreenPageLimit = 1
|
binding.viewPager.offscreenPageLimit = 1
|
||||||
binding.viewPager.registerOnPageChangeCallback(object : androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback() {
|
binding.viewPager.registerOnPageChangeCallback(object : androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback() {
|
||||||
@@ -60,8 +57,6 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainPresenter>(),
|
|||||||
private fun onNavigationItemSelected(itemId: Int): Boolean {
|
private fun onNavigationItemSelected(itemId: Int): Boolean {
|
||||||
return when (itemId) {
|
return when (itemId) {
|
||||||
R.id.navigation_home -> onHomeSelected()
|
R.id.navigation_home -> onHomeSelected()
|
||||||
R.id.navigation_plan -> onPlanSelected()
|
|
||||||
R.id.navigation_history -> onHistorySelected()
|
|
||||||
R.id.navigation_mine -> onMineSelected()
|
R.id.navigation_mine -> onMineSelected()
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
@@ -69,25 +64,11 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainPresenter>(),
|
|||||||
|
|
||||||
private fun onHomeSelected(): Boolean {
|
private fun onHomeSelected(): Boolean {
|
||||||
switchPage(PAGE_HOME)
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onMineSelected(): Boolean {
|
private fun onMineSelected(): Boolean {
|
||||||
switchPage(PAGE_MINE)
|
switchPage(PAGE_MINE)
|
||||||
// Add Mine-specific status bar, refresh, or Fragment communication here.
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,18 +80,8 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainPresenter>(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateTopBarColor(position: Int) {
|
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) {
|
@ColorRes val colorRes = when (position) {
|
||||||
PAGE_HOME -> R.color.color_zhu
|
PAGE_HOME -> R.color.color_zhu
|
||||||
PAGE_HISTORY -> R.color.color_E9A01C
|
|
||||||
PAGE_MINE -> R.color.color_B85CE6
|
PAGE_MINE -> R.color.color_B85CE6
|
||||||
else -> R.color.color_zhu
|
else -> R.color.color_zhu
|
||||||
}
|
}
|
||||||
@@ -131,8 +102,6 @@ class MainActivity : BaseActivity<ActivityMainBinding, MainPresenter>(),
|
|||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val PAGE_HOME = 0
|
const val PAGE_HOME = 0
|
||||||
const val PAGE_PLAN = 1
|
const val PAGE_MINE = 1
|
||||||
const val PAGE_HISTORY = 2
|
|
||||||
const val PAGE_MINE = 3
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,14 +167,6 @@ class MineCenterActivity : BaseActivity<ActivityMineCenterBinding, MinePresenter
|
|||||||
appUpdateManager.checkAndUpdate(currentVersion, versionInfo)
|
appUpdateManager.checkAndUpdate(currentVersion, versionInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(
|
|
||||||
requestCode: Int,
|
|
||||||
permissions: Array<out String>,
|
|
||||||
grantResults: IntArray
|
|
||||||
) {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
||||||
appUpdateManager.onRequestPermissionsResult(requestCode, grantResults)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日期、时间和日期时间共用同一个组件调用入口。
|
* 日期、时间和日期时间共用同一个组件调用入口。
|
||||||
@@ -211,6 +203,16 @@ class MineCenterActivity : BaseActivity<ActivityMineCenterBinding, MinePresenter
|
|||||||
showMessage(message)
|
showMessage(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(
|
||||||
|
requestCode: Int,
|
||||||
|
permissions: Array<out String>,
|
||||||
|
grantResults: IntArray
|
||||||
|
) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
|
appUpdateManager.onRequestPermissionsResult(requestCode, grantResults)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onPermissionsGranted(permissions: Array<String>) {
|
override fun onPermissionsGranted(permissions: Array<String>) {
|
||||||
showMessage("权限获取成功:${permissions.joinToString { it.substringAfterLast('.') }}")
|
showMessage("权限获取成功:${permissions.joinToString { it.substringAfterLast('.') }}")
|
||||||
}
|
}
|
||||||
|
|||||||
130
app/src/main/java/com/juhabi/birds/mine/ModifyPsdActivity.kt
Normal file
130
app/src/main/java/com/juhabi/birds/mine/ModifyPsdActivity.kt
Normal file
@@ -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<ModifyPsdLayoutBinding, MinePresenter>(),
|
||||||
|
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) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,11 +16,14 @@ interface MineContract {
|
|||||||
params: Map<String, String>,
|
params: Map<String, String>,
|
||||||
callback: Callback<AppVersionInfo>
|
callback: Callback<AppVersionInfo>
|
||||||
)
|
)
|
||||||
|
fun modifyPassword(oldPassword: String, newPassword: String, callback: Callback<String>)
|
||||||
fun cancel()
|
fun cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MineView : IView {
|
interface MineView : IView {
|
||||||
fun getUserInfoSuccess(userInfo: MineUserInfo)
|
fun getUserInfoSuccess(userInfo: MineUserInfo)
|
||||||
fun onVersionChecked(versionInfo: AppVersionInfo)
|
fun onVersionChecked(versionInfo: AppVersionInfo)
|
||||||
|
/** 修改密码成功回调,非修改密码页面无需处理。 */
|
||||||
|
fun onModifyPasswordSuccess(message: String) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,13 @@ import com.juhabi.birds.network.NetworkManager
|
|||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
import retrofit2.Callback
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
class MineImpl : MineContract.DataModel {
|
class MineImpl : MineContract.DataModel {
|
||||||
private val mainHandler = Handler(Looper.getMainLooper())
|
private val mainHandler = Handler(Looper.getMainLooper())
|
||||||
private var userInfoCall: Call<BaseBean<MineUserInfo>>? = null
|
private var userInfoCall: Call<BaseBean<MineUserInfo>>? = null
|
||||||
private var versionCall: Call<BaseBean<AppVersionInfo>>? = null
|
private var versionCall: Call<BaseBean<AppVersionInfo>>? = null
|
||||||
|
private var modifyPasswordCall: Call<BaseBean<Any>>? = null
|
||||||
|
|
||||||
override fun getUserInfo(
|
override fun getUserInfo(
|
||||||
params: Map<String, String>,
|
params: Map<String, String>,
|
||||||
@@ -96,11 +98,53 @@ class MineImpl : MineContract.DataModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过旧密码修改原密码
|
||||||
|
*/
|
||||||
|
override fun modifyPassword(
|
||||||
|
oldPassword: String,
|
||||||
|
newPassword: String,
|
||||||
|
callback: MineContract.Callback<String>
|
||||||
|
) {
|
||||||
|
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<BaseBean<Any>> {
|
||||||
|
override fun onResponse(
|
||||||
|
call: Call<BaseBean<Any>>,
|
||||||
|
response: Response<BaseBean<Any>>
|
||||||
|
) {
|
||||||
|
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<BaseBean<Any>>, error: Throwable) {
|
||||||
|
if (!call.isCanceled) {
|
||||||
|
mainHandler.post { callback.fail(error.message ?: "网络请求失败") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun cancel() {
|
override fun cancel() {
|
||||||
userInfoCall?.cancel()
|
userInfoCall?.cancel()
|
||||||
userInfoCall = null
|
userInfoCall = null
|
||||||
versionCall?.cancel()
|
versionCall?.cancel()
|
||||||
versionCall = null
|
versionCall = null
|
||||||
|
modifyPasswordCall?.cancel()
|
||||||
|
modifyPasswordCall = null
|
||||||
mainHandler.removeCallbacksAndMessages(null)
|
mainHandler.removeCallbacksAndMessages(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,27 @@ class MinePresenter(private val mineImpl: MineImpl) : BasePresenter<MineContract
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 提交修改密码请求,统一处理加载状态和接口结果。 */
|
||||||
|
fun modifyPassword(oldPassword: String, newPassword: String) {
|
||||||
|
val currentView = view ?: return
|
||||||
|
currentView.showLoading()
|
||||||
|
mineImpl.modifyPassword(oldPassword, newPassword, object : MineContract.Callback<String> {
|
||||||
|
override fun success(data: String) {
|
||||||
|
view?.apply {
|
||||||
|
hideLoading()
|
||||||
|
onModifyPasswordSuccess(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fail(message: String) {
|
||||||
|
view?.apply {
|
||||||
|
hideLoading()
|
||||||
|
showError(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
mineImpl.cancel()
|
mineImpl.cancel()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
|||||||
@@ -126,6 +126,15 @@ interface ApiService {
|
|||||||
fun getBindDeviceList(@HeaderMap headers: Map<String, String>, @QueryMap params: Map<String, String>): Call<BaseBean<List<DeviceEntity>>>
|
fun getBindDeviceList(@HeaderMap headers: Map<String, String>, @QueryMap params: Map<String, String>): Call<BaseBean<List<DeviceEntity>>>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备详情
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@GET("app/device/{deviceNo}")
|
||||||
|
fun getDeviceDetail(@HeaderMap headers: Map<String, String>, @Path("deviceNo") deviceNo: String): Call<BaseBean<DeviceEntity>>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 绑定设备
|
* 绑定设备
|
||||||
{
|
{
|
||||||
@@ -173,6 +182,20 @@ interface ApiService {
|
|||||||
fun getMineUserInfo(@HeaderMap headers: Map<String, String>, @QueryMap params: Map<String, String>): Call<BaseBean<MineUserInfo>>
|
fun getMineUserInfo(@HeaderMap headers: Map<String, String>, @QueryMap params: Map<String, String>): Call<BaseBean<MineUserInfo>>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过旧密码修改新密码
|
||||||
|
{
|
||||||
|
"oldPassword": "string",
|
||||||
|
"newPassword": "string"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
@PUT("app/user/password")
|
||||||
|
fun modifyPassword(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<Any>>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@GET("app/v1/checkVersion")
|
@GET("app/v1/checkVersion")
|
||||||
fun checkVersionCode(@HeaderMap headers: Map<String, String>, @QueryMap params: Map<String, String>): Call<BaseBean<AppVersionInfo>>
|
fun checkVersionCode(@HeaderMap headers: Map<String, String>, @QueryMap params: Map<String, String>): Call<BaseBean<AppVersionInfo>>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,18 +4,6 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/immersiveTopImageView"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="320dp"
|
|
||||||
android:contentDescription="@string/plan_top_image_description"
|
|
||||||
android:scaleType="centerCrop"
|
|
||||||
android:src="@drawable/img_top"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/statusBarView"
|
android:id="@+id/statusBarView"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|||||||
33
app/src/main/res/layout/device_detail_layout.xml
Normal file
33
app/src/main/res/layout/device_detail_layout.xml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
<View
|
||||||
|
android:id="@+id/statusBarView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:background="@color/color_zhu" />
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp">
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/included_title"
|
||||||
|
layout="@layout/include_activity_back_gray_layout" />
|
||||||
|
</RelativeLayout>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_bind"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:text="绑定"
|
||||||
|
android:background="@color/color_zhu"/>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/switch_ctrl"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
</LinearLayout>
|
||||||
@@ -20,12 +20,6 @@
|
|||||||
android:src="@mipmap/ic_launcher"
|
android:src="@mipmap/ic_launcher"
|
||||||
android:layout_gravity="end"/>
|
android:layout_gravity="end"/>
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/control_eye"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:src="@mipmap/icon_login_show"
|
|
||||||
android:layout_gravity="end"/>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,27 @@
|
|||||||
android:id="@+id/included_title"
|
android:id="@+id/included_title"
|
||||||
layout="@layout/include_title_home_layout" />
|
layout="@layout/include_title_home_layout" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_index"
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/home_page_title"
|
android:orientation="horizontal">
|
||||||
android:textColor="@color/black"
|
<TextView
|
||||||
android:textSize="24sp" />
|
android:id="@+id/tv_index"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/home_page_title"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="24sp" />
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/img_scan"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:src="@mipmap/ic_launcher"
|
||||||
|
android:layout_marginEnd="15dp"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
<com.scwang.smart.refresh.layout.SmartRefreshLayout
|
||||||
android:id="@+id/refresh"
|
android:id="@+id/refresh"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
212
app/src/main/res/layout/modify_psd_layout.xml
Normal file
212
app/src/main/res/layout/modify_psd_layout.xml
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/color_zhu">
|
||||||
|
<View
|
||||||
|
android:id="@+id/statusBarView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:background="@color/color_zhu" />
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp">
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/included_title"
|
||||||
|
layout="@layout/include_activity_back_gray_layout" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="20dp"
|
||||||
|
android:paddingEnd="20dp"
|
||||||
|
android:paddingBottom="32dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:paddingStart="44dp"
|
||||||
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/oldPasswordEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="请输入当前密码"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/oldPsdVisibilityButton"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@mipmap/icon_login_show" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:paddingStart="44dp"
|
||||||
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/passwordEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="请输入8-20位密码"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/passwordVisibilityButton"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@mipmap/icon_login_show"
|
||||||
|
android:contentDescription="显示密码" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:paddingStart="44dp"
|
||||||
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/confirmPasswordEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="请再次输入新密码"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/confirmPasswordVisibilityButton"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@mipmap/icon_login_show"
|
||||||
|
android:contentDescription="显示密码" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="26dp"
|
||||||
|
android:layout_marginEnd="26dp"
|
||||||
|
android:layout_marginTop="36dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="18dp"
|
||||||
|
android:paddingVertical="10dp"
|
||||||
|
android:background="@drawable/shape_register_rule_bg">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="密码规则"
|
||||||
|
android:textColor="@color/color_white"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="15dp"
|
||||||
|
android:layout_height="15dp"
|
||||||
|
android:layout_marginVertical="5dp"
|
||||||
|
android:src="@mipmap/icon_login_select"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:text="长度在8-20个字符之间"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="15dp"
|
||||||
|
android:layout_height="15dp"
|
||||||
|
android:layout_marginVertical="5dp"
|
||||||
|
android:src="@mipmap/icon_login_select"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:text="包含大小写字母和数字"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="15dp"
|
||||||
|
android:layout_height="15dp"
|
||||||
|
android:layout_marginVertical="5dp"
|
||||||
|
android:src="@mipmap/icon_login_tips"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:text="不能与当前密码相同"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/confirmButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_marginEnd="5dp"
|
||||||
|
android:layout_marginTop="84dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:backgroundTint="@null"
|
||||||
|
android:stateListAnimator="@null"
|
||||||
|
android:text="确定"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/color_zhu"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
||||||
53
app/src/main/res/layout/popup_device_action.xml
Normal file
53
app/src/main/res/layout/popup_device_action.xml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="6dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/action_rename"
|
||||||
|
android:layout_width="130dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="10dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="22dp"
|
||||||
|
android:layout_height="22dp"
|
||||||
|
android:src="@mipmap/ic_launcher"
|
||||||
|
android:contentDescription="@string/device_action_rename" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:text="重命名"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/action_unbind"
|
||||||
|
android:layout_width="130dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="10dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="22dp"
|
||||||
|
android:layout_height="22dp"
|
||||||
|
android:src="@mipmap/ic_launcher"
|
||||||
|
android:contentDescription="@string/device_action_unbind" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:text="解绑设备"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
@@ -4,16 +4,6 @@
|
|||||||
android:id="@+id/navigation_home"
|
android:id="@+id/navigation_home"
|
||||||
android:icon="@drawable/ic_nav_home"
|
android:icon="@drawable/ic_nav_home"
|
||||||
android:title="@string/tab_home" />
|
android:title="@string/tab_home" />
|
||||||
<item
|
|
||||||
android:id="@+id/navigation_plan"
|
|
||||||
android:icon="@drawable/ic_nav_plan"
|
|
||||||
android:title="@string/tab_plan"
|
|
||||||
android:visible="false"/>
|
|
||||||
<item
|
|
||||||
android:id="@+id/navigation_history"
|
|
||||||
android:icon="@drawable/ic_nav_history"
|
|
||||||
android:title="@string/tab_history"
|
|
||||||
android:visible="false"/>
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/navigation_mine"
|
android:id="@+id/navigation_mine"
|
||||||
android:icon="@drawable/ic_nav_mine"
|
android:icon="@drawable/ic_nav_mine"
|
||||||
|
|||||||
@@ -67,6 +67,7 @@
|
|||||||
<string name="home_page_title">首页</string>
|
<string name="home_page_title">首页</string>
|
||||||
<string name="device_action_rename">重命名</string>
|
<string name="device_action_rename">重命名</string>
|
||||||
<string name="device_action_unbind">解绑设备</string>
|
<string name="device_action_unbind">解绑设备</string>
|
||||||
|
<string name="cancel_scan">取消扫码</string>
|
||||||
<string name="plan_page_title">计划</string>
|
<string name="plan_page_title">计划</string>
|
||||||
<string name="history_page_title">历史</string>
|
<string name="history_page_title">历史</string>
|
||||||
<string name="mine_page_title">我的</string>
|
<string name="mine_page_title">我的</string>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
# Specifies the JVM arguments used for the daemon process.
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
# The setting is particularly useful for tweaking memory settings.
|
# 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.
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
# This option should only be used with decoupled projects. For more details, visit
|
# This option should only be used with decoupled projects. For more details, visit
|
||||||
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
|
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
|
||||||
|
|||||||
Reference in New Issue
Block a user