From 981cfae71c03f7336a07ce6b0750677e3fe4f14a Mon Sep 17 00:00:00 2001
From: fengjignqi <15192412330@163.com>
Date: Sat, 19 Sep 2026 08:41:53 +0800
Subject: [PATCH] =?UTF-8?q?=E8=AE=BE=E5=A4=87=E7=9B=B8=E5=85=B3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/build.gradle | 4 +
app/src/main/AndroidManifest.xml | 4 +
.../birds/custom/CustomRefreshHeader.java | 178 +++++++++++++++++
.../juhabi/birds/device/BindDeviceActivity.kt | 78 ++++++++
.../birds/device/DeviceDetailActivity.kt | 40 ++++
.../com/juhabi/birds/device/IndexFragment.kt | 184 ++++++++++++++++++
.../birds/device/entity/DeviceEntity.kt | 20 ++
.../com/juhabi/birds/login/LoginActivity.kt | 3 +-
.../juhabi/birds/login/model/UserEntity.kt | 9 +-
.../com/juhabi/birds/main/MainActivity.kt | 6 +-
.../birds/main/fragment/HomeFragment.kt | 25 ---
.../birds/main/fragment/MineFragment.kt | 30 ---
.../com/juhabi/birds/mine/MineFragment.kt | 50 +++++
.../juhabi/birds/mine/model/UserInfoEntity.kt | 14 ++
.../com/juhabi/birds/network/ApiService.kt | 55 +++++-
.../main/res/layout/bind_device_layout.xml | 28 +++
app/src/main/res/layout/device_item.xml | 80 ++++++++
app/src/main/res/layout/fragment_home.xml | 40 +++-
app/src/main/res/layout/layout_no_more.xml | 41 ++++
.../main/res/layout/view_refresh_header.xml | 11 ++
.../main/res/menu/bottom_navigation_menu.xml | 6 +-
.../mipmap-hdpi/icon_water_head_refresh.png | Bin 0 -> 5449 bytes
.../mipmap-xxhdpi/icon_water_head_refresh.png | Bin 0 -> 5449 bytes
.../icon_water_head_refresh.png | Bin 0 -> 9314 bytes
app/src/main/res/values/strings.xml | 4 +
gradle.properties | 1 +
26 files changed, 839 insertions(+), 72 deletions(-)
create mode 100644 app/src/main/java/com/juhabi/birds/custom/CustomRefreshHeader.java
create mode 100644 app/src/main/java/com/juhabi/birds/device/BindDeviceActivity.kt
create mode 100644 app/src/main/java/com/juhabi/birds/device/DeviceDetailActivity.kt
create mode 100644 app/src/main/java/com/juhabi/birds/device/IndexFragment.kt
create mode 100644 app/src/main/java/com/juhabi/birds/device/entity/DeviceEntity.kt
delete mode 100644 app/src/main/java/com/juhabi/birds/main/fragment/HomeFragment.kt
delete mode 100644 app/src/main/java/com/juhabi/birds/main/fragment/MineFragment.kt
create mode 100644 app/src/main/java/com/juhabi/birds/mine/MineFragment.kt
create mode 100644 app/src/main/java/com/juhabi/birds/mine/model/UserInfoEntity.kt
create mode 100644 app/src/main/res/layout/bind_device_layout.xml
create mode 100644 app/src/main/res/layout/device_item.xml
create mode 100644 app/src/main/res/layout/layout_no_more.xml
create mode 100644 app/src/main/res/layout/view_refresh_header.xml
create mode 100644 app/src/main/res/mipmap-hdpi/icon_water_head_refresh.png
create mode 100644 app/src/main/res/mipmap-xxhdpi/icon_water_head_refresh.png
create mode 100644 app/src/main/res/mipmap-xxxhdpi/icon_water_head_refresh.png
diff --git a/app/build.gradle b/app/build.gradle
index 2707a18..e009301 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -66,4 +66,8 @@ dependencies {
androidTestImplementation libs.androidx.junit
//屏幕适配
implementation 'me.jessyan:autosize:1.2.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-footer-classics:2.1.1'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8404ea2..9e1cb4d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -65,6 +65,10 @@
android:name=".login.ForgetPsdActivity"
android:exported="false" />
+
+
{
+ if (rotateAnimator != null) {
+ rotateAnimator.cancel();
+ rotateAnimator.setInterpolator(new LinearInterpolator());
+ }
+ }, 300);
+ }
+ // 动画过渡回正常大小
+ animateToNormalScale();
+ return 500;
+ }
+
+ /**
+ * 平滑动画过渡回正常大小
+ */
+ private void animateToNormalScale() {
+ if (ivRefresh == null) return;
+
+ float startScale = mCurrentScale;
+ ValueAnimator scaleAnimator = ValueAnimator.ofFloat(startScale, 1f);
+ scaleAnimator.setDuration(300);
+ scaleAnimator.setInterpolator(new DecelerateInterpolator());
+ scaleAnimator.addUpdateListener(animation -> {
+ float value = (float) animation.getAnimatedValue();
+ ivRefresh.setScaleX(value);
+ ivRefresh.setScaleY(value);
+ mCurrentScale = value;
+ });
+ scaleAnimator.start();
+ }
+
+ // --- 必须实现的方法 ---
+
+ @NonNull
+ @Override
+ public SpinnerStyle getSpinnerStyle() {
+ return SpinnerStyle.Translate; // Header 跟随内容滑动
+ }
+
+ @Override
+ public boolean isSupportHorizontalDrag() {
+ return false;
+ }
+
+ @SuppressLint("RestrictedApi")
+ @Override
+ public void setPrimaryColors(@ColorInt int... colors) {}
+
+ @SuppressLint("RestrictedApi")
+ @Override
+ public void onInitialized(@NonNull RefreshKernel kernel, int height, int maxDragHeight) {}
+
+ @SuppressLint("RestrictedApi")
+ @Override
+ public void onMoving(boolean isDragging, float percent, int offset, int height, int maxDragHeight) {
+ // 只在拖动过程中处理,避免过度计算
+ if (percent != mLastPercent) {
+ mLastPercent = percent;
+
+ // 1. 动态缩放效果:从 0.5 放大到 1.2
+ // 使用 clamp 限制范围:percent 0~1 -> scale 0.5~1.2
+ float targetScale = 0.5f + (0.7f * Math.min(percent, 1.0f));
+ if (Math.abs(targetScale - mCurrentScale) > 0.01f) {
+ mCurrentScale = targetScale;
+ ivRefresh.setScaleX(targetScale);
+ ivRefresh.setScaleY(targetScale);
+ }
+
+ // 2. 透明度渐变效果(可选)
+ // ivRefresh.setAlpha(Math.min(percent * 1.5f, 1.0f));
+ }
+ }
+
+ @SuppressLint("RestrictedApi")
+ @Override
+ public void onReleased(@NonNull RefreshLayout layout, int height, int maxDragHeight) {}
+
+ @SuppressLint("RestrictedApi")
+ @Override
+ public void onHorizontalDrag(float percentX, int offsetX, int offsetMax) {}
+
+ @Override
+ public boolean autoOpen(int duration, float dragRate, boolean animationOnly) {
+ return false;
+ }
+
+ @SuppressLint("RestrictedApi")
+ @Override
+ public void onStateChanged(@NonNull RefreshLayout refreshLayout, @NonNull RefreshState oldState, @NonNull RefreshState newState) {
+ // 状态切换时平滑恢复
+ if (newState == RefreshState.PullDownCanceled) {
+ // 用户取消下拉,恢复到初始状态
+ animateToNormalScale();
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/juhabi/birds/device/BindDeviceActivity.kt b/app/src/main/java/com/juhabi/birds/device/BindDeviceActivity.kt
new file mode 100644
index 0000000..bf5af59
--- /dev/null
+++ b/app/src/main/java/com/juhabi/birds/device/BindDeviceActivity.kt
@@ -0,0 +1,78 @@
+package com.juhabi.birds.device
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import com.gyf.immersionbar.ImmersionBar
+import com.juhabi.birds.R
+import com.juhabi.birds.base.BaseActivity
+import com.juhabi.birds.databinding.BindDeviceLayoutBinding
+import com.juhabi.birds.device.entity.DeviceEntity
+import com.juhabi.birds.device.mvp.DeviceContract
+import com.juhabi.birds.device.mvp.DeviceImpl
+import com.juhabi.birds.device.mvp.DevicePresenter
+import kotlin.random.Random
+
+/**
+ * 绑定设备
+ */
+class BindDeviceActivity: BaseActivity() , DeviceContract.DeviceView,
+ View.OnClickListener {
+ override fun createBinding(inflater: LayoutInflater): BindDeviceLayoutBinding {
+ return BindDeviceLayoutBinding.inflate(inflater)
+ }
+
+ override fun createPresenter(): DevicePresenter? {
+ return DevicePresenter(DeviceImpl())
+ }
+
+ override fun initWindows() {
+ ImmersionBar.with(this)
+ .statusBarView(binding.statusBarView)
+ .statusBarDarkFont(true)
+ .navigationBarColor(R.color.color_zhu)
+ .navigationBarDarkIcon(true)
+ .init()
+ }
+
+ override fun initView(savedInstanceState: Bundle?) {
+ binding.includedTitle.tvTitle.setText(R.string.bind_device)
+ listOf(
+ binding.tvBind,
+ binding.includedTitle.imgBack,
+ ).forEach { button ->
+ button.setOnClickListener(this)
+ }
+ }
+
+ override fun onClick(view: View) {
+ when (view.id) {
+ R.id.img_back ->{
+ finish()
+ }
+
+ R.id.tv_bind ->{//绑定设备
+// val imei = "${System.currentTimeMillis()}${Random.nextInt(100).toString().padStart(2, '0')}"
+// val name = "device001"
+ val imei = "860000000000005"
+ val name = "BM202609160005"
+ presenter?.bindDevice(imei, name)
+ }
+ }
+ }
+
+ override fun showError(message: String) {
+ showMessage(message)
+ }
+
+ override fun getBindDeviceListSuccess(devices: List) {
+ }
+
+ /** 绑定设备成功后提示用户并关闭当前页面。 */
+ override fun bindDeviceSuccess(message: String) {
+ showMessage(message)
+ finish()
+ }
+
+
+}
diff --git a/app/src/main/java/com/juhabi/birds/device/DeviceDetailActivity.kt b/app/src/main/java/com/juhabi/birds/device/DeviceDetailActivity.kt
new file mode 100644
index 0000000..758de85
--- /dev/null
+++ b/app/src/main/java/com/juhabi/birds/device/DeviceDetailActivity.kt
@@ -0,0 +1,40 @@
+package com.juhabi.birds.device
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import com.juhabi.birds.base.BaseActivity
+import com.juhabi.birds.databinding.BindDeviceLayoutBinding
+import com.juhabi.birds.device.entity.DeviceEntity
+import com.juhabi.birds.device.mvp.DeviceContract
+import com.juhabi.birds.device.mvp.DeviceImpl
+import com.juhabi.birds.device.mvp.DevicePresenter
+
+/**
+ * 设备详情
+ */
+class DeviceDetailActivity: BaseActivity() , DeviceContract.DeviceView,
+ View.OnClickListener {
+ override fun createBinding(inflater: LayoutInflater): BindDeviceLayoutBinding {
+ return BindDeviceLayoutBinding.inflate(inflater)
+ }
+
+ override fun createPresenter(): DevicePresenter? {
+ return DevicePresenter(DeviceImpl())
+ }
+
+ override fun initView(savedInstanceState: Bundle?) {
+ }
+
+ override fun showError(message: String) {
+ }
+
+ override fun getBindDeviceListSuccess(devices: List) {
+ }
+
+ 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/IndexFragment.kt
new file mode 100644
index 0000000..795e720
--- /dev/null
+++ b/app/src/main/java/com/juhabi/birds/device/IndexFragment.kt
@@ -0,0 +1,184 @@
+package com.juhabi.birds.device
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.juhabi.birds.R
+import com.juhabi.birds.base.BaseActivity
+import com.juhabi.birds.base.BaseFragment
+import com.juhabi.birds.custom.DeviceActionPopupWindow
+import com.juhabi.birds.custom.CustomRefreshHeader
+import com.juhabi.birds.databinding.FragmentHomeBinding
+import com.juhabi.birds.device.entity.DeviceEntity
+import com.juhabi.birds.device.mvp.DeviceContract
+import com.juhabi.birds.device.mvp.DeviceImpl
+import com.juhabi.birds.device.mvp.DevicePresenter
+import com.juhabi.birds.main.fragment.home.mvp.HomeContract
+import com.juhabi.birds.main.fragment.home.mvp.HomeImpl
+import com.juhabi.birds.main.fragment.home.mvp.HomePresenter
+import com.scwang.smart.refresh.footer.ClassicsFooter
+
+class IndexFragment : BaseFragment(),
+ DeviceContract.DeviceView, View.OnClickListener {
+
+ private val deviceAdapter = DeviceAdapter()
+ private var currentPage = FIRST_PAGE
+ private var pendingUnbindPosition: Int? = null
+
+ override fun createBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentHomeBinding {
+ return FragmentHomeBinding.inflate(inflater, container, false)
+ }
+
+ override fun createPresenter(): DevicePresenter {
+ return DevicePresenter(DeviceImpl())
+ }
+
+ override fun initView(savedInstanceState: Bundle?) {
+ listOf(
+ binding.tvIndex,
+ ).forEach { button ->
+ button.setOnClickListener(this)
+ }
+ binding.rvDevices.adapter = deviceAdapter
+ deviceAdapter.setOnItemChildClickListener { adapter, view, position ->
+ when (view.id) {
+ R.id.img_tips -> {
+ val device = deviceAdapter.data[position]
+ DeviceActionPopupWindow(requireContext()).show(
+ view,
+ onRename = {//重命名
+ showEditDialog(
+ "设备重命名", device.name, click = object : OnDialogClick {
+
+ override fun onCancelClick() {}
+ override fun onConfirmClick(content: String) {
+ presenter?.renameDevice(device.deviceNo, content)
+ }
+ }
+ )
+ },
+ onUnbind = {//解绑设备
+ showDialogtext(
+ "提示",
+ "确定要解绑该设备?",
+ "确定",
+ "取消",
+ object : OnDialogClick {
+ override fun onCancelClick() {
+ }
+
+ override fun onConfirmClick() {
+ // 用户确认后,按设备编号请求解绑
+ pendingUnbindPosition = position
+ presenter?.unbindDevice(device.deviceNo)
+ }
+ }
+ )
+ }
+ )
+ }
+ }
+ }
+ }
+
+ override fun initData(savedInstanceState: Bundle?) {
+ super.initData(savedInstanceState)
+ binding.refresh.setRefreshHeader(CustomRefreshHeader(requireContext()))
+ binding.refresh.setRefreshFooter(ClassicsFooter(requireContext()))
+ binding.refresh.setOnRefreshListener {
+ currentPage = FIRST_PAGE
+ requestDeviceList()
+ }
+ binding.refresh.setOnLoadMoreListener {
+ currentPage++
+ requestDeviceList()
+ }
+ requestDeviceList()
+ }
+
+ override fun onClick(view: View) {
+ when(view.id){
+ R.id.tv_index ->{
+ goTo(BindDeviceActivity::class.java,null)
+ }
+ }
+ }
+
+ override fun getBindDeviceListSuccess(devices: List) {
+ if (currentPage == FIRST_PAGE) {
+ deviceAdapter.setList(devices)
+ } else {
+ deviceAdapter.addData(devices)
+ }
+ binding.refresh.finishRefresh()
+ binding.refresh.finishLoadMore()
+ binding.refresh.setNoMoreData(devices.size < PAGE_SIZE)
+ binding.relNoMore.visibility =
+ if (deviceAdapter.data.isEmpty()) View.VISIBLE else View.GONE
+ }
+
+ override fun bindDeviceSuccess(message: String) {
+
+ }
+
+ /** 设备重命名成功后提示用户并重新加载第一页数据。 */
+ override fun renameDeviceSuccess(message: String) {
+ showMessage(message)
+ currentPage = FIRST_PAGE
+ requestDeviceList()
+ }
+
+ /** 设备解绑成功后先播放删除动画,再延迟刷新第一页数据。 */
+ override fun unbindDeviceSuccess(message: String) {
+ showMessage(message)
+ val removedPosition = pendingUnbindPosition
+ pendingUnbindPosition = null
+ if (removedPosition != null && removedPosition in deviceAdapter.data.indices) {
+ deviceAdapter.data.removeAt(removedPosition)
+ deviceAdapter.notifyItemRemoved(removedPosition)
+ binding.relNoMore.visibility =
+ if (deviceAdapter.data.isEmpty()) View.VISIBLE else View.GONE
+ }
+ // 等待 RecyclerView 删除动画完成后再刷新,避免刷新结果立即覆盖动画。
+ binding.root.postDelayed({
+ if (!isAdded) return@postDelayed
+ currentPage = FIRST_PAGE
+ requestDeviceList()
+ }, REMOVE_ANIMATION_DELAY_MS)
+ }
+
+ /** 请求指定页的设备列表。 */
+ private fun requestDeviceList() {
+ presenter?.getBindDeviceList(
+ mapOf(
+ "pageNum" to currentPage.toString(),
+ "pageSize" to PAGE_SIZE.toString()
+ )
+ )
+ }
+
+ /** 请求失败时结束刷新状态并恢复上一次有效页码。 */
+ override fun showError(message: String) {
+ binding.refresh.finishRefresh(false)
+ binding.refresh.finishLoadMore(false)
+ if (currentPage > FIRST_PAGE) {
+ currentPage--
+ }
+ super.showError(message)
+ }
+
+ /** 接口暂无数据时提供临时设备,方便先验收列表布局。 */
+ private fun temporaryDevices(): List = 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
+ }
+
+}
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
new file mode 100644
index 0000000..a6ccb1e
--- /dev/null
+++ b/app/src/main/java/com/juhabi/birds/device/entity/DeviceEntity.kt
@@ -0,0 +1,20 @@
+package com.juhabi.birds.device.entity
+
+import java.io.Serializable
+
+data class DeviceEntity(
+ val address: String,
+ val deviceNo: String,
+ val hoodBattery: Int?,
+ val hoodConnected: String,
+ val hoodConnectedText: String,
+ val imei: String,
+ val lat: Double?,
+ val lng: Double?,
+ val model: String?,
+ val name: String,
+ val ringBattery: Int?,
+ val signalLevel: Int,
+ val signalText: String,
+ val status: String
+) : Serializable
diff --git a/app/src/main/java/com/juhabi/birds/login/LoginActivity.kt b/app/src/main/java/com/juhabi/birds/login/LoginActivity.kt
index 2ba6768..f2ea6af 100644
--- a/app/src/main/java/com/juhabi/birds/login/LoginActivity.kt
+++ b/app/src/main/java/com/juhabi/birds/login/LoginActivity.kt
@@ -15,6 +15,7 @@ import com.juhabi.birds.login.model.UserEntity
import com.juhabi.birds.login.mvp.LoginContract
import com.juhabi.birds.login.mvp.LoginImpl
import com.juhabi.birds.login.mvp.LoginPresenter
+import com.juhabi.birds.main.MainActivity
import com.juhabi.birds.mine.MineCenterActivity
import com.juhabi.birds.network.TokenManager
import com.juhabi.birds.util.SharedPreferencesUtil
@@ -191,7 +192,7 @@ class LoginActivity : BaseActivity(),
SharedPreferencesUtil.putBoolean(this, KEY_USER_LOGIN, AppConfig.USER_LOGIN)
ToastUtil.showShort(mContext, "登录成功")
- startActivity(Intent(this, MineCenterActivity::class.java))
+ startActivity(Intent(this, MainActivity::class.java))
finish()
}
diff --git a/app/src/main/java/com/juhabi/birds/login/model/UserEntity.kt b/app/src/main/java/com/juhabi/birds/login/model/UserEntity.kt
index d8c9ce8..1cf6534 100644
--- a/app/src/main/java/com/juhabi/birds/login/model/UserEntity.kt
+++ b/app/src/main/java/com/juhabi/birds/login/model/UserEntity.kt
@@ -1,11 +1,8 @@
package com.juhabi.birds.login.model
import com.google.gson.annotations.SerializedName
+import java.io.Serializable
data class UserEntity(
- val scope: Any? = null,
- val openid: Any? = null,
- @SerializedName("access_token")
- val token: String = "",
-
-)
+ val token: String
+) : Serializable
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 a31f7ad..3d6d159 100644
--- a/app/src/main/java/com/juhabi/birds/main/MainActivity.kt
+++ b/app/src/main/java/com/juhabi/birds/main/MainActivity.kt
@@ -10,8 +10,8 @@ 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.main.fragment.HomeFragment
-import com.juhabi.birds.main.fragment.MineFragment
+import com.juhabi.birds.device.IndexFragment
+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
@@ -42,7 +42,7 @@ class MainActivity : BaseActivity(),
override fun initView(savedInstanceState: Bundle?) {
binding.viewPager.adapter = MainPagerAdapter(
this,
- listOf(HomeFragment(), PlanFragment(), HistoryFragment(), MineFragment())
+ listOf(IndexFragment(), PlanFragment(), HistoryFragment(), MineFragment())
)
binding.viewPager.offscreenPageLimit = 1
binding.viewPager.registerOnPageChangeCallback(object : androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback() {
diff --git a/app/src/main/java/com/juhabi/birds/main/fragment/HomeFragment.kt b/app/src/main/java/com/juhabi/birds/main/fragment/HomeFragment.kt
deleted file mode 100644
index 2be01ab..0000000
--- a/app/src/main/java/com/juhabi/birds/main/fragment/HomeFragment.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.juhabi.birds.main.fragment
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import com.juhabi.birds.base.BaseFragment
-import com.juhabi.birds.databinding.FragmentHomeBinding
-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
-
-class HomeFragment : BaseFragment(),
- HomeContract.HomeView {
-
- override fun createBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentHomeBinding {
- return FragmentHomeBinding.inflate(inflater, container, false)
- }
-
- override fun createPresenter(): HomePresenter {
- return HomePresenter(HomeImpl())
- }
-
- override fun initView(savedInstanceState: Bundle?) {
- }
-}
diff --git a/app/src/main/java/com/juhabi/birds/main/fragment/MineFragment.kt b/app/src/main/java/com/juhabi/birds/main/fragment/MineFragment.kt
deleted file mode 100644
index 4359d79..0000000
--- a/app/src/main/java/com/juhabi/birds/main/fragment/MineFragment.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.juhabi.birds.main.fragment
-
-import android.content.Intent
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import com.juhabi.birds.base.BaseFragment
-import com.juhabi.birds.databinding.FragmentMineBinding
-import com.juhabi.birds.main.fragment.mine.mvp.MineFragmentContract
-import com.juhabi.birds.main.fragment.mine.mvp.MineFragmentImpl
-import com.juhabi.birds.main.fragment.mine.mvp.MineFragmentPresenter
-import com.juhabi.birds.mine.MineCenterActivity
-
-class MineFragment : BaseFragment(),
- MineFragmentContract.MineView {
-
- override fun createBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentMineBinding {
- return FragmentMineBinding.inflate(inflater, container, false)
- }
-
- override fun createPresenter(): MineFragmentPresenter {
- return MineFragmentPresenter(MineFragmentImpl())
- }
-
- override fun initView(savedInstanceState: Bundle?) {
- binding.openComponentCenterButton.setOnClickListener {
- startActivity(Intent(requireContext(), MineCenterActivity::class.java))
- }
- }
-}
diff --git a/app/src/main/java/com/juhabi/birds/mine/MineFragment.kt b/app/src/main/java/com/juhabi/birds/mine/MineFragment.kt
new file mode 100644
index 0000000..89b19aa
--- /dev/null
+++ b/app/src/main/java/com/juhabi/birds/mine/MineFragment.kt
@@ -0,0 +1,50 @@
+package com.juhabi.birds.mine
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import com.juhabi.birds.base.BaseFragment
+import com.juhabi.birds.databinding.FragmentMineBinding
+import com.juhabi.birds.mine.model.MineUserInfo
+import com.juhabi.birds.main.model.AppVersionInfo
+import com.juhabi.birds.mine.mvp.MineContract
+import com.juhabi.birds.mine.mvp.MineImpl
+import com.juhabi.birds.mine.mvp.MinePresenter
+
+/**
+ * 个人中心
+ */
+class MineFragment : BaseFragment(),
+ MineContract.MineView {
+
+ override fun createBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentMineBinding {
+ return FragmentMineBinding.inflate(inflater, container, false)
+ }
+
+ override fun createPresenter(): MinePresenter {
+ return MinePresenter(MineImpl())
+ }
+
+ override fun onResume() {
+ super.onResume()
+ /** 页面恢复显示时重新请求当前用户的个人信息。 */
+ presenter?.getUserInfo()
+ }
+
+ override fun initView(savedInstanceState: Bundle?) {
+ }
+
+ /** 将个人信息请求结果更新到个人中心页面。 */
+ override fun getUserInfoSuccess(userInfo: MineUserInfo) {
+ showMessage("个人信息获取成功")
+ }
+
+ /** 版本检测回调,个人中心暂不处理版本信息。 */
+ override fun onVersionChecked(versionInfo: AppVersionInfo) {
+ }
+
+ /** 显示获取个人信息失败的原因。 */
+ override fun showError(message: String) {
+ showMessage(message)
+ }
+}
diff --git a/app/src/main/java/com/juhabi/birds/mine/model/UserInfoEntity.kt b/app/src/main/java/com/juhabi/birds/mine/model/UserInfoEntity.kt
new file mode 100644
index 0000000..94fa4fd
--- /dev/null
+++ b/app/src/main/java/com/juhabi/birds/mine/model/UserInfoEntity.kt
@@ -0,0 +1,14 @@
+package com.juhabi.birds.mine.model
+
+import java.io.Serializable
+
+
+data class UserInfoEntity(
+ val createTime: String,
+ val email: String,
+ val nickName: String,
+ val phoneBound: Boolean,
+ val phoneNumber: String,
+ val userName: String,
+ val userType: String
+): Serializable
\ No newline at end of file
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 2a50e12..b4d88c2 100644
--- a/app/src/main/java/com/juhabi/birds/network/ApiService.kt
+++ b/app/src/main/java/com/juhabi/birds/network/ApiService.kt
@@ -1,5 +1,6 @@
package com.juhabi.birds.network
+import com.juhabi.birds.device.entity.DeviceEntity
import com.juhabi.birds.login.model.UserEntity
import com.juhabi.birds.login.model.SendCodeEntity
import com.juhabi.birds.main.model.AppVersionInfo
@@ -7,10 +8,13 @@ import com.juhabi.birds.mine.model.MineUserInfo
import okhttp3.RequestBody
import retrofit2.Call
import retrofit2.http.Body
+import retrofit2.http.DELETE
import retrofit2.http.HeaderMap
import retrofit2.http.GET
import retrofit2.http.QueryMap
import retrofit2.http.POST
+import retrofit2.http.PUT
+import retrofit2.http.Path
/**
* 项目统一接口定义。所有业务接口地址集中维护在这里。
@@ -115,8 +119,57 @@ interface ApiService {
fun forgetPsdByEmail(@HeaderMap headers: Map, @Body requestBody: RequestBody): Call>
+ /**
+ *查询设备列表
+ */
+ @GET("app/device/list")
+ fun getBindDeviceList(@HeaderMap headers: Map, @QueryMap params: Map): Call>>
- @GET("app/v1/getUserInfo")
+
+ /**
+ * 绑定设备
+ {
+ "imei": "860000000000007",
+ "name": "001设备"
+ }
+ */
+ @POST("app/device/bind")
+ fun bindDevice(@HeaderMap headers: Map, @Body requestBody: RequestBody): Call>
+
+ /**
+ * 设备重新命名
+ {
+ "deviceNo": "BM202609160007",
+ "name": "改名001"
+ }
+ }
+ */
+ @PUT("app/device/{deviceNo}/name")
+ fun deviceRename(@HeaderMap headers: Map, @Path("deviceNo") deviceNo: String, @Body requestBody: RequestBody): Call>
+
+
+ /**
+ * 眼罩控制
+ {
+ "deviceNo": "BM202609160007",
+ "coverOn": true
+ }
+ */
+ @PUT("app/device/{deviceNo}/hood")
+ fun controlEye(@HeaderMap headers: Map, @Path("deviceNo") deviceNo: String, @Body requestBody: RequestBody): Call>
+
+
+ /**
+ * 解绑设备
+ */
+ @DELETE("app/device/{deviceNo}")
+ fun unbindDevice(@HeaderMap headers: Map, @Path("deviceNo") deviceNo: String): Call>
+
+
+ /**
+ * 获取个人信息
+ */
+ @GET("app/user/profile")
fun getMineUserInfo(@HeaderMap headers: Map, @QueryMap params: Map): Call>
diff --git a/app/src/main/res/layout/bind_device_layout.xml b/app/src/main/res/layout/bind_device_layout.xml
new file mode 100644
index 0000000..5c0d0b5
--- /dev/null
+++ b/app/src/main/res/layout/bind_device_layout.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
\ 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
new file mode 100644
index 0000000..bc63ddf
--- /dev/null
+++ b/app/src/main/res/layout/device_item.xml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index 7450be1..b04312b 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -1,8 +1,11 @@
-
+ xmlns:tools="http://schemas.android.com/tools"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:background="@color/page_background"
+ android:orientation="vertical">
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/layout_no_more.xml b/app/src/main/res/layout/layout_no_more.xml
new file mode 100644
index 0000000..d637a24
--- /dev/null
+++ b/app/src/main/res/layout/layout_no_more.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_refresh_header.xml b/app/src/main/res/layout/view_refresh_header.xml
new file mode 100644
index 0000000..f8763fa
--- /dev/null
+++ b/app/src/main/res/layout/view_refresh_header.xml
@@ -0,0 +1,11 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_navigation_menu.xml b/app/src/main/res/menu/bottom_navigation_menu.xml
index 2ebdc84..f146994 100644
--- a/app/src/main/res/menu/bottom_navigation_menu.xml
+++ b/app/src/main/res/menu/bottom_navigation_menu.xml
@@ -7,11 +7,13 @@
+ android:title="@string/tab_plan"
+ android:visible="false"/>
+ android:title="@string/tab_history"
+ android:visible="false"/>
- Px#1am@3R0s$N2z&@+hyVZ-^GQTORCt`-oPCTP*LmKb=RGrbm*g%fQld!Fk}c7s
zEK4RCTWaE{0V3H>3^-8)eaA+CHg4KFKpUh*P@ri4NPz|^+CQ2Gh+?~6XcET|Wm^dx
zx3X)Ms%toL8%vh;EmE>VQj|ne;x4(%z4y+X_vs(!%-nmIyEJ#X+>P=A7kB2~xifQq
z^SmE(&Y4TBk=^#}{)w<|awmJ(6%E?~yce!XKocS-AWQ;)OK-vmxG3rnfHy?E5o0_w
zhTg%)Z@PbGEzX~-d9aVZ@IUsN@m9Lt>%x!009SJkA`&Qq21o<}Nc6No0g%MzyhRYM
zC!IJ1g>U`&O`mvjwc2vY!TsDz-`rWNzDvMfNZSPfWNJ7>mxv4oKLT9ZHl26cPX;Ja
zBmm7o+%Nc(e{th4JaH-8b;-be{G~@fW{#h6axWyp0J$g_K(*kKiogp7X8?R2IDlD+
zL;K{DM*XKt1#rc|{oG5BeoU}WN!pGU1ku2A7hA=-C~LrB0A~oCON0_?Euc6_)UaY9
zBCFT|5_%$%|M7b(3~~qc*hL=i`zP{0TAstMA=-&+9AE-W36N$4lS%q`*(1jW_e$4>^tvH!iErAudUA
z^T7FVvKRvAP20`^tIt32fxA9`v2DI6aCaU0`jxf9Z$Z9IX?H2sG*>$-CY|uWUFD>P
z;@og%Rcbd!V;lzYZz!V$C0A{U;{0|EtKvM0Q_>?x<6Al|
z7E)Ui+w$=MKuvha$I8Gz_tc)dKf6>0OIF<7FMjg@b3A}nNy*sM7?3i|1yq-pjmlce
z%ZmywZ#9xpThju|t=dMjaJ%fy1!>A4@-zFM{>o>T%3(?1?tSU8UsmA#NcBJtI25w0
z4O})YbFh-Dhk47**Yma;J;4RG%-OUB&?KJ$rgo+E1RKrNjXEXKiC^9G%p?D7DJ(A7
zRqs9c_7ih;ZL;N$lJ
z@qV;d*WeW4^Wn`aIWj!QP@M)*($jGJpD}iS@YtR^-@MR^H*B{(dtjoAGoJwQ(*i!!
zmLT(DTgs?58rK?V%r)Oox#NZhpZ~x;4_-952VVT<-%_yO@O%PrZ^4Lc;W-C^8bEUo
zI#R32<6~9b|H5)%EoL`A_vNdChhGHw^8zL{tbCFSLd)kl?6Pf%B>ao#_ul&_=R4+k
z!QFT8TU&$G|3=~lWq0r)c*DwTB2MFqZSe|H#A6lxkH4|&BsJWZLwpW7u+XbKJeQvTsuhJO>9cP9mKE{
z^ORGk&{X?8?u`H8Yr8)F%t}K#pMB^DkK7Ei-vqIvQQL?Lhm@AGY%Y(oYp1&p9eZ)#
zeIH%y7>j1rPrdxV?F`{c0$S8xu$17|KYou1XAuBCn=~2KMCSM2n4~J
z{Fe*u_Z)D4_lE~=AoxBC3Jgw2DT)OrAcNH20Rb`$;7Rzek6iz;KU)Y;n)?{fjg6?YOTW&x5h!66q{Uxv5;E7yPIYpcX!
z$@a{iyZ*=x4`N7VNdc)L-X=F$`W{WM4I}vL^Y=Fb?$fV)`+bDoXM&7$=CX&RTdTHn
z)ko;@FYW&5!>dYS8TR}K?s?FOKbarz+}#?LHNbN5Y)O%R&AXr4fA8?VMipoHg*+gT
zvZt5mEme)g+7ZaKRq6qaEx-f-s`h4|0i-A3IqDa>>8
zqRTviuoUn7*6rW_!$4|5wB#8JJ139N*|lz>@2_<=aIQNXmYt*~h?Dg^!SQ=J;lwAu4?aR{|*JOQqR$
z<7d9GR*k<{>(2FmHz^DQg#p$8lVk!jG%?Ce(BE!;ZvgOXNB&|rq45BS7Lq%XPMHGf
z!Qg?x8#kuW4fsEw-*Lw~#zp7bYajllqXNF{L;_}mgy1>THi~m8-6lcrzVgXGycG>N
zkJxKSu1PVwA)RPqT3Qc))8IyW99#E|wQl^yTFvTrhT*tiQ8JfXlq}{L=a5Nmo>ce=
zG~meiE&?($50C;<`4O07TUHtKdT_n)2Uq{ZTWj6$i?!GG{nF9s`mO*=;AFC#5SU;!
z@y`WQDpmFXK=DtGd}m#R?S#vl4sbA4hRsl3JG91B2E({&lUpvex%^?serj;
>$qUdyXs9Wa(+TidE3e3MHlza4zkc*vwKVQSPuBcTpd?(PY>7yGO
z%*o@Nd2ANV;5OhG-(z)*JB)NgdIhG;89)z&8{~ud2M^@oe}B!bb8Fq;m9n>g{F6r<
zcrHpIBGvp3wXW;J&~h$afW1Xo+h$MtN?njjJ)sCmUB=J~P7+;yaIG7=(pE#?0kki<
zDB97mb{tw}oC0Km4#21#p&N2>>(`%m;I;fHYsoD7XU#oPA|_
z96)c)ns*5-PXP-6a0tLIK)21?WO!xg&YduTa|U@JW4fzN@eWF#k&K9NGDMQG93R`b
zy3JY@BY^Na5OyV1g`=a23$NnUcKzm?Z>E*-G5tXGIZW0KBjeBYf*x
zxAGELI0=NS06UR^T@BcqL-4M}wZrZTlXc!O3y}sV-~pEIQzZ|Q7i6^9C=y;6C)c`_
zD{V)CVrFV8oWiLP0DC(F3xJ(Gc`_gYwG$^!G$2vX<1|IlEZ=dMAWt(GJ@s;iqHs7s
zgPg@xYu(V5whgCFb!ImQGi(&5r?F|%CQSjD!4x)K5d=U10Ja7I&~wi{2OAfTo0-$o
zD6JtXAoc!Q!Dv>*)CmeF=!Ij;e?IZT-x$?NVy`Sa0W`FwHgo#4ZN_D^X|p^L
z)(l(h)v2j){P=M%Ft`3hnCv?X6X0+sU?z(WYrCW*vmnSpGxdNS0A5_{Mz4gu4y+3k
zG+{z#XJ!y4(@0*}n7SoTZ!)A|($f$&YV&26;o947i}q`~clV4uqUa)WU!3H@=s}hS
zYRnua2k4A)M(tkf2CtM&0PE(?(hRdUN1Dyj&SJ)FhBk{C3p2D?oUz$6Ns$qVX}VjQ
zse2+=8U_qz-n^`V1*W87<{_AOtl0K@$Df^8>qcL!NeZXu=GFz$x}Z&L*uXi`47BE*
z6B9JhI628#%vc3PG#O%?;gw+K0ZCa({l|`&K>}&;MsmoULEfp053Y5?FV+rYdSj1W
z>tW7pj@HGT1>+{o+x;LM>b*R1u+v?DsQ
zZoKE42+-JLHBFljkR-Vd>|xG`q{6AGseZGM7TiC&`u%Tt^w$N*qLRDDRM!#aYJj2i
z^h6M(2$fxZ_;XUZW)zlal5Dnn#r8hHagbH7ZyZkm*&XKyz-|KAW7im~{_fqo+s=)V
z-ZqYfmqO|hmLbi&6hfMT2`Rg9R-~o%!1bHoI{J=D6wjYMxecs3GyT5J^!qkGHpcPv
z)G;geY$1RIsflgV!}}Ql_bZ!r9g_QuJdI~3*UZ4oTuL(v4Nwux1tsONx_19te|6)k
zQ&^%MJacAibY4b+`HunE@AugUXuZDmd+DD~lxJIILI}8V|MZbvt4d-C_PkDC-bepR>yWek%1E#elAZM4CpkWr+}FsY
zHuh+}9y?dsmId1=?Sp
zK6XVldv-?+vg(6l9iRe9g8hD0-jMpnF;L`qS#_@?yYu(C@N*8F{C^UpkX074vVvp^
zdD3(mF*HCHOo$PtAlKa9FP;414XXje*YCz>db{aryK5JZeNPW!7u(Hk%Cu?{|f2w0G$ARxjr$QT=NCLlrz8E{G{4nO?X%O{`thqv5PT~acO
z*nTP8)IIgCeyq0$Qi)Q1R1l<69Tku&03{&LLXe*5fb#&hWX-UIx%duyr&UdHYxNhD0^7yC{dvz*=OA+
ziHa3K>ywQ;mypk1_S&M4T;f6=^!?(gA6{#&A5V#4pu8rgDGb~-AgK9g0#hn!ECeCe
zpp|`v>gd_2@ap~7T(hFn#QyuigJWB_ZhV)@a5?GJ#3*2X|2s39ki79b>rpn$Zk1X)qM
zfBZv}SDpA#$G_k|GuZ#u!5b};loL11%t^&WbbTK%3PTAk`5FA!XoL16BkDrMMHR
zGacgXI*gqeTVKopQ(XYKo!4~%;D8Pkc=g(%-n40K-B{dES{$pp^(KaLy#R$msw*G>
zD#}7tRiOaXsIIC~j4MhdXhMR9K1!78_bZg0R(Z$wO>V!Sr?{8&hb@2l_A7h)Zo7t+
z79(Iet^svY;*g69L809qNtt!s#=?*l;e|5HAk^t105z-#d8!%|P^hkJghDD%NCku%
zkksx+kcy&AYe&OFC`K|x`x^{>nipAf8
zT@xixR~3me&Gf6-CJUk>&;bEG8pfHG~+
zsIEkbMs;Pm9(7f*uE??kDut?!y~E3ahKrfRb>jvQbC#Vuqt2C9nHs3K7ysjlrUObgYFR~shYIC$%(YZkmKxDZ>BKi>P=
z>7&=jI$nu#tbgGu5ug1h$NnAX#l~qca3Al)sy&xD2jQ9BO3f#mGJi6sq!jThnFL6=fm!*b5$C
zyJh2!lPlTI6$jVYqti#W0N534Y-!XMLZLb*j$t>&klUWCxCG=vz@^_yp)7>hKV53#
z#4Q^)t|+j^E*ZGS9-Th2#nssyP`!t+RJda_zKwzl3dQ1zLk)zYXuE|5w^WdYy606f
zJ+>*nehYV8(r0NeIk;i_v#F`gp_;wY%Q!iPa2e)-Q^#c;hhs<;FWs%sz=L9y2K
z_`0zfp7pmseEH?4SF0_n3U1gANX6{*;mI-<6D-Pc1|KiIo~Wy&D7eOf8VXhwg;kK(
z{a#Uz8D>~ocdmDOws`9B?CrPTzN}7yi?#m`<2zx#{SjPx#1am@3R0s$N2z&@+hyVZ-^GQTORCt`-oPCTP*LmKb=RGrbm*g%fQld!Fk}c7s
zEK4RCTWaE{0V3H>3^-8)eaA+CHg4KFKpUh*P@ri4NPz|^+CQ2Gh+?~6XcET|Wm^dx
zx3X)Ms%toL8%vh;EmE>VQj|ne;x4(%z4y+X_vs(!%-nmIyEJ#X+>P=A7kB2~xifQq
z^SmE(&Y4TBk=^#}{)w<|awmJ(6%E?~yce!XKocS-AWQ;)OK-vmxG3rnfHy?E5o0_w
zhTg%)Z@PbGEzX~-d9aVZ@IUsN@m9Lt>%x!009SJkA`&Qq21o<}Nc6No0g%MzyhRYM
zC!IJ1g>U`&O`mvjwc2vY!TsDz-`rWNzDvMfNZSPfWNJ7>mxv4oKLT9ZHl26cPX;Ja
zBmm7o+%Nc(e{th4JaH-8b;-be{G~@fW{#h6axWyp0J$g_K(*kKiogp7X8?R2IDlD+
zL;K{DM*XKt1#rc|{oG5BeoU}WN!pGU1ku2A7hA=-C~LrB0A~oCON0_?Euc6_)UaY9
zBCFT|5_%$%|M7b(3~~qc*hL=i`zP{0TAstMA=-&+9AE-W36N$4lS%q`*(1jW_e$4>^tvH!iErAudUA
z^T7FVvKRvAP20`^tIt32fxA9`v2DI6aCaU0`jxf9Z$Z9IX?H2sG*>$-CY|uWUFD>P
z;@og%Rcbd!V;lzYZz!V$C0A{U;{0|EtKvM0Q_>?x<6Al|
z7E)Ui+w$=MKuvha$I8Gz_tc)dKf6>0OIF<7FMjg@b3A}nNy*sM7?3i|1yq-pjmlce
z%ZmywZ#9xpThju|t=dMjaJ%fy1!>A4@-zFM{>o>T%3(?1?tSU8UsmA#NcBJtI25w0
z4O})YbFh-Dhk47**Yma;J;4RG%-OUB&?KJ$rgo+E1RKrNjXEXKiC^9G%p?D7DJ(A7
zRqs9c_7ih;ZL;N$lJ
z@qV;d*WeW4^Wn`aIWj!QP@M)*($jGJpD}iS@YtR^-@MR^H*B{(dtjoAGoJwQ(*i!!
zmLT(DTgs?58rK?V%r)Oox#NZhpZ~x;4_-952VVT<-%_yO@O%PrZ^4Lc;W-C^8bEUo
zI#R32<6~9b|H5)%EoL`A_vNdChhGHw^8zL{tbCFSLd)kl?6Pf%B>ao#_ul&_=R4+k
z!QFT8TU&$G|3=~lWq0r)c*DwTB2MFqZSe|H#A6lxkH4|&BsJWZLwpW7u+XbKJeQvTsuhJO>9cP9mKE{
z^ORGk&{X?8?u`H8Yr8)F%t}K#pMB^DkK7Ei-vqIvQQL?Lhm@AGY%Y(oYp1&p9eZ)#
zeIH%y7>j1rPrdxV?F`{c0$S8xu$17|KYou1XAuBCn=~2KMCSM2n4~J
z{Fe*u_Z)D4_lE~=AoxBC3Jgw2DT)OrAcNH20Rb`$;7Rzek6iz;KU)Y;n)?{fjg6?YOTW&x5h!66q{Uxv5;E7yPIYpcX!
z$@a{iyZ*=x4`N7VNdc)L-X=F$`W{WM4I}vL^Y=Fb?$fV)`+bDoXM&7$=CX&RTdTHn
z)ko;@FYW&5!>dYS8TR}K?s?FOKbarz+}#?LHNbN5Y)O%R&AXr4fA8?VMipoHg*+gT
zvZt5mEme)g+7ZaKRq6qaEx-f-s`h4|0i-A3IqDa>>8
zqRTviuoUn7*6rW_!$4|5wB#8JJ139N*|lz>@2_<=aIQNXmYt*~h?Dg^!SQ=J;lwAu4?aR{|*JOQqR$
z<7d9GR*k<{>(2FmHz^DQg#p$8lVk!jG%?Ce(BE!;ZvgOXNB&|rq45BS7Lq%XPMHGf
z!Qg?x8#kuW4fsEw-*Lw~#zp7bYajllqXNF{L;_}mgy1>THi~m8-6lcrzVgXGycG>N
zkJxKSu1PVwA)RPqT3Qc))8IyW99#E|wQl^yTFvTrhT*tiQ8JfXlq}{L=a5Nmo>ce=
zG~meiE&?($50C;<`4O07TUHtKdT_n)2Uq{ZTWj6$i?!GG{nF9s`mO*=;AFC#5SU;!
z@y`WQDpmFXK=DtGd}m#R?S#vl4sbA4hRsl3JG91B2E({&lUpvex%^?serj;>$qUdyXs9Wa(+TidE3e3MHlza4zkc*vwKVQSPuBcTpd?(PY>7yGO
z%*o@Nd2ANV;5OhG-(z)*JB)NgdIhG;89)z&8{~ud2M^@oe}B!bb8Fq;m9n>g{F6r<
zcrHpIBGvp3wXW;J&~h$afW1Xo+h$MtN?njjJ)sCmUB=J~P7+;yaIG7=(pE#?0kki<
zDB97mb{tw}oC0Km4#21#p&N2>>(`%m;I;fHYsoD7XU#oPA|_
z96)c)ns*5-PXP-6a0tLIK)21?WO!xg&YduTa|U@JW4fzN@eWF#k&K9NGDMQG93R`b
zy3JY@BY^Na5OyV1g`=a23$NnUcKzm?Z>E*-G5tXGIZW0KBjeBYf*x
zxAGELI0=NS06UR^T@BcqL-4M}wZrZTlXc!O3y}sV-~pEIQzZ|Q7i6^9C=y;6C)c`_
zD{V)CVrFV8oWiLP0DC(F3xJ(Gc`_gYwG$^!G$2vX<1|IlEZ=dMAWt(GJ@s;iqHs7s
zgPg@xYu(V5whgCFb!ImQGi(&5r?F|%CQSjD!4x)K5d=U10Ja7I&~wi{2OAfTo0-$o
zD6JtXAoc!Q!Dv>*)CmeF=!Ij;e?IZT-x$?NVy`Sa0W`FwHgo#4ZN_D^X|p^L
z)(l(h)v2j){P=M%Ft`3hnCv?X6X0+sU?z(WYrCW*vmnSpGxdNS0A5_{Mz4gu4y+3k
zG+{z#XJ!y4(@0*}n7SoTZ!)A|($f$&YV&26;o947i}q`~clV4uqUa)WU!3H@=s}hS
zYRnua2k4A)M(tkf2CtM&0PE(?(hRdUN1Dyj&SJ)FhBk{C3p2D?oUz$6Ns$qVX}VjQ
zse2+=8U_qz-n^`V1*W87<{_AOtl0K@$Df^8>qcL!NeZXu=GFz$x}Z&L*uXi`47BE*
z6B9JhI628#%vc3PG#O%?;gw+K0ZCa({l|`&K>}&;MsmoULEfp053Y5?FV+rYdSj1W
z>tW7pj@HGT1>+{o+x;LM>b*R1u+v?DsQ
zZoKE42+-JLHBFljkR-Vd>|xG`q{6AGseZGM7TiC&`u%Tt^w$N*qLRDDRM!#aYJj2i
z^h6M(2$fxZ_;XUZW)zlal5Dnn#r8hHagbH7ZyZkm*&XKyz-|KAW7im~{_fqo+s=)V
z-ZqYfmqO|hmLbi&6hfMT2`Rg9R-~o%!1bHoI{J=D6wjYMxecs3GyT5J^!qkGHpcPv
z)G;geY$1RIsflgV!}}Ql_bZ!r9g_QuJdI~3*UZ4oTuL(v4Nwux1tsONx_19te|6)k
zQ&^%MJacAibY4b+`HunE@AugUXuZDmd+DD~lxJIILI}8V|MZbvt4d-C_PkDC-bepR>yWek%1E#elAZM4CpkWr+}FsY
zHuh+}9y?dsmId1=?Sp
zK6XVldv-?+vg(6l9iRe9g8hD0-jMpnF;L`qS#_@?yYu(C@N*8F{C^UpkX074vVvp^
zdD3(mF*HCHOo$PtAlKa9FP;414XXje*YCz>db{aryK5JZeNPW!7u(Hk%Cu?{|f2w0G$ARxjr$QT=NCLlrz8E{G{4nO?X%O{`thqv5PT~acO
z*nTP8)IIgCeyq0$Qi)Q1R1l<69Tku&03{&LLXe*5fb#&hWX-UIx%duyr&UdHYxNhD0^7yC{dvz*=OA+
ziHa3K>ywQ;mypk1_S&M4T;f6=^!?(gA6{#&A5V#4pu8rgDGb~-AgK9g0#hn!ECeCe
zpp|`v>gd_2@ap~7T(hFn#QyuigJWB_ZhV)@a5?GJ#3*2X|2s39ki79b>rpn$Zk1X)qM
zfBZv}SDpA#$G_k|GuZ#u!5b};loL11%t^&WbbTK%3PTAk`5FA!XoL16BkDrMMHR
zGacgXI*gqeTVKopQ(XYKo!4~%;D8Pkc=g(%-n40K-B{dES{$pp^(KaLy#R$msw*G>
zD#}7tRiOaXsIIC~j4MhdXhMR9K1!78_bZg0R(Z$wO>V!Sr?{8&hb@2l_A7h)Zo7t+
z79(Iet^svY;*g69L809qNtt!s#=?*l;e|5HAk^t105z-#d8!%|P^hkJghDD%NCku%
zkksx+kcy&AYe&OFC`K|x`x^{>nipAf8
zT@xixR~3me&Gf6-CJUk>&;bEG8pfHG~+
zsIEkbMs;Pm9(7f*uE??kDut?!y~E3ahKrfRb>jvQbC#Vuqt2C9nHs3K7ysjlrUObgYFR~shYIC$%(YZkmKxDZ>BKi>P=
z>7&=jI$nu#tbgGu5ug1h$NnAX#l~qca3Al)sy&xD2jQ9BO3f#mGJi6sq!jThnFL6=fm!*b5$C
zyJh2!lPlTI6$jVYqti#W0N534Y-!XMLZLb*j$t>&klUWCxCG=vz@^_yp)7>hKV53#
z#4Q^)t|+j^E*ZGS9-Th2#nssyP`!t+RJda_zKwzl3dQ1zLk)zYXuE|5w^WdYy606f
zJ+>*nehYV8(r0NeIk;i_v#F`gp_;wY%Q!iPa2e)-Q^#c;hhs<;FWs%sz=L9y2K
z_`0zfp7pmseEH?4SF0_n3U1gANX6{*;mI-<6D-Pc1|KiIo~Wy&D7eOf8VXhwg;kK(
z{a#Uz8D>~ocdmDOws`9B?CrPTzN}7yi?#m`<2zx#{SjPx#1am@3R0s$N2z&@+hyVZ}07*naRCt{2eQS^%$93L!PS1TTb{D{ccn}~c10+F8
zfIx}_%aLd)7NUn~sYHsDKt19pwu*|%<&-K)ek7H|k>ph6X**R)Dpn|&lw^^%
z9<(Kap=3p-`4B__d@M*%BnT1@F0k0=y?3U+{OInPo_l8(i^T%FAaM$dy*tx)W^RA;
zo%5YD-F*e;xxIPsodc5eT@EW3L(SzNF9taP08qUc0BE@$00@keoN)Uv4qzORanc^9
z$Z(dV`x~v+i}!82ZG2Hb)ESyA_63}-z2))mUacb6Sl}7~F1NIU#m8X&c`PXq^_%^6
z39rTPkJiuot{=eJy&KDPLv`e!BIh
zhtF+q&1_2o)OSAly|-r2e<Vz5#R*~|JMUsZ~pdK?YvoRQ9%98;lF;p5+4D1u|=6-jsc-#+2w8(
ztca_2A(*NFY!F6~Nb;aDzD7hq=is{b)}2s5ykJ#6_0S?P_nd-y%l>=Uwy7V4K%ttc3%v5CeO9*c!-Jur&r1RdIDTrUvg2-9VB1ojIPysyBEMBF}Tdz|`V~
zA-a^i4;uu=MD4$L_%*jYwBQ{ce~`0bH$8Fh`=R>&TxBv+u<)WM04TGuwO~Zymdh@<
zNg6<+yrY3iW-*&$hq&4;Q-MaW+7`W&gcvEt7vm
z*vo(@?v#Lapdxa^Gso5{7u*|HyM>AaRU|&%j7*&|o}wg(N-RZi=jggAW)2tVN`*w^
z3AE&&KXTp8hZYh8UC4vovj5(-wC3LnxLJ^E9gia*lHd3Y;y-M2zv*vvZ_MAw@|i5U
zEo4EbY8P)Qzk%gbla6;Kb=+lfC98XvW$!+gw~@RmtJ}|C`|#ZxW<19{Y{5XiWzW59
zVa*?iVhy|t&;UjRiUjx21(d`W69HY-qwzM;ZouOx~zsGj{9lehKwm}>fKvp;z3SbLB;{Z`+@FiKA
z-Ffw%yRYi~B&Tm@4C=cN?B1jqKLv}m2&}OMcp5WFBnQ^t?v*Ud+j_QlGrNj~-Ha~&
zF1L&S$~)EuH(D+YmM;f|pQ&W2e{ZDd9ZR)nm%Ck*a#<(Xu$-EHaUp;`BcZfw`2IB+
z+J7iOKimTjDV|BXM_HkRtQR!pT50IKB6qD)!bJtAOI1esDwTU+F<})?fp`j%jWgB5
z0C1mw{`uy;cMbsk0|3xMI$%t41v0yy;CfMW1ud^E<)_`Mw@}yxOC>6NR8+ofmq_b5
zZV3kg1&2C`e)x%3&tE*v8`NFH_pc$+PXb(9)m__+mtVpi%?e|7P1Ow9MQ1bg$|I|o{5Y=P+C2XHNbD^Zo3cIBm^cHErdNI!4^SSoZu{Z3!`&x)xN8o)VmsjSck@v{^A?mb2nV+UZr##TU2cxwXom6_sSc;KcDMe2z&j$d#+fc1^t7g$p%Q=A5}-xJ
zjh}h!>i2%;bguEVK;1R`{jDnc?{W_m*KQ+Vi<)N_V`JeI7wo&@D`Afa<&M9+>g_)`
zo$EW7wqxHt*9rLvl9!;{?e-|$_=(M_7^-;*GwieEKYj9=U32b>IfJ@u`2ICUv;Rms
zrCV}8(pwlubO%?(*qP$11-|;7E8l)j9#NgCUG?L;2m4pr4*>E{AQVu#80sJRcdKbs
z#Mj_*LuoSxn>6F+|qdAOx}x>NwlF7-nW|G`zXe5~D~dWdDx$?B4DWv7
zi?)J-wXmV^TQFAW8S9Srg_jec0I+A6WC>d(DB1-Y@*c~W(j26e)t{5vS0oVB3)+r?TJ21;?Zi?K@i(zmX9%L5D7jZ4pdzU}6Ftd-xNiJ`rN2Bepr
zK0pQG1o7ok#lM~H+%tmukDmI`8=<(!DOTr7z1xLCoZI#LM3ezs6`=-6C;lez0!pE@
zv|s-EmYw%4crPwN+k4HeKLq$+N`lBes`4y!jtdNI@Y^-$;{s>^5{>S-^s+sFHe;n}
zMo?9FvzJ{C7!~>=rUQ}wlryl_AI8U7=Z+oFwJUkv-j_V@fLfj=Ro2
zlU=dX#o-WR9hf2iCEUIY_-8Ynvl7$~KmFsYROBLMV3-G2%HXOf6+Vseu{N+)V|NS!
zMjp89vYlT)i~YA`?XlOs=TAs{tE_GXC3ZUZ>RemoY70&21XnR5fS0~%&zo@TNDz44^ij*g>)>H!W}!-9+_$m{?D`6Z%f`Rv(Jz`1kkBr&$tjf
zsZn(EJiE(8-Nhde!S{jJ)nO0=^tMuqE{BN)Pbui49qo}SNeQ0!9u-D)?7#x
ztToC%`il+MPo9ImTe9}#>u!6Vky4M19#amEaAvCb|8+TmxmS3K;-dn=vf&CvjJGiYaT9I=)=bQVpkQUrVxK1lCCt_h@$t*<*O+Tu=}+l-
z=zvuRu0kj|dn0C|m$@Jw`|{?UkDu!fJ0I-n?Yq87$lvCQ)&mBLcd;H!6kG{FA_CJ*
zBcZ^``{Lv0p#I)t-@gcyEduqikiNDH3Y98i9diSFXJ@WS?Y9=C$Icf^vrp&jvs5b(
z3#*QaR%c=*>43CwY$hR8-mvO{uU;AsorB83fvZ(W71D@Ufl^dMp2-q}J$sF+RS4CH
z^+gHmWA0;LzUl%?XR~K^y#J@9{B00F4!kZ_657p5OIJ1s<+`Ar6Jvif9J_G8nY~(a
zw)x@#=^5&_72t|>&K9g@uim{_opoLr?KjHtvWt}wkXZy|C{V=jwTd#RAAjyAeF9t(
z+DmY|P%1*zsGGrMfK|l0*o%oTUiQW(7PYg^6MOdB_uoa}c|wFaE3FppRk|2i5=>fD
znV=xHhvNpOULugDOK|Wj4kj=4@75#8oX^GK3z~1n$w@1|zW1
zSQr3?pcMen~#Z7SxXLR}!JDH{yrR
z0AQF8HYz9w}1x2`V|W2S{ok!QPcgNZ&f;f&`5Wz{
z8N;%tQp|XeVsNc%m(QL<5o?KJ>=K3&g*2kkf1Z)ijbbUt{JyT`ZD_5yD6SB4K^J&>
zrI|%GN+$Unv)tm9)X+6iCRz|IEMh}Y5)so7^()cXUW!+)Q=}fyVxkmkEA)a$Is=86C%Ey9U>zRS#`fpZaMqqgDDC(i6cT`<6_+XAZ4!&Pvy
zaw`a`8numhsEQDj%>OX@?ZzG1nSOv1(`W6|z7p)Z+ka{E;U--_D1L1CEp9ZT6^f01
zQ@ANHV(M{2dFKUC&(JLJ2Xkpx$RqY_0f0mzku;M@tavZjSueN
zDoY3)H=-+MKU?%V%mc^;l-uyh1G`s#a`Vm$k@d{%w3ZdT3wHr`mACEMwTp>?awfKl
zDtjEW#`|450{~4sc!AAlV7|C8E2s}W^bmIJ*pc`1F6;t!^)wST!sB72gQ{9Z@#DrH
zhLI3r-4ERl=te+LtWqrcFgx2X*j!AzfA;U+uc2tWW5*7O_w568-@bjiZ{NPW4O~n$
zba`r-l5Uc5WO+tfPNm>oG25nb_CNE>+B9bBK>#>-5LaAr1>@d+=9y;z0Gl>#;#L6I
zx;5+yZEPa2)5w$-fKjE*my8Kb%JH*EoeI!t0i($p|Gj4yY<^|{xMfdq7#p#U*tih@
zj}oU9*PA0Ku_i
z0DyI?*YW5&;ONn#0sw2)tl@e9hu5zMa2NoXXr`l7Unb1KbE7_E@Bl!N5E{i^w+5CQ
z2W*oKpB^4=d~C~>*17GA^WR9yC`M~T7$N{!1y^-Fv1%1o;5cy{;Of-`fRT|AF#uLM
zuyO3zF#&*et5*|P2LM)Ulg%R%M&d_hLN_F|P`_e9*bWF%)K{idEL1Hm2vu8aPF!%o
z^RS2TP%=KIdJ@osCr|1qAc9dD8Xc7(49U>YkSL%h0X?}&RaS`{KYm;l5M8}mR8>Ys
zMuGySer(H@mYQU$1fX96KtUQ6YarIB*d(cEMqR2CQXt7dqhb}LHMPx)-9hK0?ZA$@
z4niiz#&pH<Iff2I1t`8fR4lEFvp~jn8kQr!U~{pxIMxsmnVOtZ0c2`oN@YM~YGOkD;<9pN
zd|YKv9GHOUAaan$mP-yYfCALtz4Ud@!)7f7sYYltiP)G}H}fql6^H$J(@oZ2N@U{rnEuD5+p$aO3fm-Ya%zS+W(~^PiIMU+Y9m
zMMPT1r*#@r(wcIybsD*cm8nU`-s#CH?PjoGQUoG*0qt9Mpfg=G9}Wd|t!s@d!vU
z=w+n=1;)8vLl=hw!$FdI&7$?#d01*vLijBM}uM6YloshmEsPMQ#rmT0RbGTjt`
z16P`m_Vlz$-rUgPE^9oHNsb>BlWb
zf{N~6|5rwyx&Uls2XS&`O|;f-wWSS+pe5}H+}3ncnk#`8Afth~(<0NJztfm1vG>Hd
zO^ZSG&U(hg*mgQB#<3Dv1~uxLiGrD0FjLioX_N{>H7@QVvk;?1mTmvvFYf6-r#-hs
zZJ2C~kF{5~0cir#gh)G&p=EF@nH#g$yJidwoa{bN52&|q*!oL@Y%H*@U?$4U)R>vZ
zr$TfMOstd*lltI4c%=hNQrQ~4qzy>hgV_dTd86UJA-CCZbJv9luuV?N+
zU%j<96OCAv|GgEVBnjB1j00J3=N}E|X%q0WVxVWr_6w0z@GPvzrbly_6
z{Zk_w*iP$>dIQpK3F-~B+ujAYS|P;dakJsUZK8pKxsKi~A6KWIIo88c%=TqNUpzAW
zUZb`@vw*5$81^+Npw84zdNH?)$OMI)N70Xt334q28zy(*Tljde1n{
z)S~^fz)T>6V_ocO{WK2*c4n1;=JD2mHJGhme}$D0A3J&SB1LfYtn8)!>g&}cwft;i)Kd}Ex8w-IyOeSI?yoSzZY+t+T}ubCb1j+;ORdRLprP6NN+
z3n&%>3UKVrGB-%Z8oB1HN1xqrwmNYs*#UB8TPD}n0Cdn6ZMUTZk#@T+B9L~w?SO8#
zqz(6Xh_%vci9n>?YUkiK;9PQzOt*=Q&vf2dM}((|{+(;&*ea?dU11`Qoq?UmGQ`YA
zaMM}gt`*9f;f{Nz4!vsOyK(8*Fkf0e*&f*d)R97@hB`VP81)M{IMvgZ9@e%!Ya=05
zq(G2%U*FN$&V9-+@Vn!s;Wtq9GMo8fp#iKMOl210Z4^Hpu!b4RfI6nT)JH{se#^>N
zJ+)9Bxm4`IlP6b;PHm{6MxYI{PN0nhHFf~he1BN)$?A2m)dK4EI?--{^#;*)qPAYI
z6D=2O(E^MyJ}IabO1r!Gqw)2+dj^=9cx1z?PjfQ&~EDQ
zKX$5XnA0~M|LM`EuM%)a022Uc$ef+AyY+2o9BWa*Q21}$1^~iPR9-kTeE5-%UVnY(
zjCyntZ7*5J^zn<^S-Psz0g@V7Lyc{8P-ZNU)X7d8sMSHVffj&T=#QX|D_GkcOpa`p
zp;OK*ob%UL-|^Cc8)5BGaIM)K09Bvn04~;MQT`fIBpT4bkiyCOih&2-As1EVUQ5~b
zlJ(B`$d*nct0(Omfez?_bifuamo*1uQYX;{O77TitJmvnwc0tb0AL3DC$>m+3e#bPT`C9g&+zFw*WLlU}zSlJmIEb#C&7XmmMGf^>3d%c;#mwe6Tj3
z&Rq<9aN_9tsmWunP1QDP08;7rHs?M+dFLmfV3@=`fVM!ZQ6DMs@-mv
z+;LK`XQL18J3QBGnln=Y;Lc;uU6M)a*OV>hw1$*Ls~AcjTT3e0vl$r-41p9%Q>+@J
zoJ=*@bL;YrOLlFh$9VFhiHUTBh}O~RI0nMG-A)Hc7*@fF85>-2!Pt_3^6uD146PF!
z8*e{*{e}&5{wkQ$0u@dTZ!<8yfCG2!MK-&R}c``Pundz&WE1y2yYn>OUf5Ah`
zCXct@Oxpe`hLQo~GDD4VfQHvdQ>dwCDG{?d1C60lIz;W6!4-{>H_6K5^SSoZvF~uW
zv0`-jMq#>K)YRQ|x$ASlc2H((rvR}=x1A2?poq}{YPB+B+W=}^xoq8L?aAe9p1EG+
zv@?QvfeH`o^zrtuleWL)a(fsWD_s|Jjj4#EKqX5<)vE9aZq4v4vty{qNM`$w^siVk
zwo@dX?`H|Nd-v|7@6A^)BXm`IqP;>5mYKu>!CFFe(wv1!;+QrYutj|B0v70DY#VJ4
zEKq0Go)}zxU_OB2Oh82htT0=K9MG7d<LZ%(S%#p2SHJq@64xDf*=dkEvtf?_uR$uk>W|1>mXzaAs?WwZg*?jE@i}Ze*
z+D@K#da)EbwghNesNHTr0U!&=C0|)?QsYp_8
zgjy}Ck0donno0p?&F^<@(vC>2777zJ)S}`9YCx@)v>$)&@PYt}g#r}--nC)FWTVyi
zk&2xFfGn^jDBUQIX2>bZTdOyDg8U01Ta*EZWVijb>(Q@uHix(`n`zn9dTG9K31A
zgR_{ISpWb807*naR9L~*f~Cd2v?C?Z!+zFG+w6bt>D#t#Yj+=KzP4bX!ULPMnm^W5
zMm1&~Q0n0lOS?L@Xg{;frA^}hGfBB^61_;esGM{$yB0Ay6UWx9lL~5y-|xXmI})?i
zZFX!;JB4nkp$60o#x{&hHTNHWYTE(=iiHqLGubyso_(zmT;~2Ngi)@JD_L50y>S|o
zt6rped=6?f1)xDB1z{D7r11VEVd{ks0MIkviJ@4K6=JCqy*8v%!8H(Gn^xwn?v2%I
z*ehoeFZ}Aj+F75A&es-{sj=O<>Q%qUjQ)+K?F2v($5gLe3(IC@pfSme`|2?pOF_6d
zA}3X^liocco|dfUT4gc&Y87lnA(m>j8YFJtGHqFwJbktR#n}WE0B&8r@ug(?*#FJQ
zm$I&$G)P)@$I^(Us8GGAh^M94Sc=QNLArDsWwXW3UdvJ`+IyW8lyGd)9g{u4^`tRb
z8(1}by{sBNo%5cqoi+E{ZTCz)vsv4ErOjB2Q<(0&w9@q=%|#O9ZQd3dBq`kt;7MNeSZ{rb;Lw5;wg}EuW*r
z*64hNU~&~EpqH(NSxfut&t5x+;U^1iivnt}Z@e_Tv0-alv~HTA3KiU@CNrzv*!8AJ
zeNA|dpw8faovSXF3*m|tl`c5->Nnh60aRnOWo-8R^~*P$a)8*`vPA_o*!M=CTa|UN
z#ndo_o`M4^7*uqo^=v*JrpCa!V!e;=KCUK-VaHc5DpQ*zAv`O?(;I8F)v(Qj*Dqhb
zXkZ3g5}*eA-sp3yIvre*Br*umB(OA8k&1e6m+OURTB(o^mnK!@sX*$B{MAf#x$MmO
zDk2wL6Eo7bwWDuZdG??0&efI_sKIuV$>fOxm#FrwHRMnasF5oygPIgidf-Zt^Ih+f6pp=@-_rm9DkaL6Iym5o1cAcBL~_Obs>P
zusyFT%?4`H=-8|?VKo^UUv^^T9kTR*jBUw-8ryC%nHYU`u!-hShHS_(8#FaB$cz0h
zAfFCXs}!)%rlJ^6O>MN%htb!cXJe7iD^RO!H<密码
登录
手机注册
+ 绑定设备
请输入账号
请输入密码
显示密码
@@ -18,6 +19,7 @@
没有账号?立即注册
获取验证码
%1$d秒后重新获取
+ 已经到底了
@@ -63,6 +65,8 @@
历史
我的
首页
+ 重命名
+ 解绑设备
计划
历史
我的
diff --git a/gradle.properties b/gradle.properties
index d621849..837592e 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -14,3 +14,4 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
android.useAndroidX=true
+android.enableJetifier=true