From 69aa917897a3c22468778668fea44752933483c3 Mon Sep 17 00:00:00 2001
From: yezhiqiu <983577727@qq.com>
Date: Tue, 14 Apr 2026 17:10:34 +0800
Subject: [PATCH] =?UTF-8?q?1.route=E9=A1=B5ui=E5=8A=9F=E8=83=BD=E6=94=B9?=
=?UTF-8?q?=E7=89=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../compile-file-map.properties | 2 +-
app/build.gradle | 6 +-
app/src/main/AndroidManifest.xml | 1 -
.../tracker/adapter/HistoryFenceAdapter.kt | 67 ++
.../tracker/adapter/NotificationV2Adapter.kt | 2 +-
.../adapter/TopSlideLayoutManager.java | 40 ++
.../dialog/ShowCalenderAndTimeDialog.kt | 10 +-
.../tracker/retrofit2/INetworkService.kt | 10 +
.../abbidot/tracker/retrofit2/NetworkApi.kt | 7 +
.../tracker/ui/activity/HomeV2Activity.kt | 14 +-
.../ui/common/map/HistoryDataMapCommon.kt | 22 +-
.../ui/fragment/data/RouteV2Fragment.kt | 8 +-
.../ui/fragment/data/RouteV3Fragment.kt | 648 ++++++++++++++++++
.../tracker/ui/fragment/map/MapV3Fragment.kt | 135 +++-
.../googlemap/HistoryDataGoogleMapFragment.kt | 20 +-
.../java/com/abbidot/tracker/util/ViewUtil.kt | 2 +-
.../abbidot/tracker/vm/DataDetailViewModel.kt | 17 +-
.../tracker/widget/AppBarBehavior.java | 195 ++++++
.../tracker/widget/CustomLayoutManager.java | 39 ++
.../tracker/widget/NoClickSlideSeekBar.java | 84 +++
.../drawable-xhdpi/icon_bar_thumb_image.png | Bin 0 -> 428 bytes
.../icon_history_danger_fence_image.png | Bin 0 -> 504 bytes
.../icon_history_no_save_fence_image.png | Bin 0 -> 504 bytes
.../icon_history_save_fence_image.png | Bin 0 -> 432 bytes
.../drawable-xhdpi/icon_left_arrow_image.png | Bin 0 -> 252 bytes
.../drawable-xhdpi/icon_right_arrow_image.png | Bin 0 -> 236 bytes
.../icon_vertical_dot_line_image.png | Bin 0 -> 178 bytes
.../drawable-xxhdpi/icon_bar_thumb_image.png | Bin 0 -> 633 bytes
.../icon_history_danger_fence_image.png | Bin 0 -> 730 bytes
.../icon_history_no_save_fence_image.png | Bin 0 -> 730 bytes
.../icon_history_save_fence_image.png | Bin 0 -> 546 bytes
.../drawable-xxhdpi/icon_left_arrow_image.png | Bin 0 -> 326 bytes
.../icon_right_arrow_image.png | Bin 0 -> 305 bytes
.../icon_vertical_dot_line_image.png | Bin 0 -> 186 bytes
.../drawable-xxxhdpi/icon_bar_thumb_image.png | Bin 0 -> 797 bytes
.../icon_history_danger_fence_image.png | Bin 0 -> 1001 bytes
.../icon_history_no_save_fence_image.png | Bin 0 -> 1001 bytes
.../icon_history_save_fence_image.png | Bin 0 -> 713 bytes
.../icon_left_arrow_image.png | Bin 0 -> 399 bytes
.../icon_right_arrow_image.png | Bin 0 -> 378 bytes
.../icon_vertical_dot_line_image.png | Bin 0 -> 201 bytes
app/src/main/res/drawable/shape8_gray_bg.xml | 4 +-
.../res/drawable/shape_seek_bar_style_v3.xml | 18 +
.../dialog_calender_and_time_layout.xml | 12 +-
app/src/main/res/layout/fragment_route_v3.xml | 232 +++++++
.../res/layout/item_history_fence_layout.xml | 45 ++
app/src/main/res/values/colors.xml | 1 +
app/src/main/res/values/strings.xml | 5 +-
.../com/abbidot/baselibrary/util/AppUtils.kt | 2 +-
.../com/abbidot/baselibrary/util/Utils.kt | 3 +
50 files changed, 1584 insertions(+), 67 deletions(-)
create mode 100644 app/src/main/java/com/abbidot/tracker/adapter/HistoryFenceAdapter.kt
create mode 100644 app/src/main/java/com/abbidot/tracker/adapter/TopSlideLayoutManager.java
create mode 100644 app/src/main/java/com/abbidot/tracker/ui/fragment/data/RouteV3Fragment.kt
create mode 100644 app/src/main/java/com/abbidot/tracker/widget/AppBarBehavior.java
create mode 100644 app/src/main/java/com/abbidot/tracker/widget/CustomLayoutManager.java
create mode 100644 app/src/main/java/com/abbidot/tracker/widget/NoClickSlideSeekBar.java
create mode 100644 app/src/main/res/drawable-xhdpi/icon_bar_thumb_image.png
create mode 100644 app/src/main/res/drawable-xhdpi/icon_history_danger_fence_image.png
create mode 100644 app/src/main/res/drawable-xhdpi/icon_history_no_save_fence_image.png
create mode 100644 app/src/main/res/drawable-xhdpi/icon_history_save_fence_image.png
create mode 100644 app/src/main/res/drawable-xhdpi/icon_left_arrow_image.png
create mode 100644 app/src/main/res/drawable-xhdpi/icon_right_arrow_image.png
create mode 100644 app/src/main/res/drawable-xhdpi/icon_vertical_dot_line_image.png
create mode 100644 app/src/main/res/drawable-xxhdpi/icon_bar_thumb_image.png
create mode 100644 app/src/main/res/drawable-xxhdpi/icon_history_danger_fence_image.png
create mode 100644 app/src/main/res/drawable-xxhdpi/icon_history_no_save_fence_image.png
create mode 100644 app/src/main/res/drawable-xxhdpi/icon_history_save_fence_image.png
create mode 100644 app/src/main/res/drawable-xxhdpi/icon_left_arrow_image.png
create mode 100644 app/src/main/res/drawable-xxhdpi/icon_right_arrow_image.png
create mode 100644 app/src/main/res/drawable-xxhdpi/icon_vertical_dot_line_image.png
create mode 100644 app/src/main/res/drawable-xxxhdpi/icon_bar_thumb_image.png
create mode 100644 app/src/main/res/drawable-xxxhdpi/icon_history_danger_fence_image.png
create mode 100644 app/src/main/res/drawable-xxxhdpi/icon_history_no_save_fence_image.png
create mode 100644 app/src/main/res/drawable-xxxhdpi/icon_history_save_fence_image.png
create mode 100644 app/src/main/res/drawable-xxxhdpi/icon_left_arrow_image.png
create mode 100644 app/src/main/res/drawable-xxxhdpi/icon_right_arrow_image.png
create mode 100644 app/src/main/res/drawable-xxxhdpi/icon_vertical_dot_line_image.png
create mode 100644 app/src/main/res/drawable/shape_seek_bar_style_v3.xml
create mode 100644 app/src/main/res/layout/fragment_route_v3.xml
create mode 100644 app/src/main/res/layout/item_history_fence_layout.xml
diff --git a/FastBleLib/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties b/FastBleLib/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties
index 315de23..dd0f8d5 100644
--- a/FastBleLib/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties
+++ b/FastBleLib/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties
@@ -1 +1 @@
-#Wed Apr 08 14:56:42 CST 2026
+#Thu Apr 09 17:00:19 CST 2026
diff --git a/app/build.gradle b/app/build.gradle
index 629a992..f7b3141 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -28,9 +28,9 @@ android {
applicationId "com.abbidot.tracker"
minSdkVersion 23
targetSdkVersion 35
- versionCode 2113
-// versionName "2.1.13"
- versionName "2.1.13-Beta3"
+ versionCode 2202
+// versionName "2.2.2"
+ versionName "2.2.2-Beta1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6e86bf7..497e206 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -55,7 +55,6 @@
android:protectionLevel="signature" />
-
diff --git a/app/src/main/java/com/abbidot/tracker/adapter/HistoryFenceAdapter.kt b/app/src/main/java/com/abbidot/tracker/adapter/HistoryFenceAdapter.kt
new file mode 100644
index 0000000..784f064
--- /dev/null
+++ b/app/src/main/java/com/abbidot/tracker/adapter/HistoryFenceAdapter.kt
@@ -0,0 +1,67 @@
+package com.abbidot.tracker.adapter
+
+import android.content.Context
+import android.text.format.DateUtils
+import android.view.View
+import com.abbidot.baselibrary.list.BaseRecyclerAdapter
+import com.abbidot.baselibrary.list.RecyclerViewHolder
+import com.abbidot.baselibrary.util.Utils
+import com.abbidot.tracker.R
+import com.abbidot.tracker.bean.MessageBean
+import com.abbidot.tracker.constant.ConstantInt
+
+/**
+ *Created by .yzq on 2026/4/10/周五.
+ * @link
+ * @description:
+ */
+class HistoryFenceAdapter(
+ ctx: Context, list: MutableList?
+) : BaseRecyclerAdapter(ctx, list) {
+ override fun getEmptyLayoutId(viewType: Int) = 0
+
+ override fun getItemLayoutId(viewType: Int) = R.layout.item_history_fence_layout
+
+ override fun bindData(holder: RecyclerViewHolder?, position: Int, item: MessageBean) {
+ holder?.apply {
+ getImageView(R.id.iv_history_fence_type_image).let {
+ when (item.deviceMessageType) {
+ ConstantInt.Type1, ConstantInt.Type3 -> it.setImageResource(R.drawable.icon_history_danger_fence_image)
+ ConstantInt.Type2 -> it.setImageResource(R.drawable.icon_history_save_fence_image)
+ ConstantInt.Type4 -> it.setImageResource(R.drawable.icon_history_no_save_fence_image)
+ }
+ }
+ getTextView(R.id.tv_history_fence_type_time).text =
+ getRelativeTimeString(item.timeStamp)
+ getTextView(R.id.tv_history_fence_type_content).text = item.message
+ getImageView(R.id.iv_history_fence_type_line).let {
+ it.visibility = if (position == getData().size - 1) View.GONE
+ else View.VISIBLE
+ }
+ }
+ }
+
+ private fun getRelativeTimeString(timeStamp: Long): String {
+ val formatDateStr: String
+ val cTimeStamp = Utils.stringToTimestamp(
+ Utils.formatTime(
+ timeStamp, Utils.DATE_FORMAT_PATTERN_CN2
+ )
+ )
+ val now = System.currentTimeMillis()
+ formatDateStr = if (DateUtils.isToday(cTimeStamp)) {
+ mContext.getString(R.string.txt_today) + " " + Utils.formatTime(
+ timeStamp, Utils.DATE_FORMAT_PATTERN_EN14
+ )
+ } else if (now - cTimeStamp < (48 * 60 * 60 * 1000)) {
+ mContext.getString(R.string.txt_yesterday) + " " + Utils.formatTime(
+ timeStamp, Utils.DATE_FORMAT_PATTERN_EN14
+ )
+ } else {
+ Utils.formatTime(
+ timeStamp, Utils.DATE_FORMAT_PATTERN_EN15
+ )
+ }
+ return formatDateStr
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/abbidot/tracker/adapter/NotificationV2Adapter.kt b/app/src/main/java/com/abbidot/tracker/adapter/NotificationV2Adapter.kt
index e74d003..1853e21 100644
--- a/app/src/main/java/com/abbidot/tracker/adapter/NotificationV2Adapter.kt
+++ b/app/src/main/java/com/abbidot/tracker/adapter/NotificationV2Adapter.kt
@@ -58,7 +58,7 @@ class NotificationV2Adapter(
}
private fun getRelativeTimeString(timeStamp: Long): String {
- var formatDateStr = ""
+ val formatDateStr: String
val cTimeStamp = Utils.stringToTimestamp(
Utils.formatTime(
timeStamp, Utils.DATE_FORMAT_PATTERN_CN2
diff --git a/app/src/main/java/com/abbidot/tracker/adapter/TopSlideLayoutManager.java b/app/src/main/java/com/abbidot/tracker/adapter/TopSlideLayoutManager.java
new file mode 100644
index 0000000..acdcc25
--- /dev/null
+++ b/app/src/main/java/com/abbidot/tracker/adapter/TopSlideLayoutManager.java
@@ -0,0 +1,40 @@
+package com.abbidot.tracker.adapter;
+
+import android.content.Context;
+import android.view.View;
+
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * Created by .yzq on 2026/4/13/周一.
+ *
+ * @link
+ * @description:
+ */
+public class TopSlideLayoutManager extends LinearLayoutManager {
+ private int mTopOffset;
+
+ public TopSlideLayoutManager(Context context, int orientation, boolean reverseLayout) {
+ super(context, orientation, reverseLayout);
+ }
+
+ public void setTopOffset(int topOffset) {
+ mTopOffset = topOffset;
+ requestLayout();
+ }
+
+ @Override
+ public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+ super.onLayoutChildren(recycler, state);
+ // 可以在这里调整子项的位置,例如将顶部几个项上移
+ if (getChildCount() > 0) {
+ View firstChild = getChildAt(0);
+ if (firstChild != null) {
+ int top = getDecoratedTop(firstChild) - mTopOffset;
+ layoutDecoratedWithMargins(firstChild, firstChild.getLeft(), top, firstChild.getRight(), top + firstChild.getHeight());
+ }
+ }
+ }
+}
+
diff --git a/app/src/main/java/com/abbidot/tracker/dialog/ShowCalenderAndTimeDialog.kt b/app/src/main/java/com/abbidot/tracker/dialog/ShowCalenderAndTimeDialog.kt
index 4c46b97..6687a2f 100644
--- a/app/src/main/java/com/abbidot/tracker/dialog/ShowCalenderAndTimeDialog.kt
+++ b/app/src/main/java/com/abbidot/tracker/dialog/ShowCalenderAndTimeDialog.kt
@@ -25,7 +25,7 @@ import java.util.Calendar
class ShowCalenderAndTimeDialog(
context: Context,
showCalenderTextView: TextView,
- okListener: OnDialogOkListener? = null,
+ okListener: OnDialogSelectListener? = null,
format: String = Utils.DATE_FORMAT_PATTERN_EN1,
canSelectFutureDate: Boolean = false,
calenderShowTimestamp: Long = 0,
@@ -86,7 +86,7 @@ class ShowCalenderAndTimeDialog(
0,
23,
5,
- 24,
+ 16,
NumberPickerValueFill0Format(),
this@ShowCalenderAndTimeDialog
)
@@ -98,7 +98,7 @@ class ShowCalenderAndTimeDialog(
0,
59,
5,
- 24,
+ 16,
NumberPickerValueFill0Format(),
this@ShowCalenderAndTimeDialog
)
@@ -172,16 +172,18 @@ class ShowCalenderAndTimeDialog(
}:${Utils.fill2Digits(npDialogCalenderMin.value)}:00"
val timesTamp = Utils.stringToTimestamp(selectMonthYear)
val nowTimestamp = System.currentTimeMillis()
+
if (timesTamp > nowTimestamp) {
//时间戳还原
setSelectDate(nowTimestamp)
mShowCalenderTextView.text = Utils.formatTime(nowTimestamp, mDateFormat)
+ mOkListener?.onSelectClick(this@ShowCalenderAndTimeDialog, nowTimestamp)
} else {
mShowCalenderTextView.text = Utils.stringToDate(
selectMonthYear, Utils.DATE_FORMAT_PATTERN_CN2, mDateFormat
)
+ mOkListener?.onSelectClick(this@ShowCalenderAndTimeDialog, timesTamp)
}
- mOkListener?.onOkClick(this@ShowCalenderAndTimeDialog)
dismiss()
}
}
diff --git a/app/src/main/java/com/abbidot/tracker/retrofit2/INetworkService.kt b/app/src/main/java/com/abbidot/tracker/retrofit2/INetworkService.kt
index 7cc08c7..8b41986 100644
--- a/app/src/main/java/com/abbidot/tracker/retrofit2/INetworkService.kt
+++ b/app/src/main/java/com/abbidot/tracker/retrofit2/INetworkService.kt
@@ -837,6 +837,16 @@ interface INetworkService {
@Query("toTime") toTime: Long
): BaseResponse>
+ /**
+ * 获取设备进出围栏历史数据
+ */
+ @GET("data/getHistoryInOutFenceList")
+ suspend fun getHistoryFenceList(
+ @Query("deviceId") deviceId: String,
+ @Query("beginTimeStamp") fromTime: Long,
+ @Query("endTimeStamp") toTime: Long
+ ): BaseResponse>
+
/**
* 设置运动目标
*/
diff --git a/app/src/main/java/com/abbidot/tracker/retrofit2/NetworkApi.kt b/app/src/main/java/com/abbidot/tracker/retrofit2/NetworkApi.kt
index 59fdcc3..181b31c 100644
--- a/app/src/main/java/com/abbidot/tracker/retrofit2/NetworkApi.kt
+++ b/app/src/main/java/com/abbidot/tracker/retrofit2/NetworkApi.kt
@@ -753,6 +753,13 @@ object NetworkApi : BaseNetworkApi(INetworkService.BASE_URL) {
service.getHistoryByDay(deviceId, fromTime, toTime)
}
+ /**
+ * 获取设备进出围栏历史数据
+ */
+ suspend fun getHistoryFenceList(deviceId: String, fromTime: Long, toTime: Long) = getResult {
+ service.getHistoryFenceList(deviceId, fromTime, toTime)
+ }
+
/**
* 设置运动目标
*/
diff --git a/app/src/main/java/com/abbidot/tracker/ui/activity/HomeV2Activity.kt b/app/src/main/java/com/abbidot/tracker/ui/activity/HomeV2Activity.kt
index 4d33214..719f3f8 100644
--- a/app/src/main/java/com/abbidot/tracker/ui/activity/HomeV2Activity.kt
+++ b/app/src/main/java/com/abbidot/tracker/ui/activity/HomeV2Activity.kt
@@ -46,7 +46,7 @@ import com.abbidot.tracker.ui.activity.device.AddNewTracker1Activity
import com.abbidot.tracker.ui.activity.device.MyTrackerV2Activity
import com.abbidot.tracker.ui.fragment.account.AccountV2Fragment
import com.abbidot.tracker.ui.fragment.data.ActivityV2Fragment
-import com.abbidot.tracker.ui.fragment.data.RouteV2Fragment
+import com.abbidot.tracker.ui.fragment.data.RouteV3Fragment
import com.abbidot.tracker.ui.fragment.map.MapV3Fragment
import com.abbidot.tracker.ui.fragment.pet.PetV2Fragment
import com.abbidot.tracker.util.SocketUtilManage
@@ -111,7 +111,7 @@ class HomeV2Activity : BaseActivity(ActivityHomeV2Binding
private val mFragments = mutableListOf(
ActivityV2Fragment.newInstance(this),
- RouteV2Fragment.newInstance(this),
+ RouteV3Fragment.newInstance(this),
MapV3Fragment.newInstance(this),
PetV2Fragment.newInstance(this),
AccountV2Fragment.newInstance(this)
@@ -460,7 +460,7 @@ class HomeV2Activity : BaseActivity(ActivityHomeV2Binding
onChangeClick(mSelectPetPosition)
when (mViewBinding.homeV2ViewPager2.currentItem) {
0 -> {
- (mFragments[1] as RouteV2Fragment).setNeedUpdateTag()
+ (mFragments[1] as RouteV3Fragment).setNeedUpdateTag()
(mFragments[3] as PetV2Fragment).setNeedUpdateTag()
}
@@ -471,13 +471,13 @@ class HomeV2Activity : BaseActivity(ActivityHomeV2Binding
2, 4 -> {
(mFragments[0] as ActivityV2Fragment).setNeedUpdateTag()
- (mFragments[1] as RouteV2Fragment).setNeedUpdateTag()
+ (mFragments[1] as RouteV3Fragment).setNeedUpdateTag()
(mFragments[3] as PetV2Fragment).setNeedUpdateTag()
}
3 -> {
(mFragments[0] as ActivityV2Fragment).setNeedUpdateTag()
- (mFragments[1] as RouteV2Fragment).setNeedUpdateTag()
+ (mFragments[1] as RouteV3Fragment).setNeedUpdateTag()
}
}
}
@@ -638,7 +638,7 @@ class HomeV2Activity : BaseActivity(ActivityHomeV2Binding
fun refreshLocationBtnState() {
when (mViewBinding.homeV2ViewPager2.currentItem) {
0 -> (mFragments[0] as ActivityV2Fragment).checkNotifyLocationState()
- 1 -> (mFragments[1] as RouteV2Fragment).checkNotifyLocationState()
+ 1 -> (mFragments[1] as RouteV3Fragment).checkNotifyLocationState()
3 -> (mFragments[3] as PetV2Fragment).checkNotifyLocationState()
}
}
@@ -654,7 +654,7 @@ class HomeV2Activity : BaseActivity(ActivityHomeV2Binding
mChangePetListDialogAdapter.setSelectPetPos(mSelectPetPosition)
when (mViewBinding.homeV2ViewPager2.currentItem) {
0 -> (mFragments[0] as ActivityV2Fragment).showPetNameAndHead(position)
- 1 -> (mFragments[1] as RouteV2Fragment).showPetNameAndHead(position)
+ 1 -> (mFragments[1] as RouteV3Fragment).showPetNameAndHead(position)
2 -> (mFragments[2] as MapV3Fragment).showPetNameAndHead(position)
3 -> (mFragments[3] as PetV2Fragment).showPetNameAndHead(position)
}
diff --git a/app/src/main/java/com/abbidot/tracker/ui/common/map/HistoryDataMapCommon.kt b/app/src/main/java/com/abbidot/tracker/ui/common/map/HistoryDataMapCommon.kt
index 17bde2d..8ca6798 100644
--- a/app/src/main/java/com/abbidot/tracker/ui/common/map/HistoryDataMapCommon.kt
+++ b/app/src/main/java/com/abbidot/tracker/ui/common/map/HistoryDataMapCommon.kt
@@ -1,8 +1,10 @@
package com.abbidot.tracker.ui.common.map
import android.content.Context
+import androidx.appcompat.widget.AppCompatSeekBar
import androidx.fragment.app.Fragment
import com.abbidot.baselibrary.util.AppUtils
+import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.tracker.base.BaseMapCommon
import com.abbidot.tracker.bean.HistoryDataBean
import com.abbidot.tracker.bean.PetBean
@@ -10,7 +12,6 @@ import com.abbidot.tracker.ui.fragment.map.baidumap.HistoryDataBaiduMapFragment
import com.abbidot.tracker.ui.fragment.map.googlemap.HistoryDataGoogleMapFragment
import com.abbidot.tracker.vm.GeoCoderViewModel
import com.abbidot.tracker.widget.MapMarkerInfoView
-import com.abbidot.tracker.widget.VerticalTopToBottomSeekBar
/**
*Created by .yzq on 2022/7/5/005.
@@ -26,7 +27,7 @@ class HistoryDataMapCommon : BaseMapCommon() {
context: Context,
markerInfoView: MapMarkerInfoView,
geoCoderViewModel: GeoCoderViewModel,
- verticalTopToBottomSeekBar: VerticalTopToBottomSeekBar,
+ verticalTopToBottomSeekBar: AppCompatSeekBar,
mapLoadOk: () -> Unit
): Fragment {
return if (AppUtils.isChina(AppUtils.SWITCH_MAP_TYPE)) {
@@ -102,10 +103,15 @@ class HistoryDataMapCommon : BaseMapCommon() {
}
fun setLatLngData(data: MutableList) {
- if (null != mHistoryDataBaiduMapFragment) {
- mHistoryDataBaiduMapFragment!!.setLatLngData(data)
- } else if (null != mHistoryDataGoogleMapFragment) {
- mHistoryDataGoogleMapFragment!!.setLatLngData(data)
+ if (data.size == 0) return
+ try {
+ if (null != mHistoryDataBaiduMapFragment) {
+ mHistoryDataBaiduMapFragment!!.setLatLngData(data)
+ } else if (null != mHistoryDataGoogleMapFragment) {
+ mHistoryDataGoogleMapFragment!!.setLatLngData(data)
+ }
+ } catch (e: Exception) {
+ LogUtil.e("setLatLngData异常:${e.message}")
}
}
@@ -117,6 +123,10 @@ class HistoryDataMapCommon : BaseMapCommon() {
}
}
+ fun resetMarkerInfoViewOffset() {
+ mHistoryDataGoogleMapFragment?.resetMarkerInfoViewOffset()
+ }
+
fun setPetUserLatLng() {
if (null != mHistoryDataBaiduMapFragment) {
} else if (null != mHistoryDataGoogleMapFragment) {
diff --git a/app/src/main/java/com/abbidot/tracker/ui/fragment/data/RouteV2Fragment.kt b/app/src/main/java/com/abbidot/tracker/ui/fragment/data/RouteV2Fragment.kt
index e67868f..7c2b941 100644
--- a/app/src/main/java/com/abbidot/tracker/ui/fragment/data/RouteV2Fragment.kt
+++ b/app/src/main/java/com/abbidot/tracker/ui/fragment/data/RouteV2Fragment.kt
@@ -449,8 +449,8 @@ class RouteV2Fragment : BaseFragment(FragmentRouteV2Bind
mFromCalenderDialog = ShowCalenderAndTimeDialog(
mContext!!,
tvHomeRouteCalendarFrom,
- object : BaseDialog.OnDialogOkListener {
- override fun onOkClick(dialog: BaseDialog<*>) {
+ object : BaseDialog.OnDialogSelectListener {
+ override fun onSelectClick(dialog: BaseDialog<*>, any: Any) {
mCurrentTimestamp = System.currentTimeMillis()
isSelectCustomDate = true
getHistoryDay(tvHomeRouteCalendarFrom)
@@ -477,8 +477,8 @@ class RouteV2Fragment : BaseFragment(FragmentRouteV2Bind
mToCalenderDialog = ShowCalenderAndTimeDialog(
mContext!!,
tvHomeRouteCalendarTo,
- object : BaseDialog.OnDialogOkListener {
- override fun onOkClick(dialog: BaseDialog<*>) {
+ object : BaseDialog.OnDialogSelectListener {
+ override fun onSelectClick(dialog: BaseDialog<*>, any: Any) {
isSelectCustomDate = true
getHistoryDay(tvHomeRouteCalendarTo)
}
diff --git a/app/src/main/java/com/abbidot/tracker/ui/fragment/data/RouteV3Fragment.kt b/app/src/main/java/com/abbidot/tracker/ui/fragment/data/RouteV3Fragment.kt
new file mode 100644
index 0000000..40858d8
--- /dev/null
+++ b/app/src/main/java/com/abbidot/tracker/ui/fragment/data/RouteV3Fragment.kt
@@ -0,0 +1,648 @@
+package com.abbidot.tracker.ui.fragment.data
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.view.MotionEvent
+import android.view.View
+import android.widget.SeekBar
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.commit
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.lifecycleScope
+import com.abbidot.baselibrary.constant.EventName
+import com.abbidot.baselibrary.eventbus.XEventBus
+import com.abbidot.baselibrary.util.AppUtils
+import com.abbidot.baselibrary.util.LogUtil
+import com.abbidot.baselibrary.util.Utils
+import com.abbidot.tracker.R
+import com.abbidot.tracker.adapter.HistoryFenceAdapter
+import com.abbidot.tracker.base.BaseDialog
+import com.abbidot.tracker.base.BaseFragment
+import com.abbidot.tracker.bean.HistoryDataBean
+import com.abbidot.tracker.bean.MessageBean
+import com.abbidot.tracker.constant.ConstantInt
+import com.abbidot.tracker.constant.GetResultCallback
+import com.abbidot.tracker.databinding.FragmentRouteV3Binding
+import com.abbidot.tracker.dialog.ShowCalenderAndTimeDialog
+import com.abbidot.tracker.ui.activity.HomeV2Activity
+import com.abbidot.tracker.ui.common.map.HistoryDataMapCommon
+import com.abbidot.tracker.util.Util
+import com.abbidot.tracker.util.ViewUtil
+import com.abbidot.tracker.vm.DataDetailViewModel
+import com.abbidot.tracker.vm.GeoCoderViewModel
+import com.abbidot.tracker.widget.NoClickSlideSeekBar
+import com.abbidot.tracker.widget.TypefaceTextView
+import kotlinx.coroutines.launch
+
+
+/**
+ * 首页轨迹
+ * create an instance of this fragment.
+ */
+class RouteV3Fragment : BaseFragment(FragmentRouteV3Binding::inflate) {
+
+ private val mDataDetailViewModel: DataDetailViewModel by viewModels()
+ private val mGeoCoderViewModel: GeoCoderViewModel by viewModels()
+
+ private lateinit var mFragment: Fragment
+
+ private var mFromCalenderDialog: ShowCalenderAndTimeDialog? = null
+ private var mToCalenderDialog: ShowCalenderAndTimeDialog? = null
+
+ //当前这个页面显示的宠物下标
+ private var mCurrentShowPetPos = -1
+
+ //最多只能选择多少天的历史记录
+ private val mOnlySelectDay = 7L
+
+ //当前的时间戳
+ private var mCurrentTimestamp = 0L
+ private var mFromTimestamp = 0L
+ private var mToTimestamp = 0L
+
+ //方便保存地理反编译信息
+ private var mHistoryDataList = mutableListOf()
+ private val mHistoryDataMapCommon = HistoryDataMapCommon()
+
+ //是否选过自定义日期,没有则再次回到这个页面,刷新取24小时的记录
+ private var isSelectCustomDate = false
+
+ // private var isFirst = true
+ private var mProgress = 0
+
+ //原来有列表一个元素的高度
+ private var mLastScrollViewHeight = 0
+
+ private var mTotalHeight = 0
+
+ private lateinit var mHistoryFenceAdapter: HistoryFenceAdapter
+ private val mAllHistoryFenceList = mutableListOf()
+
+ //充值续费或升级返回类型
+ private var mRechargeBackType = ConstantInt.SpecialType
+
+ //列表是否展开
+ private var isListExpand = false
+
+ //判断是否滑过
+ private var isHaveSlide = false
+ private var mLastY = 0f
+ private var mDiffHeight = 0
+
+ //是否上滑
+ private var isSlideUp = false
+
+// private lateinit var mTopSlideLayoutManager: TopSlideLayoutManager
+
+ companion object {
+ @JvmStatic
+ fun newInstance(context: Context) = RouteV3Fragment().apply {
+ mContext = context
+ }
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ override fun initData() {
+ mViewBinding.apply {
+ getHomeV2Activity()?.edgeToEdgeAdapterBars(
+ root, WindowInsetsCompat.Type.statusBars()
+ )
+ mFragment = mHistoryDataMapCommon.getMapFragment(
+ mContext!!, miHomeRouteAddressViewV3, mGeoCoderViewModel, vsbMapRouteLineV3
+ ) {
+ mapLoadOk()
+ }
+
+ mHistoryFenceAdapter = HistoryFenceAdapter(mContext!!, null)
+ ViewUtil.instance.setRecyclerViewVerticalLinearLayout(
+ mContext!!, rvMapRouteLineV3FencesList, mHistoryFenceAdapter
+ )
+// rvMapRouteLineV3FencesList.let {
+// mTopSlideLayoutManager = TopSlideLayoutManager(
+// mContext!!, LinearLayoutManager.VERTICAL, false
+// )
+// it.layoutManager = mTopSlideLayoutManager
+// it.adapter = mHistoryFenceAdapter
+// }
+
+ ilHomeRoutePetHeadV3.ivTopPetBtnSmall.visibility = View.GONE
+ //设置不可点击状态
+ vsbMapRouteLineV3.setStatus(NoClickSlideSeekBar.STATUS.STATUS_SLIDE)
+
+ setOnClickListenerViews(
+ llHomeRouteCalendarFromV3,
+ llHomeRouteCalendarToV3,
+ ilHomeRoutePetHeadV3.homeDataPetHeadSmall.root,
+ ilHomeRoutePetHeadV3.homeDataPetNameSmall,
+ ivHomeRouteMapTypeBtnV3,
+ ivMapRouteLineV3LastBtn,
+ ivMapRouteLineV3NextBtn
+ )
+
+ llMapRouteLineV3ZoomingLayout.setOnTouchListener { _, event ->
+ if (rlMapRouteLineV3TimeLayout.isVisible) {
+ if (mLastScrollViewHeight == 0) {
+ mTotalHeight = cvHomeRouteV3Card.height + svHomeRouteMapScroll.height
+ mLastScrollViewHeight = svHomeRouteMapScroll.height
+ }
+
+ when (event.action) {
+ MotionEvent.ACTION_DOWN -> {
+ LogUtil.e("ACTION_DOWN")
+ mLastY = event.rawY
+ }
+
+ MotionEvent.ACTION_MOVE -> {
+ val dy = mLastY - event.rawY
+ val layoutParams = svHomeRouteMapScroll.layoutParams
+ val diff = (svHomeRouteMapScroll.height + dy).toInt()
+ isSlideUp = dy >= 0.0f
+ if (diff > mLastScrollViewHeight) {
+ isHaveSlide = true
+ if (mHistoryFenceAdapter.getData().size != mAllHistoryFenceList.size) {
+ mHistoryFenceAdapter.setData(mAllHistoryFenceList, true)
+ }
+ mDiffHeight = diff
+ layoutParams.height = diff
+ svHomeRouteMapScroll.layoutParams = layoutParams
+ mLastY = event.rawY
+ }
+ }
+
+ MotionEvent.ACTION_UP -> {
+ LogUtil.e("ACTION_UP")
+ val layoutParams = svHomeRouteMapScroll.layoutParams
+ if (mDiffHeight > mTotalHeight / 2) {
+ setSeekBarShowHide(false)
+ layoutParams.height = mTotalHeight
+ svHomeRouteMapScroll.layoutParams = layoutParams
+ isListExpand = true
+ } else {
+ svHomeRouteMapScroll.postDelayed(
+ { mHistoryDataMapCommon.setLatLngData(mHistoryDataList) }, 200
+ )
+ if (mDiffHeight > mLastScrollViewHeight) {
+ layoutParams.height = if (isSlideUp) {
+ isListExpand = true
+ setSeekBarShowHide(false)
+ mTotalHeight / 2
+ } else {
+ isListExpand = false
+ setSeekBarShowHide(true)
+ if (mHistoryFenceAdapter.getData().size > 1) {
+ mHistoryFenceAdapter.setData(
+ mAllHistoryFenceList.subList(
+ 0, 1
+ ), true
+ )
+ }
+ mLastScrollViewHeight
+ }
+ }
+ svHomeRouteMapScroll.layoutParams = layoutParams
+ }
+ }
+ }
+ }
+ false
+ }
+
+ if (AppUtils.isDebug()) {
+ ilHomeRoutePetHeadV3.homeDataPetHeadSmall.root.setOnLongClickListener {
+ getHomeV2Activity()?.goToDebugActivity()
+ true
+ }
+ }
+ }
+
+ //解决报错java.lang.IllegalArgumentException
+ //No view found for id 0x7f090254 (com.abbidot.tracker:id/fc_home_route_fragment) for fragment HomeMapGoogleMapFragment
+ //https://www.jianshu.com/p/9235092f407a
+ childFragmentManager.commit {
+ add(R.id.fc_home_route_fragment_v3, mFragment)
+ }
+
+ initEven()
+ initState()
+ }
+
+ private fun getHomeV2Activity(): HomeV2Activity? {
+ return if (null == activity) {
+ LogUtil.e("RouteV2Fragment,getHomeV2Activity,null == activity")
+ null
+ } else {
+ activity as HomeV2Activity
+ }
+ }
+
+ /**
+ * 一开始获取24小时内的数据
+ */
+ private fun get24HourTime() {
+ mCurrentTimestamp = System.currentTimeMillis()
+ mViewBinding.apply {
+ mFromTimestamp = Utils.getBeforeHowTimestamp(mCurrentTimestamp, 1)
+ mToTimestamp = mCurrentTimestamp
+ tvHomeRouteCalendarToV3.text =
+ Utils.formatTime(mToTimestamp, Utils.DATE_FORMAT_PATTERN_EN13)
+ tvHomeRouteCalendarFromV3.text =
+ Utils.formatTime(mFromTimestamp, Utils.DATE_FORMAT_PATTERN_EN13)
+ }
+ }
+
+
+ private fun initState() {
+ mViewBinding.miHomeRouteAddressViewV3.visibility = View.GONE
+ mHistoryDataMapCommon.clearAllMarker()
+ setSeekBarMax(0)
+ }
+
+ private fun initEven() {
+ mViewBinding.vsbMapRouteLineV3.setOnSeekBarChangeListener(object :
+ SeekBar.OnSeekBarChangeListener {
+ override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+ if (mProgress == progress) {
+ return
+ }
+ mProgress = progress
+ mViewBinding.miHomeRouteAddressViewV3.visibility = View.GONE
+ mHistoryDataMapCommon.slideChanged(progress)
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar) {
+ }
+
+ override fun onStopTrackingTouch(seekBar: SeekBar) {
+ mHistoryDataMapCommon.slideStopChanged(seekBar.progress)
+ }
+ })
+ }
+
+ override fun onResume() {
+ super.onResume()
+ //续费成功后,不执行
+ if (mRechargeBackType == ConstantInt.Type1) {
+ return
+ }
+ getHomeV2Activity()?.apply {
+ if (mCurrentShowPetPos == mSelectPetPosition) {
+ if (!isSelectCustomDate) {
+ if (mHistoryDataMapCommon.isMapLoadOk()) {
+ get24HourTime()
+ getHistoryDay(mViewBinding.tvHomeRouteCalendarFromV3)
+ }
+ }
+ } else {
+ //其他页面是否选择了宠物
+ if (!isSelectCustomDate) get24HourTime()
+ showPetNameAndHead(mSelectPetPosition)
+ }
+ checkNotifyLocationState()
+ }
+ }
+
+ fun checkNotifyLocationState() {
+ getHomeV2Activity()?.apply {
+ checkNotifyRefreshLocation(mViewBinding.ilHomeRoutePetHeadV3.homeDataPetNameSmall)
+ }
+ }
+
+ override fun liveDataObserve() {
+ //更新套餐数据
+ XEventBus.observe(this, EventName.RefreshPackage) {
+ //监听续费成功
+ if (mRechargeBackType == ConstantInt.Type0) {
+ mRechargeBackType = ConstantInt.Type1
+ }
+ }
+
+ mDataDetailViewModel.apply {
+ mHistoryDetailLive.observe(this@RouteV3Fragment) {
+ dealRequestResult(it, object : GetResultCallback {
+ override fun onResult(any: Any) {
+ val data = it.getOrNull()!!
+ setLatLngData(data)
+ getHomeV2Activity()?.let { a ->
+ a.getPet(false)?.let { p ->
+ mAllHistoryFenceList.clear()
+ getHistoryFenceList(
+ a, p.deviceId, mFromTimestamp / 1000, mToTimestamp / 1000
+ )
+ }
+ }
+ }
+
+ override fun onRequestError(exceptionCode: String?) {
+ setSeekBarShowHide(false)
+ }
+ }, isShowNoDataTip = false)
+ }
+ mHistoryFenceEvents.observe(this@RouteV3Fragment) {
+ dealRequestResult(it, object : GetResultCallback {
+ override fun onResult(any: Any) {
+ it.getOrNull()?.let { d ->
+ if (d.size > 0) {
+ mViewBinding.rlMapRouteLineV3TimeLayout.visibility = View.VISIBLE
+ mAllHistoryFenceList.addAll(d)
+ if (isListExpand) {
+ mHistoryFenceAdapter.setData(
+ mAllHistoryFenceList, true
+ )
+ } else {
+ mHistoryFenceAdapter.setData(
+ mAllHistoryFenceList.subList(0, 1), true
+ )
+ }
+ if (isHaveSlide) {
+ //判断滑过,从无数据到有数据布局错乱
+ val layoutParams =
+ mViewBinding.svHomeRouteMapScroll.layoutParams
+ if (layoutParams.height < mLastScrollViewHeight) {
+ layoutParams.height = mLastScrollViewHeight
+ mViewBinding.svHomeRouteMapScroll.layoutParams =
+ layoutParams
+ }
+ }
+ } else {
+ mViewBinding.rlMapRouteLineV3TimeLayout.visibility = View.GONE
+ val lastScrollViewNoListHeight =
+ mViewBinding.rlHomeRouteCalendarV3Layout.height
+ if (isHaveSlide) {
+ val layoutParams =
+ mViewBinding.svHomeRouteMapScroll.layoutParams
+ layoutParams.height = lastScrollViewNoListHeight
+ mViewBinding.svHomeRouteMapScroll.layoutParams = layoutParams
+ }
+ isListExpand = false
+ }
+ if (mViewBinding.cvHomeRouteV3Card.height > 0) mViewBinding.svHomeRouteMapScroll.postDelayed(
+ { mHistoryDataMapCommon.setLatLngData(mHistoryDataList) }, 200
+ )
+ }
+ }
+ }, isShowNoDataTip = false)
+ }
+ }
+
+ //地理反编译成功返回
+ mGeoCoderViewModel.mLatLonAddressLiveData.observe(this) {
+ val position = mViewBinding.vsbMapRouteLineV3.progress
+ if (mHistoryDataList.size <= position) return@observe
+ mHistoryDataList[position].apply {
+ //详细位置
+ address = it
+ val timeString = Utils.formatTime(timeStamp * 1000, Utils.DATE_FORMAT_PATTERN_EN10)
+ //更新位置时间
+ dayTime = timeString
+ mViewBinding.root.postDelayed(
+ {
+ mViewBinding.miHomeRouteAddressViewV3.let { mi ->
+ mi.visibility = View.VISIBLE
+ mi.setShowText(timeString, it)
+ }
+ }, 100
+ )
+ }
+ }
+ }
+
+ /**
+ * 地图加载好了
+ */
+ private fun mapLoadOk() {
+ if (mCurrentShowPetPos == -1) return
+ getHomeV2Activity()?.apply {
+ showPetNameAndHead(mSelectPetPosition)
+ }
+ }
+
+ /**
+ * 设置需要更新的标识
+ */
+ fun setNeedUpdateTag() {
+ mCurrentShowPetPos = -1
+ }
+
+ /**
+ * 显示选择的宠物
+ */
+ fun showPetNameAndHead(position: Int) {
+ getHomeV2Activity()?.apply {
+ if (mPetList.size == 0) {
+ return
+ }
+ mCurrentShowPetPos = position
+
+ ViewUtil.instance.selectPetDialogShow(
+ mContext,
+ mPetList,
+ position,
+ mViewBinding.ilHomeRoutePetHeadV3.homeDataPetNameSmall,
+ mViewBinding.ilHomeRoutePetHeadV3.homeDataPetHeadSmall.appHeadImage
+ )
+
+ if (mHistoryDataMapCommon.isMapLoadOk()) {
+ getHistoryDay(mViewBinding.tvHomeRouteCalendarFromV3)
+ }
+ }
+ }
+
+ private fun setLatLngData(data: MutableList) {
+ viewLifecycleOwner.lifecycleScope.launch {
+ mHistoryDataList = data
+ getHomeV2Activity()?.getPet(false)?.let {
+ mHistoryDataMapCommon.setPetBean(it)
+ }
+
+ if (isResumed) {
+ getHomeV2Activity()?.getPet()?.let { pet ->
+ if (Util.checkPackageLimit(getHomeV2Activity()!!, pet.deviceId)) {
+ mRechargeBackType = pet.availableOrder
+ mHistoryDataMapCommon.setPetUserLatLng()
+ return@launch
+ }
+ }
+ }
+ if (data.size == 0) {
+ setSeekBarShowHide(false)
+ mHistoryDataMapCommon.setPetUserLatLng()
+ return@launch
+ }
+
+ setSeekBarShowHide(true)
+ val max = data.size - 1
+ setSeekBarMax(max)
+
+ mHistoryDataMapCommon.setLatLngData(data)
+ }
+ }
+
+ /**
+ * 设置SeekBar相关布局隐藏显示
+ */
+ private fun setSeekBarShowHide(show: Boolean) {
+ mViewBinding.apply {
+ if (show && !isListExpand) {
+ vsbMapRouteLineV3.visibility = View.VISIBLE
+ ivMapRouteLineV3LastBtn.visibility = View.VISIBLE
+ ivMapRouteLineV3NextBtn.visibility = View.VISIBLE
+ } else {
+ vsbMapRouteLineV3.visibility = View.GONE
+ ivMapRouteLineV3LastBtn.visibility = View.GONE
+ ivMapRouteLineV3NextBtn.visibility = View.GONE
+ }
+ }
+ }
+
+ private fun setSeekBarMax(max: Int) {
+ mViewBinding.vsbMapRouteLineV3.let {
+ it.max = max
+ //定位中心显示最后一个经纬度
+ it.progress = max
+ }
+ }
+
+ /**
+ * cSelectView 当前设置日期的view
+ */
+ private fun getHistoryDay(cSelectView: TypefaceTextView) {
+ mViewBinding.apply {
+// mFromTimestamp = Utils.stringToTimestamp(
+// tvHomeRouteCalendarFromV3.text.toString(), Utils.DATE_FORMAT_PATTERN_EN13
+// )
+// mToTimestamp = Utils.stringToTimestamp(
+// tvHomeRouteCalendarToV3.text.toString(), Utils.DATE_FORMAT_PATTERN_EN13
+// )
+ if (mToTimestamp - mFromTimestamp < 0) {
+ checkCorrectDate(cSelectView)
+ } else if (mToTimestamp - mFromTimestamp > mOnlySelectDay * 24 * 60 * 60 * 1000) {
+ checkCorrectDate(cSelectView)
+ }
+
+ getHomeV2Activity()?.getPet()?.apply {
+ initState()
+ mDataDetailViewModel.getHistoryByDay(
+ getHomeV2Activity()!!, deviceId, mFromTimestamp / 1000, mToTimestamp / 1000
+ )
+ }
+ }
+ }
+
+ /**
+ * 检测符合的日期
+ */
+ private fun checkCorrectDate(cSelectView: TypefaceTextView) {
+ mViewBinding.apply {
+ if (cSelectView == tvHomeRouteCalendarFromV3) {
+ mToTimestamp = Utils.getAfterHowTimestamp(mFromTimestamp, mOnlySelectDay)
+ if (mToTimestamp > mCurrentTimestamp) {
+ mToTimestamp = mCurrentTimestamp
+ }
+ tvHomeRouteCalendarToV3.text = Utils.formatTime(
+ mToTimestamp, Utils.DATE_FORMAT_PATTERN_EN13
+ )
+ mToCalenderDialog?.setSelectDate(mToTimestamp)
+ } else {
+ //结束日期小于开始日期,就默认选择结束日期前一天
+ mFromTimestamp =
+ if (mFromTimestamp > mToTimestamp) Utils.getBeforeHowTimestamp(mToTimestamp, 1L)
+ else Utils.getBeforeHowTimestamp(mToTimestamp, mOnlySelectDay)
+ tvHomeRouteCalendarFromV3.text = Utils.formatTime(
+ mFromTimestamp, Utils.DATE_FORMAT_PATTERN_EN13
+ )
+ mFromCalenderDialog?.setSelectDate(mFromTimestamp)
+ }
+ }
+ }
+
+ override fun onClick(v: View?) {
+ mViewBinding.apply {
+ when (v!!) {
+ ilHomeRoutePetHeadV3.homeDataPetNameSmall, ilHomeRoutePetHeadV3.homeDataPetHeadSmall.root -> {
+ getHomeV2Activity()?.let {
+ if (!it.isNotifyRefreshLocation) it.selectPetDialog(false)
+ }
+ }
+
+ llHomeRouteCalendarFromV3 -> {
+ getHomeV2Activity()?.getPet()?.let {
+ //防止执行多次弹窗
+ if (isLimitClick()) {
+ return
+ }
+ if (Util.checkPackageLimit(getHomeV2Activity()!!, it.deviceId)) {
+ mRechargeBackType = it.availableOrder
+ return
+ }
+ }
+
+ if (null == mFromCalenderDialog) {
+ mFromCalenderDialog = ShowCalenderAndTimeDialog(
+ mContext!!,
+ tvHomeRouteCalendarFromV3,
+ object : BaseDialog.OnDialogSelectListener {
+ override fun onSelectClick(dialog: BaseDialog<*>, any: Any) {
+ mCurrentTimestamp = System.currentTimeMillis()
+ isSelectCustomDate = true
+ mFromTimestamp = any as Long
+ getHistoryDay(tvHomeRouteCalendarFromV3)
+ }
+ },
+ calenderShowTimestamp = mFromTimestamp,
+ format = Utils.DATE_FORMAT_PATTERN_EN13
+ )
+ }
+ mFromCalenderDialog?.show()
+ }
+
+ llHomeRouteCalendarToV3 -> {
+ getHomeV2Activity()?.getPet()?.let {
+ //防止执行多次弹窗
+ if (isLimitClick()) {
+ return
+ }
+ if (Util.checkPackageLimit(getHomeV2Activity()!!, it.deviceId)) {
+ mRechargeBackType = it.availableOrder
+ return
+ }
+ }
+ if (null == mToCalenderDialog) {
+ mToCalenderDialog = ShowCalenderAndTimeDialog(
+ mContext!!,
+ tvHomeRouteCalendarToV3,
+ object : BaseDialog.OnDialogSelectListener {
+ override fun onSelectClick(dialog: BaseDialog<*>, any: Any) {
+ isSelectCustomDate = true
+ mToTimestamp = any as Long
+ getHistoryDay(tvHomeRouteCalendarToV3)
+ }
+ },
+ calenderShowTimestamp = mToTimestamp,
+ format = Utils.DATE_FORMAT_PATTERN_EN13
+ )
+ }
+ mToCalenderDialog?.show()
+ }
+
+ ivHomeRouteMapTypeBtnV3 -> mHistoryDataMapCommon.switchSatelliteAndNormalMapType()
+ ivMapRouteLineV3LastBtn -> {
+ if (vsbMapRouteLineV3.progress == 0) {
+ return
+ }
+ vsbMapRouteLineV3.progress -= 1
+ mHistoryDataMapCommon.slideStopChanged(vsbMapRouteLineV3.progress)
+ }
+
+ ivMapRouteLineV3NextBtn -> {
+ if (vsbMapRouteLineV3.progress == vsbMapRouteLineV3.max) {
+ return
+ }
+ vsbMapRouteLineV3.progress += 1
+ mHistoryDataMapCommon.slideStopChanged(vsbMapRouteLineV3.progress)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/abbidot/tracker/ui/fragment/map/MapV3Fragment.kt b/app/src/main/java/com/abbidot/tracker/ui/fragment/map/MapV3Fragment.kt
index 6e00a34..795cac6 100644
--- a/app/src/main/java/com/abbidot/tracker/ui/fragment/map/MapV3Fragment.kt
+++ b/app/src/main/java/com/abbidot/tracker/ui/fragment/map/MapV3Fragment.kt
@@ -28,17 +28,20 @@ import com.abbidot.baselibrary.util.MMKVUtil
import com.abbidot.baselibrary.util.Utils
import com.abbidot.tracker.R
import com.abbidot.tracker.adapter.HomeMapDeviceStateAdapter
+import com.abbidot.tracker.adapter.SelectMapListDialogAdapter
import com.abbidot.tracker.base.BaseDialog
import com.abbidot.tracker.base.BaseFragment
import com.abbidot.tracker.bean.BleReportDataBean
import com.abbidot.tracker.bean.BleTrackDeviceBean
import com.abbidot.tracker.bean.DataBean
import com.abbidot.tracker.bean.MapDeviceBean
+import com.abbidot.tracker.bean.MenuTxtBean
import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.constant.ConstantString
import com.abbidot.tracker.constant.GetResultCallback
import com.abbidot.tracker.databinding.FragmentMapV3Binding
import com.abbidot.tracker.dialog.CommonDialog1
+import com.abbidot.tracker.dialog.SelectMapListDialog
import com.abbidot.tracker.dialog.SelectMapTypeDialog
import com.abbidot.tracker.ui.activity.HomeV2Activity
import com.abbidot.tracker.ui.activity.map.LiveActivityV3
@@ -104,6 +107,13 @@ class MapV3Fragment : BaseFragment(FragmentMapV3Binding::i
private var needGpsToGCJ02 = true
private var mAnimatorSet: AnimatorSet? = null
+ private val mMapGooglePackageName = "com.google.android.apps.maps"
+ private val mMapGaoDePackageName = "com.autonavi.minimap"
+ private val mMapBaiduPackageName = "com.baidu.BaiduMap"
+
+ private lateinit var mSelectMapListDialogAdapter: SelectMapListDialogAdapter
+ private var mSelectMapListDialog: SelectMapListDialog? = null
+
//一键定位开始的时间戳
private var notifyRefreshLocationTimestamp = 0L
@@ -909,28 +919,110 @@ class MapV3Fragment : BaseFragment(FragmentMapV3Binding::i
}
}
- private fun goNavigation() {
- mMapDeviceBean?.let { m ->
- try {
- //自动弹出手机中已经有安装地图的应用
- val uri = if (MMKVUtil.getBoolean(MMKVKey.isGpsToGCJ02)) {
- val convertLatLon =
- LonAndLatUtil.convertFromWGS84ToGCJ02(m.latitude, m.longitude)
- "google.navigation:q=${convertLatLon[0]},${convertLatLon[1]}&mode=w".toUri()
- } else {
- "google.navigation:q=${m.latitude},${m.longitude}&mode=w".toUri()
+// private fun goNavigation() {
+// mMapDeviceBean?.let { m ->
+// try {
+// //自动弹出手机中已经有安装地图的应用
+// val uri = if (MMKVUtil.getBoolean(MMKVKey.isGpsToGCJ02)) {
+// val convertLatLon =
+// LonAndLatUtil.convertFromWGS84ToGCJ02(m.latitude, m.longitude)
+// "google.navigation:q=${convertLatLon[0]},${convertLatLon[1]}&mode=w".toUri()
+// } else {
+// "google.navigation:q=${m.latitude},${m.longitude}&mode=w".toUri()
+// }
+// val intent = Intent(Intent.ACTION_VIEW, uri)
+// intent.setPackage("com.google.android.apps.maps")
+// startActivity(intent)
+// } catch (e: Exception) {
+// showToast(getString(R.string.txt_no_install))
+// }
+// }
+// }
+
+ private fun showNavigationDialog() {
+ if (null == mSelectMapListDialog) {
+ val mapList = mutableListOf()
+ ViewUtil.instance.addMenuBean(
+ mapList,
+ getString(R.string.map_navigate_map_google),
+ mMapGooglePackageName,
+ R.drawable.ico_map_google
+ )
+ ViewUtil.instance.addMenuBean(
+ mapList,
+ getString(R.string.map_navigate_map_gaode),
+ mMapGaoDePackageName,
+ R.drawable.ico_map_gaode
+ )
+ ViewUtil.instance.addMenuBean(
+ mapList,
+ getString(R.string.map_navigate_map_baidu),
+ mMapBaiduPackageName,
+ R.drawable.ico_map_gaode
+ )
+
+ mSelectMapListDialogAdapter = SelectMapListDialogAdapter(mContext!!, mapList)
+ mSelectMapListDialogAdapter.setOnItemClickListener(object :
+ BaseRecyclerAdapter.OnItemClickListener {
+ override fun onItemClick(itemView: View?, pos: Int) {
+ selectMapNavigation(mapList[pos])
+ }
+ })
+ mSelectMapListDialog = SelectMapListDialog(mContext!!, mSelectMapListDialogAdapter)
+ }
+ mSelectMapListDialog!!.show()
+ }
+
+ /**
+ * 选择地图开始跳转
+ */
+ private fun selectMapNavigation(item: MenuTxtBean) {
+ mSelectMapListDialog?.dismiss()
+ mMapDeviceBean?.apply {
+ try {
+ when (item.menuValue) {
+ //谷歌地图
+ mMapGooglePackageName -> {
+ var lat = latitude
+ var lon = longitude
+ if (MMKVUtil.getBoolean(MMKVKey.isGpsToGCJ02)) {
+ val convertLatLon =
+ LonAndLatUtil.convertFromWGS84ToGCJ02(latitude, longitude)
+ lat = convertLatLon[0]
+ lon = convertLatLon[1]
+ }
+ val uri = "google.navigation:q=${lat},${lon}&mode=w".toUri()
+ val intent = Intent(Intent.ACTION_VIEW, uri)
+ intent.setPackage(item.menuValue)
+ startActivity(intent)
+ }
+ //高德地图 https://lbs.amap.com/api/amap-mobile/guide/android/walk-navi
+ mMapGaoDePackageName -> {
+ val uri = "amapuri://openFeature?featureName=OnFootNavi&sourceApplication=${
+ getString(
+ R.string.app_name
+ )
+ }&lat=${latitude}&lon=${longitude}&dev=1".toUri()
+ val intent = Intent(Intent.ACTION_VIEW, uri)
+ intent.setPackage(item.menuValue)
+ startActivity(intent)
+ }
+ //百度地图 https://lbs.baidu.com/docs/webapi?title=mapadjustment/uri/andriod
+ mMapBaiduPackageName -> {
+ val uri =
+ "baidumap://map/direction?destination=name:|latlng:${latitude},${longitude}&mode=walking&coord_type=wgs84".toUri()
+ val intent = Intent(Intent.ACTION_VIEW, uri)
+ intent.setPackage(item.menuValue)
+ startActivity(intent)
+ }
}
- val intent = Intent(Intent.ACTION_VIEW, uri)
- intent.setPackage("com.google.android.apps.maps")
- startActivity(intent)
} catch (e: Exception) {
- showToast(getString(R.string.txt_no_install))
+ showToast(getString(R.string.txt_no_install), gravity = Gravity.CENTER)
}
}
}
override fun onClick(v: View?) {
- if (isLimitClick()) return
mViewBinding.apply {
when (v!!) {
homeMapRefreshBtn -> {
@@ -964,6 +1056,7 @@ class MapV3Fragment : BaseFragment(FragmentMapV3Binding::i
}
homeMapLiveBtn -> {
+ if (isLimitClick()) return
if (!isCanLive) {
showToast(R.string.txt_live_works_cellular, gravity = Gravity.CENTER)
return
@@ -974,7 +1067,11 @@ class MapV3Fragment : BaseFragment(FragmentMapV3Binding::i
ivHomeMapRefreshLocation -> notifyRefreshLocation()
llHomeMapTopPet.ivTopPetBtnSmall -> showMapTypeDialog()
- homeMapBluetoothBtn -> checkPermissions(1)
+ homeMapBluetoothBtn -> {
+ if (isLimitClick()) return
+ checkPermissions(1)
+ }
+
llHomeMapTopPet.homeDataPetNameSmall, llHomeMapTopPet.homeDataPetHeadSmall.root -> {
getHomeV2Activity()?.let {
if (!it.isNotifyRefreshLocation) {
@@ -993,7 +1090,11 @@ class MapV3Fragment : BaseFragment(FragmentMapV3Binding::i
ilHomeMapDeviceMsg.root.visibility = View.GONE
}
- ilHomeMapPetLocation.ivPetLocationNavigationBtn -> goNavigation()
+ ilHomeMapPetLocation.ivPetLocationNavigationBtn -> {
+ if (isLimitClick()) return
+// goNavigation()
+ showNavigationDialog()
+ }
}
}
}
diff --git a/app/src/main/java/com/abbidot/tracker/ui/fragment/map/googlemap/HistoryDataGoogleMapFragment.kt b/app/src/main/java/com/abbidot/tracker/ui/fragment/map/googlemap/HistoryDataGoogleMapFragment.kt
index e832f9f..b6294c3 100644
--- a/app/src/main/java/com/abbidot/tracker/ui/fragment/map/googlemap/HistoryDataGoogleMapFragment.kt
+++ b/app/src/main/java/com/abbidot/tracker/ui/fragment/map/googlemap/HistoryDataGoogleMapFragment.kt
@@ -3,6 +3,7 @@ package com.abbidot.tracker.ui.fragment.map.googlemap
import android.content.Context
import android.graphics.BitmapFactory
import android.graphics.Typeface
+import androidx.appcompat.widget.AppCompatSeekBar
import androidx.core.view.isVisible
import com.abbidot.baselibrary.constant.MMKVKey
import com.abbidot.baselibrary.util.AppUtils
@@ -15,7 +16,6 @@ import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.util.ViewUtil
import com.abbidot.tracker.vm.GeoCoderViewModel
import com.abbidot.tracker.widget.MapMarkerInfoView
-import com.abbidot.tracker.widget.VerticalTopToBottomSeekBar
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.BitmapDescriptorFactory
@@ -32,7 +32,7 @@ class HistoryDataGoogleMapFragment : BaseGoogleMapFragment() {
// private val mScreenshotsViewModel: ScreenshotsViewModel by viewModels()
private lateinit var mGeoCoderViewModel: GeoCoderViewModel
private lateinit var mMarkerInfoView: MapMarkerInfoView
- private lateinit var mVerticalTopToBottomSeekBar: VerticalTopToBottomSeekBar
+ private lateinit var mVerticalTopToBottomSeekBar: AppCompatSeekBar
private val mMarkerOptions = MarkerOptions()
private lateinit var mPetIconDescriptor: BitmapDescriptor
@@ -55,7 +55,7 @@ class HistoryDataGoogleMapFragment : BaseGoogleMapFragment() {
context: Context,
markerInfoView: MapMarkerInfoView,
geoCoderViewModel: GeoCoderViewModel,
- verticalTopToBottomSeekBar: VerticalTopToBottomSeekBar,
+ verticalTopToBottomSeekBar: AppCompatSeekBar,
mapLoadOk: () -> Unit
) = HistoryDataGoogleMapFragment().apply {
mContext = context
@@ -97,9 +97,7 @@ class HistoryDataGoogleMapFragment : BaseGoogleMapFragment() {
if (getGoogleMapZoom() != cameraPosition.zoom) {
setGoogleMapZoom(cameraPosition.zoom)
}
- mCurLatLng?.let {
- if (mMarkerInfoView.isVisible) setMarkerInfoViewOffset(mMarkerInfoView, it)
- }
+ resetMarkerInfoViewOffset()
}
setOnMarkerClickListener { m ->
//点击数字大头针回到该位置
@@ -123,6 +121,12 @@ class HistoryDataGoogleMapFragment : BaseGoogleMapFragment() {
if (::mMapLoadOk.isInitialized) mMapLoadOk()
}
+ fun resetMarkerInfoViewOffset() {
+ mCurLatLng?.let {
+ if (mMarkerInfoView.isVisible) setMarkerInfoViewOffset(mMarkerInfoView, it)
+ }
+ }
+
suspend fun setPetBean(petBean: PetBean) {
if (petBean == mPetBean) {
return
@@ -153,7 +157,7 @@ class HistoryDataGoogleMapFragment : BaseGoogleMapFragment() {
mGoogleMap?.clear()
if (data.size == 0) return
-
+ mLatLngList.clear()
var maxLat = data[0].latitude
var maxLon = data[0].longitude
var minLat = data[0].latitude
@@ -195,7 +199,7 @@ class HistoryDataGoogleMapFragment : BaseGoogleMapFragment() {
* 滑动改变
*/
fun slideChanged(progress: Int) {
- setPetMarkerLatLng(mLatLngList[progress])
+ if (progress < mLatLngList.size) setPetMarkerLatLng(mLatLngList[progress])
}
/**
diff --git a/app/src/main/java/com/abbidot/tracker/util/ViewUtil.kt b/app/src/main/java/com/abbidot/tracker/util/ViewUtil.kt
index 68f9c3e..4491637 100644
--- a/app/src/main/java/com/abbidot/tracker/util/ViewUtil.kt
+++ b/app/src/main/java/com/abbidot/tracker/util/ViewUtil.kt
@@ -206,7 +206,7 @@ class ViewUtil private constructor() {
) {
numberPicker.apply {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
- selectionDividerHeight = AppUtils.dpToPx(1)
+ selectionDividerHeight = AppUtils.dpToPx(0.5f).toInt()
if (tSize > 0) {
textSize = QMUIDisplayHelper.sp2px(context, tSize).toFloat()
}
diff --git a/app/src/main/java/com/abbidot/tracker/vm/DataDetailViewModel.kt b/app/src/main/java/com/abbidot/tracker/vm/DataDetailViewModel.kt
index cc440e7..b4c7053 100644
--- a/app/src/main/java/com/abbidot/tracker/vm/DataDetailViewModel.kt
+++ b/app/src/main/java/com/abbidot/tracker/vm/DataDetailViewModel.kt
@@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope
import com.abbidot.tracker.base.BaseActivity
import com.abbidot.tracker.bean.ActiveTimeBean
import com.abbidot.tracker.bean.HistoryDataBean
+import com.abbidot.tracker.bean.MessageBean
import com.abbidot.tracker.bean.SleepTimeBean
import com.abbidot.tracker.retrofit2.NetworkApi
import kotlinx.coroutines.launch
@@ -20,6 +21,7 @@ class DataDetailViewModel : ViewModel() {
val mActiveDetailLiveData = MutableLiveData>()
val mSleepDetailLiveData = MutableLiveData>()
val mHistoryDetailLive = MutableLiveData>>()
+ val mHistoryFenceEvents = MutableLiveData>>()
val mSetGoalLiveData = MutableLiveData>()
val mPetActivityInfoLiveData = MutableLiveData>()
@@ -40,10 +42,7 @@ class DataDetailViewModel : ViewModel() {
* 获取SleepTime数据
*/
fun getSleepTimeByDay(
- activity: BaseActivity<*>,
- deviceId: String,
- dayTime: String,
- petId: String
+ activity: BaseActivity<*>, deviceId: String, dayTime: String, petId: String
) {
activity.showLoading(true)
viewModelScope.launch {
@@ -60,6 +59,16 @@ class DataDetailViewModel : ViewModel() {
}
}
+ fun getHistoryFenceList(
+ activity: BaseActivity<*>, deviceId: String, fromTime: Long, toTime: Long
+ ) {
+ activity.showLoading(true)
+ viewModelScope.launch {
+ val result = NetworkApi.getHistoryFenceList(deviceId, fromTime, toTime)
+ mHistoryFenceEvents.value = result
+ }
+ }
+
/**
*设置运动目标
* @param goalTime min
diff --git a/app/src/main/java/com/abbidot/tracker/widget/AppBarBehavior.java b/app/src/main/java/com/abbidot/tracker/widget/AppBarBehavior.java
new file mode 100644
index 0000000..280d846
--- /dev/null
+++ b/app/src/main/java/com/abbidot/tracker/widget/AppBarBehavior.java
@@ -0,0 +1,195 @@
+package com.abbidot.tracker.widget;
+
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.core.view.ViewCompat;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+/**
+ * 仿饿了么地图滑动特效
+ */
+public class AppBarBehavior extends AppBarLayout.Behavior {
+ /**
+ * nestedScrollview的滑动距离
+ */
+ int ay = 0;
+ /**
+ * nestedScrollview 沒有滑动到顶部之前的可滑动最大距离
+ */
+ private int minY = 0;
+
+ public AppBarBehavior() {
+
+ }
+
+ public AppBarBehavior(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /**
+ * AppBarLayout布局时调用
+ *
+ * @param parent 父布局CoordinatorLayout
+ * @param abl 使用此Behavior的AppBarLayout
+ * @param layoutDirection 布局方向
+ * @return 返回true表示子View重新布局,返回false表示请求默认布局
+ */
+ @Override
+ public boolean onLayoutChild(CoordinatorLayout parent, AppBarLayout abl, int layoutDirection) {
+ return super.onLayoutChild(parent, abl, layoutDirection);
+ }
+
+ /**
+ * 当CoordinatorLayout的子View尝试发起嵌套滚动时调用
+ *
+ * @param parent 父布局CoordinatorLayout
+ * @param child 使用此Behavior的AppBarLayout
+ * @param directTargetChild CoordinatorLayout的子View,或者是包含嵌套滚动操作的目标View
+ * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
+ * @param nestedScrollAxes 嵌套滚动的方向
+ * @return 返回true表示接受滚动
+ */
+ @Override
+ public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes, int type) {
+ return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
+ }
+
+
+ /**
+ * 当嵌套滚动已由CoordinatorLayout接受时调用
+ *
+ * @param coordinatorLayout 父布局CoordinatorLayout
+ * @param child 使用此Behavior的AppBarLayout
+ * @param directTargetChild CoordinatorLayout的子View,或者是包含嵌套滚动操作的目标View
+ * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
+ */
+ @Override
+ public void onNestedScrollAccepted(@NonNull CoordinatorLayout coordinatorLayout, @NonNull AppBarLayout child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
+ super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, axes, type);
+ }
+
+ /**
+ * 当准备开始嵌套滚动时调用
+ *
+ * @param coordinatorLayout 父布局CoordinatorLayout
+ * @param child 使用此Behavior的AppBarLayout
+ * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
+ * @param dx 用户在水平方向上滑动的像素数
+ * @param dy 用户在垂直方向上滑动的像素数
+ * @param consumed 输出参数,consumed[0]为水平方向应该消耗的距离,consumed[1]为垂直方向应该消耗的距离
+ */
+ @Override
+ public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed, int type) {
+ if (minY == 0) {
+ minY = target.getHeight() + child.getHeight() - coordinatorLayout.getHeight();
+ }
+ /**
+ * 如果nestedScrollview 布局内容少没有内部滑动,这时需要我们进行处理
+ * 当nestedScrollview 内容很多时,我们不需要任何事情
+ * */
+ if (target.getScrollY() <= 0) {
+ ay += dy;
+ if (dy > 0 && ay >= minY) {
+ dy = minY + dy - ay;//这里之所以没有让dy = 0;因为当快速滑动时就会有问题,快速滑动时dy的变化很大,自行琢磨一下,还不懂加群交流
+ ay = minY;
+ }
+ if (dy < 0 && ay <= 0) {
+ ay = 0;
+ dy = 0;
+ }
+ }
+ super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
+ }
+
+ /**
+ * 嵌套滚动时调用
+ *
+ * @param coordinatorLayout 父布局CoordinatorLayout
+ * @param child 使用此Behavior的AppBarLayout
+ * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
+ * @param dxConsumed 由目标View滚动操作消耗的水平像素数
+ * @param dyConsumed 由目标View滚动操作消耗的垂直像素数
+ * @param dxUnconsumed 由用户请求但是目标View滚动操作未消耗的水平像素数
+ * @param dyUnconsumed 由用户请求但是目标View滚动操作未消耗的垂直像素数
+ */
+ @Override
+ public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
+ super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
+ }
+
+ /**
+ * 当嵌套滚动的子View准备快速滚动时调用
+ *
+ * @param coordinatorLayout 父布局CoordinatorLayout
+ * @param child 使用此Behavior的AppBarLayout
+ * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
+ * @param velocityX 水平方向的速度
+ * @param velocityY 垂直方向的速度
+ * @return 如果Behavior消耗了快速滚动返回true
+ */
+ @Override
+ public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY) {
+
+ return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
+ }
+
+ /**
+ * 当嵌套滚动的子View快速滚动时调用
+ *
+ * @param coordinatorLayout 父布局CoordinatorLayout
+ * @param child 使用此Behavior的AppBarLayout
+ * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
+ * @param velocityX 水平方向的速度
+ * @param velocityY 垂直方向的速度
+ * @param consumed 如果嵌套的子View消耗了快速滚动则为true
+ * @return 如果Behavior消耗了快速滚动返回true
+ */
+ @Override
+ public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) {
+ return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
+ }
+
+ /**
+ * 当触摸时调用
+ *
+ * @param parent 父布局CoordinatorLayout
+ * @param child 使用此Behavior的AppBarLayout
+ * @param ev 手势事件
+ */
+ @Override
+ public boolean onTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
+ return super.onTouchEvent(parent, child, ev);
+ }
+
+ /**
+ * 当触摸想要拦截时调用 关键所在 true 不拦截 false 拦截AppBarLayout的手势触摸
+ *
+ * @param parent 父布局CoordinatorLayout
+ * @param child 使用此Behavior的AppBarLayout
+ * @param ev 手势事件
+ */
+ @Override
+ public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
+ return false;
+ }
+
+ /**
+ * 嵌套滚动结束时被调用
+ *
+ * @param coordinatorLayout 父布局CoordinatorLayout
+ * @param abl 使用此Behavior的AppBarLayout
+ * @param target 发起嵌套滚动的目标View(即AppBarLayout下面的ScrollView或RecyclerView)
+ */
+ @Override
+ public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl, View target, int type) {
+ super.onStopNestedScroll(coordinatorLayout, abl, target, type);
+ }
+
+}
diff --git a/app/src/main/java/com/abbidot/tracker/widget/CustomLayoutManager.java b/app/src/main/java/com/abbidot/tracker/widget/CustomLayoutManager.java
new file mode 100644
index 0000000..210f194
--- /dev/null
+++ b/app/src/main/java/com/abbidot/tracker/widget/CustomLayoutManager.java
@@ -0,0 +1,39 @@
+package com.abbidot.tracker.widget;
+
+import android.content.Context;
+
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * Created by .yzq on 2026/4/10/周五.
+ *
+ * @link
+ * @description:
+ */
+public class CustomLayoutManager extends LinearLayoutManager {
+
+ public CustomLayoutManager(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+ super.onLayoutChildren(recycler, state);
+
+ // 根据需要修改布局和滚动效果
+ // 例如调整位置或是控制滑出顶部的限制
+ }
+
+ @Override
+ public boolean canScrollVertically() {
+ return true; // 允许垂直滚动
+ }
+
+ @Override
+ public void scrollToPosition(int position) {
+ // 自定义滚动位置,确保滑动时不会被提前阻止
+ super.scrollToPosition(position);
+ }
+}
+
diff --git a/app/src/main/java/com/abbidot/tracker/widget/NoClickSlideSeekBar.java b/app/src/main/java/com/abbidot/tracker/widget/NoClickSlideSeekBar.java
new file mode 100644
index 0000000..2156bf7
--- /dev/null
+++ b/app/src/main/java/com/abbidot/tracker/widget/NoClickSlideSeekBar.java
@@ -0,0 +1,84 @@
+package com.abbidot.tracker.widget;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import androidx.appcompat.widget.AppCompatSeekBar;
+
+/**
+ * 可以通过STATUS设置 Seekbar禁止点击禁止滑动等
+ */
+public class NoClickSlideSeekBar extends AppCompatSeekBar {
+ private static final int PADDING_DEFAULT = 50;
+
+ public enum STATUS {
+ STATUS_ENABLE, STATUS_CLICK, STATUS_SLIDE, STATUS_UNABLE
+ }
+
+ /**
+ * 填充大小
+ */
+ private final int mPaddingSize = PADDING_DEFAULT;
+
+ private STATUS mStaus = STATUS.STATUS_ENABLE;
+
+ private Rect mThumbRect;
+
+ private int mX, mY;
+
+ private NoClickSlideSeekBar(Context context) {
+ super(context);
+ }
+
+ public NoClickSlideSeekBar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ private NoClickSlideSeekBar(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+
+ if (MotionEvent.ACTION_DOWN == event.getAction()) {
+ mThumbRect = getThumb().getBounds();
+ }
+ mX = (int) event.getX();
+ mY = (int) event.getY();
+
+ if (mStaus == STATUS.STATUS_CLICK && !checkBound()) {
+ return true;
+ }
+ if (mStaus == STATUS.STATUS_SLIDE && checkBound()) {
+ return true;
+ }
+ if (mStaus == STATUS.STATUS_UNABLE) {
+ return true;
+ }
+ return super.onTouchEvent(event);
+ }
+
+ /**
+ * 判断当前触摸点 是否在滑块之类-mPaddingSize是为了提高体验,因为有些滑块太小
+ *
+ * @return
+ */
+ private boolean checkBound() {
+
+ if (mX < mThumbRect.left - mPaddingSize || mX > mThumbRect.right + mPaddingSize || mY < mThumbRect.top - mPaddingSize || mY > mThumbRect.bottom + mPaddingSize) {
+ return true;
+ }
+ return false;
+ }
+
+ public void setStatus(STATUS status) {
+ this.mStaus = status;
+ }
+
+}
+
+
+
diff --git a/app/src/main/res/drawable-xhdpi/icon_bar_thumb_image.png b/app/src/main/res/drawable-xhdpi/icon_bar_thumb_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..ecfc4886f45cff0d60fd2c5eadaa4fb8372a988a
GIT binary patch
literal 428
zcmV;d0aN~oP)KzJ@Etm?-EDGZ@BH-3b(UDVs}s$TowtLmy^6jm-o8a;xV
zFYtV=(M7y|nXXkFs9qTyDq-57SmyJBP)U-?=+KVzl9`5NF$K1vF5~sI6E?Or1P7_?
zlXl2nNs(FCFq@yoz{qT8hnL7z%`8`7%XI@!_@~!{kxe8AIkT70$=ElX``4|2O@R-|
WAt-fY?5q?30000Eo3Gn!Rr->iC48UUr~J4pXZN3}N-)CBsd}5vs>V?%
zI$CR~?fcH!Y!3?PXvr=*Fi}9eGviM$<*ZSO**f
zcx$D#l^LRv))wZFDrqe+L3*6%nX|HhG;70+&a{Y31-2lkjI|YcMfQlXbI|6+lM%hW
uQOMF;Sd(=2c4*_oi>Lit^}Mp0ZTkVW7aa9IA#!~H0000!otG6y}i7=yt})*xVX3;yT6A3000YgQchC}0Dpu)
zzrsgHgu?C(6E6S&010qNS#tmY3labT3lag+-G2N400Cf0L_t(IPnFcsc7z}d1W-f}
zUH$*>Eo3Gn!Rr->iC48UUr~J4pXZN3}N-)CBsd}5vs>V?%
zI$CR~?fcH!Y!3?PXvr=*Fi}9eGviM$<*ZSO**f
zcx$D#l^LRv))wZFDrqe+L3*6%nX|HhG;70+&a{Y31-2lkjI|YcMfQlXbI|6+lM%hW
uQOMF;Sd(=2c4*_oi>Lit^}Mp0ZTkVW7aa9IA#!~H0000iW*Bv`{xEJ_r-@bk4&YeIu
zgxt1m8=O7kLheJLVy==Pzu^504)yonpD&ny{^P~&&p=Vm0*}aI1_o{+5N5n|x9$%E
z1EajBi(`m||J}*A`wkm$xNv@X_5c3^KIUzm!fTb@2A_6Le!Tc$)J?rvF;BMDH)naT
zD0ZEEZB}NgzvJ;ct6p)gIM<>3L{No&?Z2}>*e7^Rloftkxh~=1wzK+kV;t(W))n1t
z{_HsQ;mZe^?0rjSFwA$;5-oXm?8)NZkg8PSX)Q*Mq7hRL>TTu8P5MwI*IpJnfyJZR
z&!BtZq90cl9;lf)(ONQJ%($kaz_R0!$$=oB@2oRUFnm91;MLR-DtcP!ohWaDj!#%`
zR8cPXjH5mQuOEpSNWFOLn?7Yzi4uEN`T~ZX92+v~LtP$Dyv1O-cgJ6y6}RND#&cW|aD+ZTngAY3sSz|J<+ZS%r7*trhuk@A>-saxWJ@a{bNrfw?_W=<8ii
S11DhkF?hQAxvXX)
zI~QdYfKn_aL4Lsu_4^%u?%yQ<4nJa0`Jj{Oot*
z+@?0WIj`um*v({JahPLz1S+?d7QaHE~a6zCiVPgg&ebxsLQ0CDtOB>(^b
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable-xhdpi/icon_right_arrow_image.png b/app/src/main/res/drawable-xhdpi/icon_right_arrow_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..6f84105f976830232b5c1920648dfb8e27d14d6d
GIT binary patch
literal 236
zcmeAS@N?(olHy`uVBq!ia0vp^Qa~)r!3-puC-%4iDgFST5LfpCpOXHmrF~OM`X>X)
zI~QdYfKn_aL4Lsu_4^%u?%yQ<4nJa0`Jj24)@qiyop
c9;*(yIc@CCJR5%T0Ig^6boFyt=akR{0LQLVhX4Qo
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable-xhdpi/icon_vertical_dot_line_image.png b/app/src/main/res/drawable-xhdpi/icon_vertical_dot_line_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..83af35c95c8272beb5ecf05868c8eacb57eb1e2e
GIT binary patch
literal 178
zcmeAS@N?(olHy`uVBq!ia0vp^OhBB&!3-qJr%kp2Qv3lvA+FD!J$wB4v3r5fQ!wym
z*na^i#ZnUF7rftrq26uLO=}>Zv%n*=n1O*?2!t6g-L3lr6twhoaSV|NPfkcoWKdF5
z(@08TDOBX(c<|`V8IHmQQadaHcw=m11Wp{t;@I@ifqA1;Q;x-*2?yUgF=QNOvfLA7
RdlYC0gQu&X%Q~loCIG2?IhX(d
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable-xxhdpi/icon_bar_thumb_image.png b/app/src/main/res/drawable-xxhdpi/icon_bar_thumb_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..def6bc4a7d25a46bb84fdc7858ddd77d37c33661
GIT binary patch
literal 633
zcmV-<0*3vGP)^ZrruDc-cT^MKs^8e00eYWPE!DX
zzd-rFx)1;W010qNS#tmY3labT3lag+-G2N400HGmL_t(oN9~x~a)lraMFm>%`v1S%
zTu^fq5g~o(6kj^0gUdaepvmsK>*b8G_B-#g)*2UKT>fQD9#F2b_6c184G&0>H|j8W
z|CM)n@5hnQ_nH|yHekew7YdqM{=!NhYvGr;Zj*1V9@z7SAzyRq4%B|ZnQOW`gay86lI9kk3pj;&v
zKAcdh1z8h8u1+m%;NUR0tIGw4@o)fFs~A`@o@d%MUAa`lu7fv&HkXW0w}DDH$(^Q2
z*7fP>Rf{)Q#RWLN`=q_I9u+~U~!_b}-C~h5KH@UoZIztiW52s*5
z<20Z061KQr@g?73aOLL3@~8l=@gkm|alBFf&b-b008E+hIKD4s&(urUwF1HM6p1d
zt^1!hpxGDXq$+&bk{;bNY(sfvZLO`f>$+O2bxpr0@##7U-CB(wc`iWEK~S~agt|$q
zX}IbP+P{X>oR7=*qCw$S{n>FW+g7%1Sq}YJa?70Zcx*+tWf7Dmi4)9GqX$KjB65r+
zlqC^Fj+`vUp>a!}00d4A$n(K$$r7%h+M0mJJY8kLO3ArzM=SI7Pm1pRtf%a&{oE(n$~+h17j
z-alams0h2SH|=L;FN80z=Y2QspCSk63U>3`eV)%FIv}Qp7`(vl`CQ?1%!WAGaudG#_Pzr&=-Qlq^v)0U%>o&l=~dL)Y|&BYC_F?#{BswKS%9Ca6Rq1*#H0l
M07*qoM6N<$f^ZB~3IG5A
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable-xxhdpi/icon_history_no_save_fence_image.png b/app/src/main/res/drawable-xxhdpi/icon_history_no_save_fence_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..93c4915ad9e705a44a260d32aeffb59fdf1e5e96
GIT binary patch
literal 730
zcmV<00ww*4P)F1HM6p1d
zt^1!hpxGDXq$+&bk{;bNY(sfvZLO`f>$+O2bxpr0@##7U-CB(wc`iWEK~S~agt|$q
zX}IbP+P{X>oR7=*qCw$S{n>FW+g7%1Sq}YJa?70Zcx*+tWf7Dmi4)9GqX$KjB65r+
zlqC^Fj+`vUp>a!}00d4A$n(K$$r7%h+M0mJJY8kLO3ArzM=SI7Pm1pRtf%a&{oE(n$~+h17j
z-alams0h2SH|=L;FN80z=Y2QspCSk63U>3`eV)%FIv}Qp7`(vl`CQ?1%!WAGaudG#_Pzr&=-Qlq^v)0U%>o&l=~dL)Y|&BYC_F?#{BswKS%9Ca6Rq1*#H0l
M07*qoM6N<$f=_{2H~;_u
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable-xxhdpi/icon_history_save_fence_image.png b/app/src/main/res/drawable-xxhdpi/icon_history_save_fence_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..1249ea4502c000a6dedce068be8fe5af710577a1
GIT binary patch
literal 546
zcmV+-0^R+IP)0rF)GOSQZc2rszkp_JMn3nmj$qh+
z2^|8pB$mXJB+sI`L_=xMq376?_U8LMJVVC8>y*ub**sSK$?!$NeNEJ4Vvxg<@#2%?
zRClYp*sPMsBwtHQs5MUpJFD_ZVQ;l+q9AVpx?Tgu^*@5!Sggl^o<>e^w21)IBI0q(E9XrUY2n?yQB$}#D=
ze=Jze?`?ZX_kkmy?dJg>GW%-ZFW5n=+UKMHeJ}0&$u)LrbJ)b(UxB|08y`ZI3q)~0
kqN7g2N4yyCnZK;S50MBTv{*D#VgLXD07*qoM6N<$g8w}CYybcN
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable-xxhdpi/icon_left_arrow_image.png b/app/src/main/res/drawable-xxhdpi/icon_left_arrow_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..6e4349165f2d16f25e6983746f9a447b134fdd77
GIT binary patch
literal 326
zcmeAS@N?(olHy`uVBq!ia0vp^>Oic`!3-qN>`$x#Qv3lvA+GKPJ|+EAOZ%pj^iKwo
zcP`2*0Hs(;g8YIR>i0YR+`mfz$mcBZh%9Dc;1&X5#!GkW{s0Bfdb&7DpTU#6#l|6djT_OvNKm`Wb~-1mhgx;rHP4davu
WfsfkD_Iw6Oic`!3-qN>`$x#Qv3lvA+GKPJ|+EAOZq35_Dunz
zl|EnZ1Ep9>g8YIR>K*pG&s^~y$mcBZh%9Dc;1&X5#!GkW{s0Acc)B=-Sop8K>dn-u
zz`+_I@NNIIFF()7$4FdR!nT}yn!M5?rA24HGRCj@%k?BdR7}7^vhR+J#=rc$dvnb6
zpZ7d3D=R!5d8te*eRkh&rPy+h2WFgiKWT5AJ#nJ6QQ4|oxzw0u&G3iY{U%k;D!FOn
z_e}M8w0iQh-CHcBt$*tNKT#^Wt6ckMf?fZl9q*R?`B(J%`@Nnug)*vh|LLTDdH$w;
ylek!Zx8CZ_-rvI06@s{V{H4}SWa8&v#LoU$;D4~wgQ-A2FnGH9xvXC>mro;?GS
zYYL@}fl@3bL4Lsu4)yyD3KZ&qe9i)o$YKTtZXpn6ymYtj4^Yt2)5S4FBRDxBF)^_r
zkxi#z;zU8c{x#D&J2__;v8AP@t$DRF(d>j@iur*X3g$`7H?B0@Y3B_%oHL>J%7^D1
bJkAUkzA&GybD!T0G>pO1)z4*}Q$iB}e!D>|
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable-xxxhdpi/icon_bar_thumb_image.png b/app/src/main/res/drawable-xxxhdpi/icon_bar_thumb_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..cd6cfc867cce173274c4c13d9d52d60a848e8e3c
GIT binary patch
literal 797
zcmV+&1LFLNP)EX0000aP)t-sM{rEJ
zxw*KwxVN{rxVX5v|4x#l>xs4`h
zl&sak$7wQq&H-#9e0-Fb3Cr5g>Se7p#<`PkF8s-v2HO7T*-EadR+qoQTDIO^Ncl8>WSOfsNU7pGZF-aqWp%7cIFha@8EM<;X^B
zJ0bz@Nl77%iP;$mSc+{nu)~;1Y=%0JS)@`9H54VUu%>KWu~vpLL-8PWUpdGekVC5v
zn8dq!#efcF#<*^i379i4I_+1X*41DX+Wu|aJ9pKJnLF6rWp7GSA&Z8a3)GEN6gse4
z4jD{R#e~u>ObHB75uvecfQjyM6Y%bJz=D5rP%k2BloA;H6?B*U4SS)eyHqs<6>~S`
zFN9QJH%b`@{u<09aVRH`zQZ~e%Wqi6&vMrtt|6tZ&>VmPg(nF643x7UaaA#tQq3rI
zn{{e$L!D|Oy*?diB55L>Ju~Xw`{It4jFya+OgaM42eVx+{EyAyecoj_@24GON^fl(
zXl{r339I3N=fO8|(PJb!=m@7*oOi_r9}Bm{BQvNOv6BwUBRZxNgGP5{kId46BnDMT
zYI0Z9UvM|}X2hgo8!GlRg*qfuq)QV@NGf)NmgcRHRA6rUULsPlVZ7-pKGNXBW680_
z`r68*ZGU8U2CL;b?(j%^8u$HS4%4hdX4GLIm6#`k4g=aHCrsM;`&%5xNQ#p>j)rvR
zjy=YRERC)#ZOx9@GzxV#8WbO1I?44(Wj=*=gBH7SuQ0h)|0D?0URC2>(8awyyhjO1
z>w3a0N_H(Hid#}W63OnqUTfGxgKK=9gQ?60uVE_Fux-5@@Y4&_0d+tfPzTfjbwC|>
b4+s7L>SDTI;Qq(400000NkvXXu0mjfVK-{Q
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable-xxxhdpi/icon_history_danger_fence_image.png b/app/src/main/res/drawable-xxxhdpi/icon_history_danger_fence_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..1b1b1adf4a1363ef19ae4c28bad103b797ab330d
GIT binary patch
literal 1001
zcmV)z*SbE_bsR_foaZ(C-N)p9z0R3|SK|3N54E-UPLQDb$#x3#eI$YDn+p^?FUyls=cG
zNexUiK&g1YGXyS81C~SqspXtdrA@K~N|GGVMUzGai&2uaXlH2iEnv(dl!$mF>0(M@
z#HuJkiX}CyXMMp7YGuhIq?8@}2Q|M6>MjXb#o~oxdt;iiOV(8^UMLbZPLiz4;)xSK_;U(KqKKT+fl<7#QjaK);q&>g%7ckID8Ikd#GsNT@eFEJC5I>hQ^`FjQ`&nrLybNEK{Up{VZ;
z25PV#Q%%qtD0J9C={H9Cy`w4&l}fFSsyirpb*2i1Sp9}F!~T!4`VCcI9LRRBEL_GR
zuWBJp*4HVRwikd}bfMf|BLYb)xm{DfjBZpZ0M3EsBmWDu<-BRY#M|&4!mM;rM
zK|vrm7Ms_BmDVmaSYWvQyY@kEceYrHM0GDW4Y_BahE}x&Elcl$e?wta}d5LBi
z)*-GRdgFw{2F0s*beGX2$(hXX>B}a;cxUuX$Y}uc0XWf*v6w`sN|~Z%8N~V7jlDQH
z)8ZK@ei^;kzXVB*#`H|4qf11*Gf0so)zTG_i~(JsD?a%Y}>!EBimeh$=aj?$m9{?RiqGvF}e)HxZ
X&yaQ?)z*SbE_bsR_foaZ(C-N)p9z0R3|SK|3N54E-UPLQDb$#x3#eI$YDn+p^?FUyls=cG
zNexUiK&g1YGXyS81C~SqspXtdrA@K~N|GGVMUzGai&2uaXlH2iEnv(dl!$mF>0(M@
z#HuJkiX}CyXMMp7YGuhIq?8@}2Q|M6>MjXb#o~oxdt;iiOV(8^UMLbZPLiz4;)xSK_;U(KqKKT+fl<7#QjaK);q&>g%7ckID8Ikd#GsNT@eFEJC5I>hQ^`FjQ`&nrLybNEK{Up{VZ;
z25PV#Q%%qtD0J9C={H9Cy`w4&l}fFSsyirpb*2i1Sp9}F!~T!4`VCcI9LRRBEL_GR
zuWBJp*4HVRwikd}bfMf|BLYb)xm{DfjBZpZ0M3EsBmWDu<-BRY#M|&4!mM;rM
zK|vrm7Ms_BmDVmaSYWvQyY@kEceYrHM0GDW4Y_BahE}x&Elcl$e?wta}d5LBi
z)*-GRdgFw{2F0s*beGX2$(hXX>B}a;cxUuX$Y}uc0XWf*v6w`sN|~Z%8N~V7jlDQH
z)8ZK@ei^;kzXVB*#`H|4qf11*Gf0so)zTG_i~(JsD?a%Y}>!EBimeh$=aj?$m9{?RiqGvF}e)HxZ
X&yaQ?sxVgExxVX5uxVX5uxVgExwzjspxw*KwxU-=cIRF3v3UpFVQvg7}f8Woa&v5Th
zvk1lj000SaNLh0L01FZT01FZU(%pXi0006wNkl4AY`u`uiyz&wP
zRP1TtvWj5{nPftDS>~7#_;Ccxx}K}GPwisQG@gMpE8w}m4>)NUoO@hHkB!GgTr&ij
zr;
zT31M>&di8wB1<{~)K#1<<-59`7l#l+=J>@$V{MwzZ3^X}7(-5k&C5qtYO8!?f(VG#
z_46aJ+HOS=@a0x0@rD3JLjjmo3Teb;W6{(^AemvQQc!dxplp(f{mjE^9!kJu3M=Br
z46s}&xt&`ZO~Z5`?r9^
zMU|9(51}Et@&R^AF~mA?51D+)Je0T7RC^avTzT_B5>_Zt*0WRkWGssdHm0qT4N|Z0
zJ}!2a?g_-AhfD!cjk#gzMjR?Z5eM&M@`2R74XBhT5ayYADeT2FLQ8Q!r+Ny&1M=>}
zJ>=;W6unxa$*XSw>oq?Cf#@13GltmMgk;V<6m9fc%k8vrZQ||KhV_j-puEFOYF_x&
z+n(nU-qDURQr1t=Lwa6Ft9q<^Y`C=c*f(vUmtOwI(_E(-U~_&vhKsenUu+w7jqv_C
vU}E1syZE><<7C&q-z%4yIXxrr4Hn
zAL;LgiP0+qYh6g^$kp1NEt8%>0r8^Z&Zd@OPeUw7bY?5jwlnNgwx>H&V{#BNCL@?-
zl-YA-c*+svws)RPHG#W5KNuDh=Ils$0C{7Aoqb9%WGaC<`;wVqx>D5JI1vdZ35ByT
z>{%76{mVfqdu9hw{FM}x*{FVu;@dk8Y?zwm9>i9Upb+*pmI$?VBOE(AEQ+0NxnkJe
z%OQ&2PXH!eYAz<;gw?4R<#xBl)RDl#j5$Kbtl3DV?14(byeUk=yeX^{p=gkal!y^Ac9%^zUT60Mac@&l*M9!bz&jAsA<002ovPDHLkV1n}Sr=$P?
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable-xxxhdpi/icon_right_arrow_image.png b/app/src/main/res/drawable-xxxhdpi/icon_right_arrow_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..7291f1613839317a82fcfc55c71aa517ef96f7d0
GIT binary patch
literal 378
zcmV-=0fqjFP)Wp-z-(rFGgiB=qfn=I#&+NCV=>N{)dZwxl#tq*j1;CJakNw<6*CaeOvEt&Q9dUN
zL02&h9SlVq!_hKX4)iPLLX$bsH=`F(iJ-3Bm56EtmA@g1R0^R`PdO4V@|@ZrxgTyH
zJ}(LkY@b$Vr82)tc)XW5dRl*UV5OxD+S5*;cqc&+^Vha|y33e7vBZccEiXzuc?A)X
zkW8CBjikixM%GTnq45I9D_p&r(vz_-6hhjnyp^&xy%~AgEwM5Wtb;ko<8sawSa?Uc
Y4_zA`O)^mmyZ`_I07*qoM6N<$f+$&*MgRZ+
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable-xxxhdpi/icon_vertical_dot_line_image.png b/app/src/main/res/drawable-xxxhdpi/icon_vertical_dot_line_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..faf6cd5bc5e1784344c4a1ff9cfc4f4b2b16cc3f
GIT binary patch
literal 201
zcmeAS@N?(olHy`uVBq!ia0vp^EI@pNgBeKvzPw2SNbv{wgt)pF_&j^|?D6BrPr+bW
z$IB*=+L9o@V21q;^}a!WErF~q_@If0RhjpZN*
z3y%v!nu5cnwluD$(=04567D^L%nwX9ye|C3tH{X5tHf}F+hvA(3s7(iV+TWlgMeTH
foXPm&feC{X7u&&CY3tVm&1Ud)^>bP0l+XkKMh-t1
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable/shape8_gray_bg.xml b/app/src/main/res/drawable/shape8_gray_bg.xml
index dfcc015..efdbff5 100644
--- a/app/src/main/res/drawable/shape8_gray_bg.xml
+++ b/app/src/main/res/drawable/shape8_gray_bg.xml
@@ -3,13 +3,13 @@
-
-
+
-
-
+
diff --git a/app/src/main/res/drawable/shape_seek_bar_style_v3.xml b/app/src/main/res/drawable/shape_seek_bar_style_v3.xml
new file mode 100644
index 0000000..4590be3
--- /dev/null
+++ b/app/src/main/res/drawable/shape_seek_bar_style_v3.xml
@@ -0,0 +1,18 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_calender_and_time_layout.xml b/app/src/main/res/layout/dialog_calender_and_time_layout.xml
index 91a254a..dbcd04c 100644
--- a/app/src/main/res/layout/dialog_calender_and_time_layout.xml
+++ b/app/src/main/res/layout/dialog_calender_and_time_layout.xml
@@ -28,20 +28,20 @@
@@ -56,7 +56,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_history_fence_layout.xml b/app/src/main/res/layout/item_history_fence_layout.xml
new file mode 100644
index 0000000..6ce0a35
--- /dev/null
+++ b/app/src/main/res/layout/item_history_fence_layout.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index c9176ae..390a3b3 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -377,4 +377,5 @@
#00C478
#F9FFE8
#B0B0B0
+ #758E94
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 0c1abf2..7e3fa9f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -262,7 +262,7 @@
Google Map
Gaode Map
Cancel
- The APP is not installed, please download and install the app first
+ Install the map app to navigate
Active Time
Goal
@@ -1076,4 +1076,7 @@
Fell asleep %s ago
Move %s to wake up
+ Baidu Map
+ Timeline
+
\ No newline at end of file
diff --git a/baselibrary/src/main/java/com/abbidot/baselibrary/util/AppUtils.kt b/baselibrary/src/main/java/com/abbidot/baselibrary/util/AppUtils.kt
index 44c42ff..53c0ba4 100644
--- a/baselibrary/src/main/java/com/abbidot/baselibrary/util/AppUtils.kt
+++ b/baselibrary/src/main/java/com/abbidot/baselibrary/util/AppUtils.kt
@@ -39,7 +39,7 @@ class AppUtils {
/**
- * 根据包名判断app是否安装
+ * 根据包名判断app是否安装 高版本不兼容
*/
fun isAppInstalled(context: Context, packageName: String): Boolean {
val pm = context.packageManager
diff --git a/baselibrary/src/main/java/com/abbidot/baselibrary/util/Utils.kt b/baselibrary/src/main/java/com/abbidot/baselibrary/util/Utils.kt
index 60b0699..1faffe5 100644
--- a/baselibrary/src/main/java/com/abbidot/baselibrary/util/Utils.kt
+++ b/baselibrary/src/main/java/com/abbidot/baselibrary/util/Utils.kt
@@ -44,6 +44,9 @@ class Utils {
const val DATE_FORMAT_PATTERN_EN10 = "dd/MM/yyyy HH:mm:ss"
const val DATE_FORMAT_PATTERN_EN11 = "dd/MM HH:mm"
const val DATE_FORMAT_PATTERN_EN12 = "HH:mm:ss"
+ const val DATE_FORMAT_PATTERN_EN13 = "MMM d | HH:mm"
+ const val DATE_FORMAT_PATTERN_EN14 = "HH:mm"
+ const val DATE_FORMAT_PATTERN_EN15 = "MM-dd HH:mm"
//返回星期几 简写
const val WEEK_FORMAT_PATTERN = "E"