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 0000000..ecfc488 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_bar_thumb_image.png differ diff --git a/app/src/main/res/drawable-xhdpi/icon_history_danger_fence_image.png b/app/src/main/res/drawable-xhdpi/icon_history_danger_fence_image.png new file mode 100644 index 0000000..a789498 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_history_danger_fence_image.png differ diff --git a/app/src/main/res/drawable-xhdpi/icon_history_no_save_fence_image.png b/app/src/main/res/drawable-xhdpi/icon_history_no_save_fence_image.png new file mode 100644 index 0000000..2d5fee8 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_history_no_save_fence_image.png differ diff --git a/app/src/main/res/drawable-xhdpi/icon_history_save_fence_image.png b/app/src/main/res/drawable-xhdpi/icon_history_save_fence_image.png new file mode 100644 index 0000000..52962e8 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_history_save_fence_image.png differ diff --git a/app/src/main/res/drawable-xhdpi/icon_left_arrow_image.png b/app/src/main/res/drawable-xhdpi/icon_left_arrow_image.png new file mode 100644 index 0000000..c970dc8 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_left_arrow_image.png differ 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 0000000..6f84105 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_right_arrow_image.png differ 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 0000000..83af35c Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_vertical_dot_line_image.png differ 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 0000000..def6bc4 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_bar_thumb_image.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_history_danger_fence_image.png b/app/src/main/res/drawable-xxhdpi/icon_history_danger_fence_image.png new file mode 100644 index 0000000..6dcd4a9 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_history_danger_fence_image.png differ 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 0000000..93c4915 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_history_no_save_fence_image.png differ 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 0000000..1249ea4 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_history_save_fence_image.png differ 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 0000000..6e43491 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_left_arrow_image.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_right_arrow_image.png b/app/src/main/res/drawable-xxhdpi/icon_right_arrow_image.png new file mode 100644 index 0000000..cbda44f Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_right_arrow_image.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_vertical_dot_line_image.png b/app/src/main/res/drawable-xxhdpi/icon_vertical_dot_line_image.png new file mode 100644 index 0000000..6364706 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_vertical_dot_line_image.png differ 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 0000000..cd6cfc8 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_bar_thumb_image.png differ 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 0000000..1b1b1ad Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_history_danger_fence_image.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/icon_history_no_save_fence_image.png b/app/src/main/res/drawable-xxxhdpi/icon_history_no_save_fence_image.png new file mode 100644 index 0000000..2d18864 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_history_no_save_fence_image.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/icon_history_save_fence_image.png b/app/src/main/res/drawable-xxxhdpi/icon_history_save_fence_image.png new file mode 100644 index 0000000..cfde23a Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_history_save_fence_image.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/icon_left_arrow_image.png b/app/src/main/res/drawable-xxxhdpi/icon_left_arrow_image.png new file mode 100644 index 0000000..48b673e Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_left_arrow_image.png differ 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 0000000..7291f16 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_right_arrow_image.png differ 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 0000000..faf6cd5 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_vertical_dot_line_image.png differ 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"