1.route页ui功能改版
@@ -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"
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
android:protectionLevel="signature" /> <!-- Optional. Required for location feature -->
|
||||
<uses-permission android:name="${applicationId}.permission.JPUSH_MESSAGE" /> <!-- 为了提高sdk识别唯一用户的能力,保证消息推送的精准送达,建议集成以下权限(可选) -->
|
||||
<!-- <uses-permission -->
|
||||
<!-- android:name="android.permission.QUERY_ALL_PACKAGES" -->
|
||||
<!-- tools:ignore="QueryAllPackagesPermission" /> -->
|
||||
<!-- 如您需要接入地理围栏业务,建议集成以下权限(可选) -->
|
||||
<uses-permission android:name="android.permission.GET_TASKS" /> <!-- 如您需要对应设备通知相关的能力,建议集成以下权限(可选) -->
|
||||
|
||||
@@ -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<MessageBean>?
|
||||
) : BaseRecyclerAdapter<MessageBean>(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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -837,6 +837,16 @@ interface INetworkService {
|
||||
@Query("toTime") toTime: Long
|
||||
): BaseResponse<MutableList<HistoryDataBean>>
|
||||
|
||||
/**
|
||||
* 获取设备进出围栏历史数据
|
||||
*/
|
||||
@GET("data/getHistoryInOutFenceList")
|
||||
suspend fun getHistoryFenceList(
|
||||
@Query("deviceId") deviceId: String,
|
||||
@Query("beginTimeStamp") fromTime: Long,
|
||||
@Query("endTimeStamp") toTime: Long
|
||||
): BaseResponse<MutableList<MessageBean>>
|
||||
|
||||
/**
|
||||
* 设置运动目标
|
||||
*/
|
||||
|
||||
@@ -753,6 +753,13 @@ object NetworkApi : BaseNetworkApi<INetworkService>(INetworkService.BASE_URL) {
|
||||
service.getHistoryByDay(deviceId, fromTime, toTime)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备进出围栏历史数据
|
||||
*/
|
||||
suspend fun getHistoryFenceList(deviceId: String, fromTime: Long, toTime: Long) = getResult {
|
||||
service.getHistoryFenceList(deviceId, fromTime, toTime)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置运动目标
|
||||
*/
|
||||
|
||||
@@ -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>(ActivityHomeV2Binding
|
||||
|
||||
private val mFragments = mutableListOf<Fragment>(
|
||||
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>(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>(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>(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>(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)
|
||||
}
|
||||
|
||||
@@ -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<HistoryDataBean>) {
|
||||
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) {
|
||||
|
||||
@@ -449,8 +449,8 @@ class RouteV2Fragment : BaseFragment<FragmentRouteV2Binding>(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<FragmentRouteV2Binding>(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)
|
||||
}
|
||||
|
||||
@@ -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>(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<HistoryDataBean>()
|
||||
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<MessageBean>()
|
||||
|
||||
//充值续费或升级返回类型
|
||||
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<HistoryDataBean>) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>(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>(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<MenuTxtBean>()
|
||||
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>(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>(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>(FragmentMapV3Binding::i
|
||||
ilHomeMapDeviceMsg.root.visibility = View.GONE
|
||||
}
|
||||
|
||||
ilHomeMapPetLocation.ivPetLocationNavigationBtn -> goNavigation()
|
||||
ilHomeMapPetLocation.ivPetLocationNavigationBtn -> {
|
||||
if (isLimitClick()) return
|
||||
// goNavigation()
|
||||
showNavigationDialog()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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<Result<ActiveTimeBean>>()
|
||||
val mSleepDetailLiveData = MutableLiveData<Result<SleepTimeBean>>()
|
||||
val mHistoryDetailLive = MutableLiveData<Result<MutableList<HistoryDataBean>>>()
|
||||
val mHistoryFenceEvents = MutableLiveData<Result<MutableList<MessageBean>>>()
|
||||
val mSetGoalLiveData = MutableLiveData<Result<String>>()
|
||||
val mPetActivityInfoLiveData = MutableLiveData<Result<ActiveTimeBean>>()
|
||||
|
||||
@@ -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
|
||||
|
||||
195
app/src/main/java/com/abbidot/tracker/widget/AppBarBehavior.java
Normal file
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
BIN
app/src/main/res/drawable-xhdpi/icon_bar_thumb_image.png
Normal file
|
After Width: | Height: | Size: 428 B |
|
After Width: | Height: | Size: 504 B |
|
After Width: | Height: | Size: 504 B |
|
After Width: | Height: | Size: 432 B |
BIN
app/src/main/res/drawable-xhdpi/icon_left_arrow_image.png
Normal file
|
After Width: | Height: | Size: 252 B |
BIN
app/src/main/res/drawable-xhdpi/icon_right_arrow_image.png
Normal file
|
After Width: | Height: | Size: 236 B |
BIN
app/src/main/res/drawable-xhdpi/icon_vertical_dot_line_image.png
Normal file
|
After Width: | Height: | Size: 178 B |
BIN
app/src/main/res/drawable-xxhdpi/icon_bar_thumb_image.png
Normal file
|
After Width: | Height: | Size: 633 B |
|
After Width: | Height: | Size: 730 B |
|
After Width: | Height: | Size: 730 B |
|
After Width: | Height: | Size: 546 B |
BIN
app/src/main/res/drawable-xxhdpi/icon_left_arrow_image.png
Normal file
|
After Width: | Height: | Size: 326 B |
BIN
app/src/main/res/drawable-xxhdpi/icon_right_arrow_image.png
Normal file
|
After Width: | Height: | Size: 305 B |
|
After Width: | Height: | Size: 186 B |
BIN
app/src/main/res/drawable-xxxhdpi/icon_bar_thumb_image.png
Normal file
|
After Width: | Height: | Size: 797 B |
|
After Width: | Height: | Size: 1001 B |
|
After Width: | Height: | Size: 1001 B |
|
After Width: | Height: | Size: 713 B |
BIN
app/src/main/res/drawable-xxxhdpi/icon_left_arrow_image.png
Normal file
|
After Width: | Height: | Size: 399 B |
BIN
app/src/main/res/drawable-xxxhdpi/icon_right_arrow_image.png
Normal file
|
After Width: | Height: | Size: 378 B |
|
After Width: | Height: | Size: 201 B |
@@ -3,13 +3,13 @@
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="false">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/block_color" />
|
||||
<solid android:color="@color/line_color1" />
|
||||
<corners android:radius="@dimen/dp_8" />
|
||||
</shape>
|
||||
</item>
|
||||
<item android:state_pressed="true">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/white" />
|
||||
<solid android:color="@color/block_color" />
|
||||
<corners android:radius="@dimen/dp_8" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
18
app/src/main/res/drawable/shape_seek_bar_style_v3.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@android:id/background">
|
||||
<shape>
|
||||
<corners android:radius="@dimen/dp_20" />
|
||||
<solid android:color="@color/grey_color_92" />
|
||||
|
||||
</shape>
|
||||
</item>
|
||||
<item android:id="@android:id/progress">
|
||||
<clip>
|
||||
<shape>
|
||||
<solid android:color="@color/line_stroke_color" />
|
||||
<corners android:radius="@dimen/dp_20" />
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -28,20 +28,20 @@
|
||||
|
||||
<NumberPicker
|
||||
android:id="@+id/np_dialog_calender_hour"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="@dimen/dp_47"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.abbidot.tracker.widget.TypefaceTextView
|
||||
android:id="@+id/tv_home_route_calendar_from"
|
||||
style="@style/my_TextView_style_v2"
|
||||
android:layout_marginHorizontal="@dimen/dp_18"
|
||||
android:layout_marginHorizontal="@dimen/dp_10"
|
||||
android:text=":"
|
||||
android:textSize="@dimen/textSize24"
|
||||
android:textSize="@dimen/textSize20"
|
||||
app:typeface="@string/roboto_bold_font" />
|
||||
|
||||
<NumberPicker
|
||||
android:id="@+id/np_dialog_calender_min"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="@dimen/dp_47"
|
||||
android:layout_height="wrap_content" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<com.abbidot.tracker.widget.TypefaceRoundButton
|
||||
android:id="@+id/btn_select_calender_hour_min_cancel"
|
||||
style="@style/my_QMUIRoundButton_small_style_v2"
|
||||
android:layout_marginEnd="@dimen/dp_4"
|
||||
android:layout_marginEnd="@dimen/dp_6"
|
||||
android:text="@string/txt_cancel"
|
||||
app:qmui_borderColor="@color/block_color2"
|
||||
app:qmui_borderWidth="0.55dp"
|
||||
@@ -65,7 +65,7 @@
|
||||
<com.abbidot.tracker.widget.TypefaceRoundButton
|
||||
android:id="@+id/btn_select_calender_hour_min_ok"
|
||||
style="@style/my_QMUIRoundButton_small_style_v2"
|
||||
android:layout_marginStart="@dimen/dp_4"
|
||||
android:layout_marginStart="@dimen/dp_6"
|
||||
android:text="@android:string/ok"
|
||||
android:textColor="@color/select_color"
|
||||
app:qmui_backgroundColor="@color/btn_yellow_color"
|
||||
|
||||
232
app/src/main/res/layout/fragment_route_v3.xml
Normal file
@@ -0,0 +1,232 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".ui.fragment.data.RouteV3Fragment">
|
||||
|
||||
|
||||
<include
|
||||
android:id="@+id/il_home_route_pet_head_v3"
|
||||
layout="@layout/layout_top_pet_data_small"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/dp_8"
|
||||
android:layout_marginTop="@dimen/dp_8" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/cv_home_route_v3_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_margin="@dimen/dp_8"
|
||||
android:layout_weight="1"
|
||||
app:cardCornerRadius="@dimen/dp_32">
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/fc_home_route_fragment_v3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<com.abbidot.tracker.widget.MapMarkerInfoView
|
||||
android:id="@+id/mi_home_route_address_view_v3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/iv_home_route_map_type_btn_v3"
|
||||
style="@style/map_image_white_btn_style"
|
||||
android:layout_gravity="top|end"
|
||||
android:layout_margin="@dimen/dp_12" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/sv_home_route_map_scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_home_route_calendar_v3_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
android:layout_marginHorizontal="@dimen/dp_8"
|
||||
android:background="@drawable/shape_home_route_calendar_bg"
|
||||
android:padding="@dimen/dp_12">
|
||||
|
||||
<View
|
||||
android:id="@+id/v_home_route_calendar_center_v3"
|
||||
android:layout_width="@dimen/dp_1"
|
||||
android:layout_height="@dimen/dp_1"
|
||||
android:layout_centerHorizontal="true" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/ll_home_route_calendar_from_v3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/dp_4"
|
||||
android:layout_toStartOf="@id/v_home_route_calendar_center_v3"
|
||||
android:background="@drawable/shape8_white_gray_bg"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:paddingVertical="@dimen/dp_8">
|
||||
|
||||
<com.abbidot.tracker.widget.TypefaceTextView
|
||||
android:id="@+id/tv_home_route_calendar_from_v3"
|
||||
style="@style/my_TextView_style_v2"
|
||||
android:layout_marginStart="@dimen/dp_12"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/textSize12"
|
||||
app:typeface="@string/roboto_regular_font" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/dp_8"
|
||||
android:src="@drawable/icon_date_time_svg" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/ll_home_route_calendar_to_v3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@id/ll_home_route_calendar_from_v3"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginStart="@dimen/dp_4"
|
||||
android:layout_toEndOf="@id/v_home_route_calendar_center_v3"
|
||||
android:background="@drawable/shape8_white_gray_bg"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:paddingVertical="@dimen/dp_8">
|
||||
|
||||
<com.abbidot.tracker.widget.TypefaceTextView
|
||||
android:id="@+id/tv_home_route_calendar_to_v3"
|
||||
style="@style/my_TextView_style_v2"
|
||||
android:layout_marginStart="@dimen/dp_12"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/textSize12"
|
||||
app:typeface="@string/roboto_regular_font" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/dp_8"
|
||||
android:src="@drawable/icon_date_time_svg" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/iv_map_route_line_v3_last_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/ll_home_route_calendar_from_v3"
|
||||
android:layout_alignStart="@id/ll_home_route_calendar_from_v3"
|
||||
android:layout_marginTop="@dimen/dp_10"
|
||||
android:background="@drawable/selector_transparent_pressed"
|
||||
android:paddingVertical="@dimen/dp_8"
|
||||
android:src="@drawable/icon_left_arrow_image"
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/iv_map_route_line_v3_next_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@id/iv_map_route_line_v3_last_btn"
|
||||
android:layout_alignEnd="@id/ll_home_route_calendar_to_v3"
|
||||
android:background="@drawable/selector_transparent_pressed"
|
||||
android:paddingVertical="@dimen/dp_8"
|
||||
android:src="@drawable/icon_right_arrow_image"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.abbidot.tracker.widget.NoClickSlideSeekBar
|
||||
android:id="@+id/vsb_map_route_line_v3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/ll_home_route_calendar_from_v3"
|
||||
android:layout_marginHorizontal="@dimen/dp_2"
|
||||
android:layout_marginTop="@dimen/dp_12"
|
||||
android:layout_toStartOf="@id/iv_map_route_line_v3_next_btn"
|
||||
android:layout_toEndOf="@id/iv_map_route_line_v3_last_btn"
|
||||
android:maxHeight="@dimen/dp_8"
|
||||
android:progress="100"
|
||||
android:progressDrawable="@drawable/shape_seek_bar_style_v3"
|
||||
android:splitTrack="false"
|
||||
android:thumb="@drawable/icon_bar_thumb_image"
|
||||
android:visibility="gone" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_map_route_line_v3_time_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dp_8"
|
||||
android:background="@drawable/shape20_white_half_bottom_bg"
|
||||
android:paddingHorizontal="@dimen/dp_14"
|
||||
android:paddingBottom="@dimen/dp_22"
|
||||
android:visibility="visible">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/ll_map_route_line_v3_zooming_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/dp_4"
|
||||
android:paddingBottom="@dimen/dp_10">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/v_map_route_line_v3_zooming"
|
||||
android:layout_width="@dimen/dp_30"
|
||||
android:layout_height="@dimen/dp_4"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/shape8_gray_bg" />
|
||||
|
||||
<com.abbidot.tracker.widget.TypefaceTextView
|
||||
style="@style/my_TextView_style_v2"
|
||||
android:layout_below="@id/ll_map_route_line_v3_zooming_layout"
|
||||
android:layout_gravity="end"
|
||||
android:text="@string/txt_time_line"
|
||||
android:textSize="@dimen/textSize12"
|
||||
app:typeface="@string/roboto_regular_font" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/iv_history_fence_start_image"
|
||||
android:layout_width="@dimen/dp_18"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/ll_map_route_line_v3_zooming_layout"
|
||||
android:layout_marginTop="@dimen/dp_2"
|
||||
android:src="@drawable/icon_right_arrow_image"
|
||||
android:tint="@color/select_color" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_map_route_line_v3_fences_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/ll_map_route_line_v3_zooming_layout"
|
||||
android:layout_marginStart="@dimen/dp_8"
|
||||
android:layout_toEndOf="@id/iv_history_fence_start_image" />
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<View
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/dp_40"
|
||||
android:background="@color/transparent" />
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
45
app/src/main/res/layout/item_history_fence_layout.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/iv_history_fence_type_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/icon_history_danger_fence_image" />
|
||||
|
||||
<com.abbidot.tracker.widget.TypefaceTextView
|
||||
android:id="@+id/tv_history_fence_type_time"
|
||||
style="@style/my_TextView_style_v2"
|
||||
android:layout_alignTop="@id/iv_history_fence_type_image"
|
||||
android:layout_alignBottom="@id/iv_history_fence_type_image"
|
||||
android:layout_marginStart="@dimen/dp_8"
|
||||
android:layout_toEndOf="@id/iv_history_fence_type_image"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="@dimen/textSize16"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.abbidot.tracker.widget.TypefaceTextView
|
||||
android:id="@+id/tv_history_fence_type_content"
|
||||
style="@style/my_TextView_style_v2"
|
||||
android:layout_below="@id/tv_history_fence_type_time"
|
||||
android:layout_alignStart="@id/tv_history_fence_type_time"
|
||||
android:layout_marginTop="@dimen/dp_6"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/select_color3"
|
||||
android:textSize="@dimen/textSize14"
|
||||
app:typeface="@string/roboto_regular_font" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/iv_history_fence_type_line"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/iv_history_fence_type_image"
|
||||
android:layout_alignStart="@id/iv_history_fence_type_image"
|
||||
android:layout_alignEnd="@id/iv_history_fence_type_image"
|
||||
android:layout_marginTop="@dimen/dp_2"
|
||||
android:src="@drawable/icon_vertical_dot_line_image" />
|
||||
</RelativeLayout>
|
||||
@@ -377,4 +377,5 @@
|
||||
<color name="rote_line_color">#00C478</color>
|
||||
<color name="light_yellow_color">#F9FFE8</color>
|
||||
<color name="grey_color_91">#B0B0B0</color>
|
||||
<color name="grey_color_92">#758E94</color>
|
||||
</resources>
|
||||
@@ -262,7 +262,7 @@
|
||||
<string name="map_navigate_map_google">Google Map</string>
|
||||
<string name="map_navigate_map_gaode">Gaode Map</string>
|
||||
<string name="map_navigate_cancel">Cancel</string>
|
||||
<string name="txt_no_install">The APP is not installed, please download and install the app first</string>
|
||||
<string name="txt_no_install">Install the map app to navigate</string>
|
||||
<!-- Data -->
|
||||
<string name="data_active_time">Active Time</string>
|
||||
<string name="data_active_goal">Goal</string>
|
||||
@@ -1076,4 +1076,7 @@
|
||||
<string name="txt_fully_asleep">Fell asleep %s ago</string>
|
||||
<string name="txt_move_wake">Move %s to wake up</string>
|
||||
|
||||
<string name="map_navigate_map_baidu">Baidu Map</string>
|
||||
<string name="txt_time_line">Timeline</string>
|
||||
|
||||
</resources>
|
||||