1.map和直播页增加用户和宠物虚线设置

2.优化帮助页面
3.支付页面去掉税的计算
4.GPS: Off 改为GPS: Sleep;
5.map页增加位置更新时间格式:当更新滞后超过2倍的上报间隔时,才显示
(2h 35m ago)”,显示休眠中时,不显示“(2h 35m ago)
6.运动数据改为查看30天数据
7.历史轨迹限制只能看30天数据
This commit is contained in:
yezhiqiu
2026-05-07 12:02:55 +08:00
parent 587697954d
commit 5be446af72
32 changed files with 433 additions and 147 deletions

View File

@@ -28,9 +28,9 @@ android {
applicationId "com.abbidot.tracker" applicationId "com.abbidot.tracker"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 35 targetSdkVersion 35
versionCode 2203 versionCode 2204
// versionName "2.2.3" // versionName "2.2.4"
versionName "2.2.3-Beta1" versionName "2.2.4-Beta1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -2,19 +2,50 @@
<body> <body>
<div> <div>
<h3>ABBIDOT Tracker Subscription Terms and Conditions <h2>ABBIDOT Tracker Subscription Terms and Conditions</h2>
</h3> <hr>
<p>1.Subscription Plans Users can choose between Basic and Prime plans. Basic plan subscribers can upgrade to Prime at any time. Prime plan subscribers can't change to Basic plan. <h3>1. Subscription Plans</h3>
<p>ABBIDOT offers three subscription plans:</p>
<p>2.Refund Policy Automatic Refund (Within 48 Hours): Full refund available if canceled within 48 hours of subscription. Processed automatically without manual review. Manual Refund (After 48 Hours): For subscriptions older than 48 hours but within 1 month, refunds require manual approval. Eligibility: Only applicable to annual (1-year) subscriptions. Refunds may be prorated based on usage. No Refund After 1 Month: Subscriptions active for over 1 month are non-refundable.</p> <ul>
<li>3-Month Plan</li>
<p>3.Pausing Subscription & Number Retention Users may pause their subscription. Number Retention: Paused numbers can be retained for up to 1 year. A small fee will apply for number retention during the pause period. Failure to reactivate within 1 year may result in number release.</p> <li>1-Year Plan</li>
<li>2-Year Plan</li>
<p>4.Modifications ABBIDOT reserves the right to update these terms. Users will be notified of changes. By subscribing, you agree to these terms.</p> </ul>
<p>All subscriptions are automatically renewed at the end of each billing cycle unless canceled by the user.</p>
<p>For support contact:</p> <p>Users may cancel their subscription at any time. After cancellation, the subscription will remain active until the end of the current billing period, and no further charges will be applied.</p>
<p>support@abbidot.com</p> <p>The device will continue to function normally during the active subscription period.</p>
<hr>
<h3>2. Refund Policy</h3>
<h4>2.1 Automatic Refund (Within 48 Hours)</h4>
<p>All subscription purchases are eligible for a <strong>full automatic refund within 48 hours</strong> of payment. Refunds will be processed automatically without manual review.</p>
<hr>
<h4>2.2 Standard Refund Window (30 Days)</h4>
<p>After the initial 48-hour period, users may request a refund within <strong>30 days of purchase.</strong></p>
<ul>
<li>All subscription plans (3-Month, 1-Year, 2-Year) are eligible</li>
<li>Refund requests are subject to review and approval</li>
<li>Refunds may be partially adjusted based on usage and service consumption</li>
</ul>
<hr>
<h4>2.3 No Refund After 30 Days</h4>
<p>Subscriptions older than 30 days are non-refundable.</p>
<hr>
<h3>3. Subscription Cancellation</h3>
<p>Users may cancel their subscription at any time.</p>
<ul>
<li>Cancellation stops future billing</li>
<li>The current subscription remains active until the end of the billing period</li>
<li>No partial refund is issued after cancellation unless within the refund window</li>
</ul>
<hr>
<h3>4. Policy Updates</h3>
<p>ABBIDOT reserves the right to update or modify these Terms and Conditions at any time. Users will be notified of significant changes.</p>
<p>By subscribing to ABBIDOT services, you agree to these terms.</p>
<hr>
<h3>5. Customer Support</h3>
<p>If you encounter any difficulties, please contact us at:</p>
<p><a title="Mail to subscription@abbidot.com" href="subscription@abbidot.com">subscription@abbidot.com</a></p>
<p>Our support team will assist you as soon as possible.</p>
</div> </div>

View File

@@ -2,8 +2,10 @@ package com.abbidot.tracker.dialog
import android.content.Context import android.content.Context
import android.widget.CompoundButton import android.widget.CompoundButton
import com.abbidot.baselibrary.constant.MMKVKey
import com.abbidot.baselibrary.list.BaseRecyclerAdapter import com.abbidot.baselibrary.list.BaseRecyclerAdapter
import com.abbidot.baselibrary.util.AppUtils import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.baselibrary.util.MMKVUtil
import com.abbidot.tracker.base.BaseDialog import com.abbidot.tracker.base.BaseDialog
import com.abbidot.tracker.bean.DataBean import com.abbidot.tracker.bean.DataBean
import com.abbidot.tracker.databinding.DialogSelectMapTypeLayoutBinding import com.abbidot.tracker.databinding.DialogSelectMapTypeLayoutBinding
@@ -18,12 +20,14 @@ import com.abbidot.tracker.util.ViewUtil
class SelectMapTypeDialog( class SelectMapTypeDialog(
context: Context, context: Context,
adapter: BaseRecyclerAdapter<*>, adapter: BaseRecyclerAdapter<*>,
checkedChangeListener: CompoundButton.OnCheckedChangeListener? = null fenceCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null,
dashedCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null
) : BaseDialog<DialogSelectMapTypeLayoutBinding>( ) : BaseDialog<DialogSelectMapTypeLayoutBinding>(
DialogSelectMapTypeLayoutBinding::inflate, context DialogSelectMapTypeLayoutBinding::inflate, context
) { ) {
private var mAdapter = adapter private var mAdapter = adapter
private val mCheckedChangeListener = checkedChangeListener private val mFenceCheckedChangeListener = fenceCheckedChangeListener
private val mDashedCheckedChangeListener = dashedCheckedChangeListener
override fun initView() { override fun initView() {
mViewBinding.apply { mViewBinding.apply {
@@ -31,7 +35,10 @@ class SelectMapTypeDialog(
context, rvShowMapTypeList, mAdapter, right = AppUtils.dpToPx(58) context, rvShowMapTypeList, mAdapter, right = AppUtils.dpToPx(58)
) )
cbDialogMapFencesSwitch.isChecked = Util.getShowFenceSp() cbDialogMapFencesSwitch.isChecked = Util.getShowFenceSp()
cbDialogMapFencesSwitch.setOnCheckedChangeListener(mCheckedChangeListener) cbDialogMapDashedLineSwitch.isChecked =
MMKVUtil.getBoolean(MMKVKey.ShowDashedLine, true)
cbDialogMapFencesSwitch.setOnCheckedChangeListener(mFenceCheckedChangeListener)
cbDialogMapDashedLineSwitch.setOnCheckedChangeListener(mDashedCheckedChangeListener)
} }
} }
@@ -58,4 +65,8 @@ class SelectMapTypeDialog(
fun setFencesSwitch(checked: Boolean) { fun setFencesSwitch(checked: Boolean) {
mViewBinding.cbDialogMapFencesSwitch.isChecked = checked mViewBinding.cbDialogMapFencesSwitch.isChecked = checked
} }
fun setDashedSwitch(checked: Boolean) {
mViewBinding.cbDialogMapDashedLineSwitch.isChecked = checked
}
} }

View File

@@ -21,6 +21,7 @@ import java.util.Calendar
* @link * @link
* @description:显示日历弹窗 * @description:显示日历弹窗
* @param canSelectFutureDate 平时正常日期true不能选择未来时间 * @param canSelectFutureDate 平时正常日期true不能选择未来时间
* @param minLastDayRange 最小天数能选最近多少天0表示没有限制
*/ */
class ShowCalenderAndTimeDialog( class ShowCalenderAndTimeDialog(
context: Context, context: Context,
@@ -29,7 +30,8 @@ class ShowCalenderAndTimeDialog(
format: String = Utils.DATE_FORMAT_PATTERN_EN1, format: String = Utils.DATE_FORMAT_PATTERN_EN1,
canSelectFutureDate: Boolean = false, canSelectFutureDate: Boolean = false,
calenderShowTimestamp: Long = 0, calenderShowTimestamp: Long = 0,
minYear: Int = 2023 minYear: Int = 2023,
minLastDayRange: Int = 0
) : BaseDialog<DialogCalenderAndTimeLayoutBinding>( ) : BaseDialog<DialogCalenderAndTimeLayoutBinding>(
DialogCalenderAndTimeLayoutBinding::inflate, context DialogCalenderAndTimeLayoutBinding::inflate, context
), OnValueChangeListener { ), OnValueChangeListener {
@@ -44,7 +46,8 @@ class ShowCalenderAndTimeDialog(
private val mOkListener = okListener private val mOkListener = okListener
private val mMinYear = minYear private val mMinYear = minYear
private val mCalenderShowTimestamp = calenderShowTimestamp private var mCalenderShowTimestamp = calenderShowTimestamp
private val mMinLastDayRange = minLastDayRange
override fun initView() { override fun initView() {
mMonths = context.resources.getStringArray(R.array.array_month) mMonths = context.resources.getStringArray(R.array.array_month)
@@ -58,8 +61,24 @@ class ShowCalenderAndTimeDialog(
val cYear = calendar.get(Calendar.YEAR) val cYear = calendar.get(Calendar.YEAR)
val month = calendar.get(Calendar.MONTH) + 1 val month = calendar.get(Calendar.MONTH) + 1
val day = calendar.get(Calendar.DAY_OF_MONTH) val day = calendar.get(Calendar.DAY_OF_MONTH)
if (mMinLastDayRange > 0) {
val minTimestamp = Utils.getBeforeHowTimestamp(
calendar.timeInMillis, mMinLastDayRange.toLong()
)
val minDate =
Utils.formatTime(minTimestamp, Utils.DATE_FORMAT_PATTERN_CN).split("-")
it.setRange(
minDate[0].toInt(),
minDate[1].toInt(),
minDate[2].toInt(),
cYear,
month,
day
)
} else {
it.setRange(mMinYear, 1, 1, cYear, month, day) it.setRange(mMinYear, 1, 1, cYear, month, day)
} }
}
updateMonthYear() updateMonthYear()
it.setOnMonthChangeListener { year, month -> it.setOnMonthChangeListener { year, month ->
@@ -104,8 +123,6 @@ class ShowCalenderAndTimeDialog(
) )
} }
//根据传入的时间戳进行还原显示
setSelectDate(mCalenderShowTimestamp)
setOnClickListenerViews( setOnClickListenerViews(
llDialogCalenderLayout.ivSelectCalendarMonthLeft, llDialogCalenderLayout.ivSelectCalendarMonthLeft,
@@ -117,6 +134,12 @@ class ShowCalenderAndTimeDialog(
} }
} }
override fun onStart() {
super.onStart()
//根据传入的时间戳进行还原显示
setSelectDate(mCalenderShowTimestamp)
}
/** /**
* 根据传入的时间戳进行还原显示 * 根据传入的时间戳进行还原显示
* @param showTimestamp 13位时间戳 * @param showTimestamp 13位时间戳
@@ -174,11 +197,11 @@ class ShowCalenderAndTimeDialog(
val nowTimestamp = System.currentTimeMillis() val nowTimestamp = System.currentTimeMillis()
if (timesTamp > nowTimestamp) { if (timesTamp > nowTimestamp) {
//时间戳还原 mCalenderShowTimestamp = nowTimestamp
setSelectDate(nowTimestamp)
mShowCalenderTextView.text = Utils.formatTime(nowTimestamp, mDateFormat) mShowCalenderTextView.text = Utils.formatTime(nowTimestamp, mDateFormat)
mOkListener?.onSelectClick(this@ShowCalenderAndTimeDialog, nowTimestamp) mOkListener?.onSelectClick(this@ShowCalenderAndTimeDialog, nowTimestamp)
} else { } else {
mCalenderShowTimestamp = timesTamp
mShowCalenderTextView.text = Utils.stringToDate( mShowCalenderTextView.text = Utils.stringToDate(
selectMonthYear, Utils.DATE_FORMAT_PATTERN_CN2, mDateFormat selectMonthYear, Utils.DATE_FORMAT_PATTERN_CN2, mDateFormat
) )

View File

@@ -100,7 +100,7 @@ class ShowCalenderDialog(
* 根据传入的时间戳进行还原显示 * 根据传入的时间戳进行还原显示
* @param showTimestamp 13位时间戳 * @param showTimestamp 13位时间戳
*/ */
fun setSelectDate(showTimestamp: Long) { private fun setSelectDate(showTimestamp: Long) {
if (showTimestamp > 0) { if (showTimestamp > 0) {
val calendar = java.util.Calendar.getInstance().apply { val calendar = java.util.Calendar.getInstance().apply {
timeInMillis = showTimestamp timeInMillis = showTimestamp

View File

@@ -324,7 +324,7 @@ class MoreActivityActivity :
) )
} }
} }
}, calenderShowTimestamp = cTimestamp, minLastDayRange = 364) }, calenderShowTimestamp = cTimestamp, minLastDayRange = 29)
calenderDialog.show() calenderDialog.show()
} }

View File

@@ -201,7 +201,7 @@ class MoreSleepActivity :
) )
} }
} }
}, calenderShowTimestamp = cTimestamp, minLastDayRange = 364) }, calenderShowTimestamp = cTimestamp, minLastDayRange = 29)
calenderDialog.show() calenderDialog.show()
} }

View File

@@ -25,24 +25,39 @@ class HelpCreatePetFenceActivity :
ViewUtil.instance.addMenuBean( ViewUtil.instance.addMenuBean(
menuList, "", imageResId = R.drawable.create_fence_help1, menuType = MultipleEntity.IMG menuList, "", imageResId = R.drawable.create_fence_help1, menuType = MultipleEntity.IMG
) )
ViewUtil.instance.addMenuBean(
menuList, getString(R.string.txt_set_fence_type)
)
ViewUtil.instance.addMenuBean(
menuList, getString(R.string.txt_fence_type_help), menuType = MultipleEntity.IMG_IMG
)
ViewUtil.instance.addMenuBean(
menuList, getString(R.string.txt_set_boundary)
)
ViewUtil.instance.addMenuBean( ViewUtil.instance.addMenuBean(
menuList, getString(R.string.txt_create_fence_tip2), menuType = MultipleEntity.IMG_IMG menuList, getString(R.string.txt_create_fence_tip2), menuType = MultipleEntity.IMG_IMG
) )
ViewUtil.instance.addMenuBean( ViewUtil.instance.addMenuBean(
menuList, "", imageResId = R.drawable.create_fence_help2, menuType = MultipleEntity.IMG menuList, "", imageResId = R.drawable.create_fence_help2, menuType = MultipleEntity.IMG
) )
ViewUtil.instance.addMenuBean(
menuList, getString(R.string.txt_enable_set_notify)
)
ViewUtil.instance.addMenuBean( ViewUtil.instance.addMenuBean(
menuList, getString(R.string.txt_create_fence_tip3), menuType = MultipleEntity.IMG_IMG menuList, getString(R.string.txt_create_fence_tip3), menuType = MultipleEntity.IMG_IMG
) )
ViewUtil.instance.addMenuBean(
menuList, "", imageResId = R.drawable.create_fence_help3, menuType = MultipleEntity.IMG
)
ViewUtil.instance.addMenuBean(
menuList, getString(R.string.txt_create_fence_tip4), menuType = MultipleEntity.IMG_IMG
)
ViewUtil.instance.addMenuBean( ViewUtil.instance.addMenuBean(
menuList, "", imageResId = R.drawable.create_fence_help4, menuType = MultipleEntity.IMG menuList, "", imageResId = R.drawable.create_fence_help4, menuType = MultipleEntity.IMG
) )
ViewUtil.instance.addMenuBean(
menuList, getString(R.string.txt_edit_delete_fence)
)
// ViewUtil.instance.addMenuBean(
// menuList, getString(R.string.txt_create_fence_tip4), menuType = MultipleEntity.IMG_IMG
// )
// ViewUtil.instance.addMenuBean(
// menuList, "", imageResId = R.drawable.create_fence_help4, menuType = MultipleEntity.IMG
// )
val helpCreateFenceAdapter = HelpTextImageTypeAdapter(menuList) val helpCreateFenceAdapter = HelpTextImageTypeAdapter(menuList)
ViewUtil.instance.setRecyclerViewVerticalLinearLayout( ViewUtil.instance.setRecyclerViewVerticalLinearLayout(

View File

@@ -1,18 +1,53 @@
package com.abbidot.tracker.ui.activity.help package com.abbidot.tracker.ui.activity.help
import android.view.View
import com.abbidot.tracker.R import com.abbidot.tracker.R
import com.abbidot.tracker.base.BaseActivity import com.abbidot.tracker.base.BaseActivity
import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.constant.ConstantString
import com.abbidot.tracker.databinding.ActivityHelpTrackerStatusBinding import com.abbidot.tracker.databinding.ActivityHelpTrackerStatusBinding
class HelpTrackerStatusActivity : class HelpTrackerStatusActivity :
BaseActivity<ActivityHelpTrackerStatusBinding>(ActivityHelpTrackerStatusBinding::inflate) { BaseActivity<ActivityHelpTrackerStatusBinding>(ActivityHelpTrackerStatusBinding::inflate) {
private var mType = ConstantInt.Type0
override fun getTopBar() = mViewBinding.ilHelpTrackerStatusBar.titleTopBar override fun getTopBar() = mViewBinding.ilHelpTrackerStatusBar.titleTopBar
override fun initData() { override fun initData() {
super.initData() super.initData()
intent.extras?.apply {
mType = getInt(ConstantString.Type, ConstantInt.Type0)
}
mViewBinding.apply {
when (mType) {
0 -> {
setTopBarTitle(R.string.txt_check_tracker_status) setTopBarTitle(R.string.txt_check_tracker_status)
setLeftBackImage(R.drawable.icon_white_back_svg) setLeftBackImage(R.drawable.icon_white_back_svg)
mViewBinding.ilHelpTrackerStatusTitle1.tvHelpTitleOne.setText(R.string.txt_check_tracker_status_top_tip) ilHelpTrackerStatusTitle1.tvHelpTitleOne.setText(R.string.txt_check_tracker_status_top_tip)
}
1 -> {
setTopBarTitle(R.string.txt_sleep_mode)
setLeftBackImage(R.drawable.icon_white_back_svg)
ilHelpTrackerStatusTitle1.tvHelpTitleOne.setText(R.string.txt_sleep_mode_help)
ivHelpTrackerStatusImage.visibility = View.GONE
}
2 -> {
setTopBarTitle(R.string.txt_wifi_zone_home)
setLeftBackImage(R.drawable.icon_white_back_svg)
ilHelpTrackerStatusTitle1.tvHelpTitleOne.setText(R.string.txt_wifi_zone_home_help)
ivHelpTrackerStatusImage.visibility = View.GONE
}
3 -> {
setTopBarTitle(R.string.tracker_manage_set_duration)
setLeftBackImage(R.drawable.icon_white_back_svg)
ilHelpTrackerStatusTitle1.tvHelpTitleOne.setText(R.string.txt_gps_update_help)
ivHelpTrackerStatusImage.visibility = View.GONE
}
}
}
} }
} }

View File

@@ -7,6 +7,8 @@ import com.abbidot.tracker.R
import com.abbidot.tracker.adapter.HowWorkAdapter import com.abbidot.tracker.adapter.HowWorkAdapter
import com.abbidot.tracker.base.BaseActivity import com.abbidot.tracker.base.BaseActivity
import com.abbidot.tracker.bean.MenuTxtBean import com.abbidot.tracker.bean.MenuTxtBean
import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.constant.ConstantString
import com.abbidot.tracker.databinding.ActivityHowWorkBinding import com.abbidot.tracker.databinding.ActivityHowWorkBinding
import com.abbidot.tracker.util.ViewUtil import com.abbidot.tracker.util.ViewUtil
import com.qmuiteam.qmui.util.QMUIDisplayHelper import com.qmuiteam.qmui.util.QMUIDisplayHelper
@@ -26,7 +28,10 @@ class HowWorkActivity : BaseActivity<ActivityHowWorkBinding>(ActivityHowWorkBind
ViewUtil.instance.addMenuBean(menuList, getString(R.string.txt_power_on_off)) ViewUtil.instance.addMenuBean(menuList, getString(R.string.txt_power_on_off))
ViewUtil.instance.addMenuBean(menuList, getString(R.string.txt_active_tracker)) ViewUtil.instance.addMenuBean(menuList, getString(R.string.txt_active_tracker))
ViewUtil.instance.addMenuBean(menuList, getString(R.string.txt_check_tracker_status)) ViewUtil.instance.addMenuBean(menuList, getString(R.string.txt_check_tracker_status))
ViewUtil.instance.addMenuBean(menuList, getString(R.string.txt_tracker_battery_life)) ViewUtil.instance.addMenuBean(menuList, getString(R.string.txt_sleep_mode))
ViewUtil.instance.addMenuBean(menuList, getString(R.string.txt_wifi_zone_home))
ViewUtil.instance.addMenuBean(menuList, getString(R.string.tracker_manage_set_duration))
// ViewUtil.instance.addMenuBean(menuList, getString(R.string.txt_tracker_battery_life))
ViewUtil.instance.addMenuBean(menuList, getString(R.string.txt_create_pet_fence)) ViewUtil.instance.addMenuBean(menuList, getString(R.string.txt_create_pet_fence))
mHowWorkAdapter = HowWorkAdapter(this, menuList).apply { mHowWorkAdapter = HowWorkAdapter(this, menuList).apply {
setOnItemClickListener(object : BaseRecyclerAdapter.OnItemClickListener { setOnItemClickListener(object : BaseRecyclerAdapter.OnItemClickListener {
@@ -35,8 +40,26 @@ class HowWorkActivity : BaseActivity<ActivityHowWorkBinding>(ActivityHowWorkBind
0 -> startActivity(Intent(mContext, HelpPowerOnOffActivity::class.java)) 0 -> startActivity(Intent(mContext, HelpPowerOnOffActivity::class.java))
1 -> startActivity(Intent(mContext, HelpActiveTrackerActivity::class.java)) 1 -> startActivity(Intent(mContext, HelpActiveTrackerActivity::class.java))
2 -> startActivity(Intent(mContext, HelpTrackerStatusActivity::class.java)) 2 -> startActivity(Intent(mContext, HelpTrackerStatusActivity::class.java))
3 -> startActivity(Intent(mContext, HelpTrackerBatteryActivity::class.java)) 3 -> {
4 -> startActivity(Intent(mContext, HelpCreatePetFenceActivity::class.java)) Intent(mContext, HelpTrackerStatusActivity::class.java).let {
it.putExtra(ConstantString.Type, ConstantInt.Type1)
startActivity(it)
}
}
4 -> {
Intent(mContext, HelpTrackerStatusActivity::class.java).let {
it.putExtra(ConstantString.Type, ConstantInt.Type2)
startActivity(it)
}
}
5 -> {
Intent(mContext, HelpTrackerStatusActivity::class.java).let {
it.putExtra(ConstantString.Type, ConstantInt.Type3)
startActivity(it)
}
}
6 -> startActivity(Intent(mContext, HelpCreatePetFenceActivity::class.java))
} }
} }
}) })

View File

@@ -91,6 +91,9 @@ class LiveActivityV3 : BaseActivity<ActivityLiveV3Binding>(ActivityLiveV3Binding
//是否显示围栏 //是否显示围栏
private var isShowFence = true private var isShowFence = true
//是否显示虚线
private var isShowDashed = true
//地图类型,标准和卫星地图 //地图类型,标准和卫星地图
private var mMapType = ConstantInt.Type0 private var mMapType = ConstantInt.Type0
private var mShowCenterLocation = ConstantInt.PetLocationType private var mShowCenterLocation = ConstantInt.PetLocationType
@@ -138,6 +141,7 @@ class LiveActivityV3 : BaseActivity<ActivityLiveV3Binding>(ActivityLiveV3Binding
} }
isShowFence = Util.getShowFenceSp() isShowFence = Util.getShowFenceSp()
isShowDashed = MMKVUtil.getBoolean(MMKVKey.ShowDashedLine, true)
mViewBinding.apply { mViewBinding.apply {
ViewUtil.instance.viewRotationAnimator( ViewUtil.instance.viewRotationAnimator(
@@ -775,7 +779,8 @@ class LiveActivityV3 : BaseActivity<ActivityLiveV3Binding>(ActivityLiveV3Binding
private fun showMapTypeDialog() { private fun showMapTypeDialog() {
if (null == mSelectMapTypeDialog) { if (null == mSelectMapTypeDialog) {
mSelectMapTypeDialog = ViewUtil.instance.getMapTypeDialog( mSelectMapTypeDialog = ViewUtil.instance.getMapTypeDialog(
mContext, object : BaseRecyclerAdapter.OnItemClickListener { mContext,
object : BaseRecyclerAdapter.OnItemClickListener {
override fun onItemClick(itemView: View?, pos: Int) { override fun onItemClick(itemView: View?, pos: Int) {
mMapType = Util.getMapTypeSp() mMapType = Util.getMapTypeSp()
if (pos == mMapType) { if (pos == mMapType) {
@@ -783,8 +788,8 @@ class LiveActivityV3 : BaseActivity<ActivityLiveV3Binding>(ActivityLiveV3Binding
} }
mHomeMapCommon.switchSatelliteAndNormalMapType() mHomeMapCommon.switchSatelliteAndNormalMapType()
} }
}) { v, isChecked -> },
if (v.id == R.id.cb_dialog_map_fences_switch) { { _, isChecked ->
isShowFence = isChecked isShowFence = isChecked
MMKVUtil.putBoolean(MMKVKey.ShowFence, isChecked) MMKVUtil.putBoolean(MMKVKey.ShowFence, isChecked)
if (isChecked) { if (isChecked) {
@@ -794,8 +799,16 @@ class LiveActivityV3 : BaseActivity<ActivityLiveV3Binding>(ActivityLiveV3Binding
} else { } else {
mFencesMapViewModel.setFencesData(mContext, null, mFragment) mFencesMapViewModel.setFencesData(mContext, null, mFragment)
} }
},
{ _, isChecked ->
isShowDashed = isChecked
MMKVUtil.putBoolean(MMKVKey.ShowDashedLine, isChecked)
if (isChecked) {
mHomeMapCommon.addUserAndPetLine()
} else {
mHomeMapCommon.removeUserAndPetLine()
} }
} })
} else { } else {
mSelectMapTypeDialog!!.mapTypeSpToUpdate() mSelectMapTypeDialog!!.mapTypeSpToUpdate()
} }
@@ -990,6 +1003,9 @@ class LiveActivityV3 : BaseActivity<ActivityLiveV3Binding>(ActivityLiveV3Binding
} }
} }
} }
if (isShowDashed) {
mHomeMapCommon.addUserAndPetLine()
}
} }
} }
} }

View File

@@ -62,6 +62,7 @@ class SureSubscriptionPlanActivity :
//升级套餐还剩下多少差价 //升级套餐还剩下多少差价
private var mResidualMoney = 0.0 private var mResidualMoney = 0.0
//设备类型 //设备类型
private var mType = ConstantInt.Type1 private var mType = ConstantInt.Type1
@@ -253,7 +254,7 @@ class SureSubscriptionPlanActivity :
ViewUtil.instance.addMenuBean( ViewUtil.instance.addMenuBean(
mSummaryAdapter.getData(), mSummaryAdapter.getData(),
p.planName, p.planName,
"$price", Utils.formatDecimal(p.planPrice, 2),
colorRedId = R.color.data_black_color colorRedId = R.color.data_black_color
) )
mTotalMoney += price mTotalMoney += price
@@ -289,12 +290,12 @@ class SureSubscriptionPlanActivity :
isSwitch = true isSwitch = true
) )
} }
ViewUtil.instance.addMenuBean( // ViewUtil.instance.addMenuBean(
mSummaryAdapter.getData(), // mSummaryAdapter.getData(),
getString(R.string.txt_sales_tax), // getString(R.string.txt_sales_tax),
"0", // "0",
colorRedId = R.color.data_black_color // colorRedId = R.color.data_black_color
) // )
} }
//判断套餐是否过期 或者套餐没退款 //判断套餐是否过期 或者套餐没退款
@@ -417,9 +418,10 @@ class SureSubscriptionPlanActivity :
private fun updateMoney() { private fun updateMoney() {
mViewBinding.apply { mViewBinding.apply {
val list = mSummaryAdapter.getData() val list = mSummaryAdapter.getData()
val taxMoney = abs(Utils.formatDecimal(mTaxRate * mTotalMoney, 2).toDouble()) // val taxMoney = abs(Utils.formatDecimal(mTaxRate * mTotalMoney, 2).toDouble())
val taxMoney = 0.0
mOrderBean?.tax = taxMoney mOrderBean?.tax = taxMoney
list[list.size - 1].menuValue = taxMoney.toString() // list[list.size - 1].menuValue = taxMoney.toString()
mTotalWithTaxMoney = taxMoney + mTotalMoney mTotalWithTaxMoney = taxMoney + mTotalMoney
mTotalWithTaxMoney = abs(mTotalWithTaxMoney) mTotalWithTaxMoney = abs(mTotalWithTaxMoney)
ilSubscribePlanSummary.ilSureSubscribePlanTotalLayout.tvSubscribeSummaryItemMoney.text = ilSubscribePlanSummary.ilSureSubscribePlanTotalLayout.tvSubscribeSummaryItemMoney.text =

View File

@@ -10,7 +10,6 @@ import com.abbidot.tracker.base.BaseMapCommon
import com.abbidot.tracker.bean.HistoryDataBean import com.abbidot.tracker.bean.HistoryDataBean
import com.abbidot.tracker.bean.MapDeviceBean import com.abbidot.tracker.bean.MapDeviceBean
import com.abbidot.tracker.constant.ConstantInt import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.constant.LinkMapCallback
import com.abbidot.tracker.databinding.LayoutPetLocationInfoBinding import com.abbidot.tracker.databinding.LayoutPetLocationInfoBinding
import com.abbidot.tracker.ui.fragment.map.baidumap.HomeMapBaiduMapFragment import com.abbidot.tracker.ui.fragment.map.baidumap.HomeMapBaiduMapFragment
import com.abbidot.tracker.ui.fragment.map.googlemap.HomeMapGoogleMapFragmentV3 import com.abbidot.tracker.ui.fragment.map.googlemap.HomeMapGoogleMapFragmentV3
@@ -199,6 +198,14 @@ class HomeMapCommonV3 @Inject constructor() : BaseMapCommon() {
return mHomeMapGoogleMapFragment?.mUserLatLng return mHomeMapGoogleMapFragment?.mUserLatLng
} }
fun addUserAndPetLine() {
mHomeMapGoogleMapFragment?.addUserAndPetLine()
}
fun removeUserAndPetLine() {
mHomeMapGoogleMapFragment?.removeUserAndPetLine()
}
// fun getAddressShowMarkerInfoWindow(historyDataBean: HistoryDataBean) { // fun getAddressShowMarkerInfoWindow(historyDataBean: HistoryDataBean) {
// if (null != mHomeMapBaiduMapFragment) { // if (null != mHomeMapBaiduMapFragment) {
// mHomeMapBaiduMapFragment!!.showMarkerInfoWindow(historyDataBean) // mHomeMapBaiduMapFragment!!.showMarkerInfoWindow(historyDataBean)

View File

@@ -643,7 +643,8 @@ class RouteV3Fragment : BaseFragment<FragmentRouteV3Binding>(FragmentRouteV3Bind
} }
}, },
calenderShowTimestamp = mFromTimestamp, calenderShowTimestamp = mFromTimestamp,
format = Utils.DATE_FORMAT_PATTERN_EN13 format = Utils.DATE_FORMAT_PATTERN_EN13,
minLastDayRange = 29
) )
} }
mFromCalenderDialog?.show() mFromCalenderDialog?.show()
@@ -672,7 +673,8 @@ class RouteV3Fragment : BaseFragment<FragmentRouteV3Binding>(FragmentRouteV3Bind
} }
}, },
calenderShowTimestamp = mToTimestamp, calenderShowTimestamp = mToTimestamp,
format = Utils.DATE_FORMAT_PATTERN_EN13 format = Utils.DATE_FORMAT_PATTERN_EN13,
minLastDayRange = 29
) )
} }
mToCalenderDialog?.show() mToCalenderDialog?.show()

View File

@@ -503,7 +503,7 @@ class HomeTrackFragment :
ViewUtil.instance.addMenuBean( ViewUtil.instance.addMenuBean(
mTrackStateList, mTrackStateList,
getString(R.string.tracker_manage_set_gps), getString(R.string.tracker_manage_set_gps),
getString(R.string.tracker_manage_set_led_off), getString(R.string.txt_sleep),
imageResId = R.drawable.icon_map_gps imageResId = R.drawable.icon_map_gps
) )
ViewUtil.instance.addMenuBean( ViewUtil.instance.addMenuBean(
@@ -669,7 +669,7 @@ class HomeTrackFragment :
it.menuValue = it.menuValue =
if (isTimeoutReport || powerSwitch == ConstantInt.Type0 || powerSwitch == ConstantInt.Type2 || powerSwitch == ConstantInt.Type3 || inWifiZone == ConstantInt.Type1) { if (isTimeoutReport || powerSwitch == ConstantInt.Type0 || powerSwitch == ConstantInt.Type2 || powerSwitch == ConstantInt.Type3 || inWifiZone == ConstantInt.Type1) {
it.colorRedId = R.color.orange_color3 it.colorRedId = R.color.orange_color3
getString(R.string.tracker_manage_set_led_off) getString(R.string.txt_sleep)
} else if (gpsSignal > ConstantInt.WeakSignal) getString(R.string.txt_strong_signal) } else if (gpsSignal > ConstantInt.WeakSignal) getString(R.string.txt_strong_signal)
else if (gpsSignal == ConstantInt.NoSignal) { else if (gpsSignal == ConstantInt.NoSignal) {
it.colorRedId = R.color.orange_color3 it.colorRedId = R.color.orange_color3

View File

@@ -9,6 +9,8 @@ import android.location.LocationManager
import android.provider.Settings import android.provider.Settings
import android.view.Gravity import android.view.Gravity
import android.view.View import android.view.View
import android.widget.CompoundButton
import android.widget.CompoundButton.OnCheckedChangeListener
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
@@ -63,7 +65,8 @@ import javax.inject.Inject
* create an instance of this fragment. * create an instance of this fragment.
*/ */
@AndroidEntryPoint @AndroidEntryPoint
class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::inflate) { class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::inflate),
OnCheckedChangeListener {
private val mFencesMapViewModel: FencesMapViewModel by viewModels() private val mFencesMapViewModel: FencesMapViewModel by viewModels()
private val mMapViewModel: MapViewModel by viewModels() private val mMapViewModel: MapViewModel by viewModels()
@@ -93,6 +96,9 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
//是否显示围栏 //是否显示围栏
private var isShowFence = true private var isShowFence = true
//是否显示虚线
private var isShowDashed = true
//地图类型,标准和卫星地图 //地图类型,标准和卫星地图
private var mMapType = ConstantInt.Type0 private var mMapType = ConstantInt.Type0
@@ -120,6 +126,7 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
} }
isShowFence = Util.getShowFenceSp() isShowFence = Util.getShowFenceSp()
isShowDashed = MMKVUtil.getBoolean(MMKVKey.ShowDashedLine, true)
mViewBinding.apply { mViewBinding.apply {
getHomeV2Activity()?.edgeToEdgeAdapterBars( getHomeV2Activity()?.edgeToEdgeAdapterBars(
@@ -208,6 +215,7 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
} }
val showFence = Util.getShowFenceSp() val showFence = Util.getShowFenceSp()
val showDashed = MMKVUtil.getBoolean(MMKVKey.ShowDashedLine, true)
//检测直播页面有没有修改围栏显示 //检测直播页面有没有修改围栏显示
if (isShowFence != showFence) { if (isShowFence != showFence) {
if (null == mSelectMapTypeDialog) { if (null == mSelectMapTypeDialog) {
@@ -216,6 +224,13 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
mSelectMapTypeDialog?.setFencesSwitch(showFence) mSelectMapTypeDialog?.setFencesSwitch(showFence)
} }
} }
if (isShowDashed != showDashed) {
if (null == mSelectMapTypeDialog) {
setDashedShow(showDashed)
} else {
mSelectMapTypeDialog?.setDashedSwitch(showDashed)
}
}
} }
private fun getHomeV2Activity(): HomeV2Activity? { private fun getHomeV2Activity(): HomeV2Activity? {
@@ -548,11 +563,8 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
} }
mHomeMapCommon.switchSatelliteAndNormalMapType() mHomeMapCommon.switchSatelliteAndNormalMapType()
} }
}) { v, isChecked -> }, this, this
if (v.id == R.id.cb_dialog_map_fences_switch) { )
setFencesShow(isChecked)
}
}
else { else {
mSelectMapTypeDialog!!.mapTypeSpToUpdate() mSelectMapTypeDialog!!.mapTypeSpToUpdate()
} }
@@ -574,6 +586,19 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
} }
} }
/**
* 设置虚线显示
*/
private fun setDashedShow(isShow: Boolean) {
isShowDashed = isShow
MMKVUtil.putBoolean(MMKVKey.ShowDashedLine, isShow)
if (isShow) {
mHomeMapCommon.addUserAndPetLine()
} else {
mHomeMapCommon.removeUserAndPetLine()
}
}
/** /**
* 设置需要更新的标识 * 设置需要更新的标识
*/ */
@@ -678,6 +703,9 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
mFencesMapViewModel.setFencesData(mContext!!, fences, mFragment) mFencesMapViewModel.setFencesData(mContext!!, fences, mFragment)
} }
} }
if (isShowDashed) {
mHomeMapCommon.addUserAndPetLine()
}
} }
} }
@@ -929,6 +957,12 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
// } // }
// } // }
override fun onCheckedChanged(v: CompoundButton, isChecked: Boolean) {
when (v.id) {
R.id.cb_dialog_map_fences_switch -> setFencesShow(isChecked)
R.id.cb_dialog_map_dashed_line_switch -> setDashedShow(isChecked)
}
}
override fun onClick(v: View?) { override fun onClick(v: View?) {
mViewBinding.apply { mViewBinding.apply {
@@ -1008,5 +1042,4 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
} }
} }
} }
} }

View File

@@ -406,14 +406,15 @@ abstract class BaseGoogleMapFragment :
if (MMKVUtil.getBoolean(MMKVKey.isGpsToGCJ02)) { if (MMKVUtil.getBoolean(MMKVKey.isGpsToGCJ02)) {
mUserLatLng?.let { mUserLatLng?.let {
if (null == mUserMarker) { if (null == mUserMarker) {
mUserMarker = addImageMarker(it, R.drawable.icon_user_location_image) mUserMarker = addImageMarker(it, R.drawable.icon_user_location_image,false)
} else { } else {
if (it.latitude == mUserMarker!!.position.latitude && it.longitude == mUserMarker!!.position.longitude) { if (it.latitude == mUserMarker!!.position.latitude && it.longitude == mUserMarker!!.position.longitude) {
} else { } else {
mUserMarker?.remove() mUserMarker?.remove()
mUserMarker = addImageMarker(it, R.drawable.icon_user_location_image) mUserMarker = addImageMarker(it, R.drawable.icon_user_location_image,false)
} }
} }
mUserMarker?.setAnchor(0.5f,0.5f)
} }
} }
// else { // else {
@@ -791,7 +792,7 @@ abstract class BaseGoogleMapFragment :
/** /**
* 获取地图画线的PolylineOptions * 获取地图画线的PolylineOptions
*/ */
private fun getPolylineOptions(widthDp: Float, lineColorRes: Int): PolylineOptions { fun getPolylineOptions(widthDp: Float, lineColorRes: Int): PolylineOptions {
return PolylineOptions().clickable(false).width(AppUtils.dpToPx(widthDp)) return PolylineOptions().clickable(false).width(AppUtils.dpToPx(widthDp))
.color(ContextCompat.getColor(mContext!!, lineColorRes)).geodesic(false) .color(ContextCompat.getColor(mContext!!, lineColorRes)).geodesic(false)
} }

View File

@@ -25,7 +25,6 @@ import com.google.android.gms.maps.model.CircleOptions
import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.Marker import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.Polyline import com.google.android.gms.maps.model.Polyline
import com.google.android.gms.maps.model.PolylineOptions
import kotlin.math.pow import kotlin.math.pow
/** /**
@@ -47,7 +46,7 @@ class HomeMapGoogleMapFragmentV3 : BaseGoogleMapFragment() {
//启动动画移动地图摄像机 //启动动画移动地图摄像机
private var isMoveCamera = true private var isMoveCamera = true
private var mPolyline: Polyline? = null private var mUserAndPetLine: Polyline? = null
private var mRippleCircle: Circle? = null private var mRippleCircle: Circle? = null
private var mValueAnimator: ValueAnimator? = null private var mValueAnimator: ValueAnimator? = null
@@ -111,6 +110,19 @@ class HomeMapGoogleMapFragmentV3 : BaseGoogleMapFragment() {
mPetLocationLayoutBinding.let { layout -> mPetLocationLayoutBinding.let { layout ->
layout.tvPetLocationReverseGeocode.text = address layout.tvPetLocationReverseGeocode.text = address
layout.tvPetLocationUpdateTime.text = timeString layout.tvPetLocationUpdateTime.text = timeString
layout.tvPetLocationUpdateTimeFormat.visibility =
if (powerSwitch == ConstantInt.Type2) View.GONE
else {
if (Util.isTimeoutReport(updateTime, gnssInterval)) {
layout.tvPetLocationUpdateTimeFormat.text = String.format(
getString(R.string.txt_location_ago),
Utils.getTimeDifference(
updateTime * 1000, System.currentTimeMillis()
)
)
View.VISIBLE
} else View.GONE
}
} }
} }
} }
@@ -207,27 +219,26 @@ class HomeMapGoogleMapFragmentV3 : BaseGoogleMapFragment() {
/** /**
* 画用户和宠物之间的虚线 * 画用户和宠物之间的虚线
*/ */
private fun addUserAndPetLine(petLatLng: LatLng) { fun addUserAndPetLine() {
mUserLatLng?.apply { mGoogleMap?.apply {
mGoogleMap?.let { mUserLatLng?.let { u ->
if (null == mPolyline) { mPetLatLng?.let { p ->
val polylineOptions = mUserAndPetLine?.remove()
PolylineOptions().clickable(false).width(AppUtils.dpToPx(1.5f)) getPolylineOptions(1.5f, R.color.blue_color9).let {
.color(ContextCompat.getColor(mContext!!, R.color.blue_color9)) it.add(toGCJ02LatLon(p))
.geodesic(false) it.add(toGCJ02LatLon(u))
mPolyline = it.addPolyline(polylineOptions) mUserAndPetLine = addPolyline(it)
mPolyline?.pattern = getDashedPatternStyle(18f)
} }
mPolyline?.let { pLine -> mUserAndPetLine?.pattern = getDashedPatternStyle(18f)
val latList = mutableListOf<LatLng>()
latList.add(petLatLng)
latList.add(this)
pLine.points = latList
} }
} }
} }
} }
fun removeUserAndPetLine() {
mUserAndPetLine?.remove()
}
/** /**
* 初始化并添加水波纹圆 * 初始化并添加水波纹圆
*/ */

View File

@@ -878,7 +878,8 @@ class ViewUtil private constructor() {
fun getMapTypeDialog( fun getMapTypeDialog(
context: Context, context: Context,
onItemClickListener: BaseRecyclerAdapter.OnItemClickListener? = null, onItemClickListener: BaseRecyclerAdapter.OnItemClickListener? = null,
checkedChangeListener: CompoundButton.OnCheckedChangeListener? = null fenceCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null,
dashedCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null
): SelectMapTypeDialog { ): SelectMapTypeDialog {
val mapType = Util.getMapTypeSp() val mapType = Util.getMapTypeSp()
val typeList = mutableListOf<DataBean>() val typeList = mutableListOf<DataBean>()
@@ -902,7 +903,9 @@ class ViewUtil private constructor() {
} }
}) })
} }
return SelectMapTypeDialog(context, mapTypeAdapter, checkedChangeListener) return SelectMapTypeDialog(
context, mapTypeAdapter, fenceCheckedChangeListener, dashedCheckedChangeListener
)
} }
/** /**

View File

@@ -35,7 +35,6 @@ import com.abbidot.tracker.widget.TypefaceButton
import com.abbidot.tracker.widget.TypefaceTextView import com.abbidot.tracker.widget.TypefaceTextView
import com.clj.fastble.BleManager import com.clj.fastble.BleManager
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.util.concurrent.TimeUnit
class MapViewModel : ViewModel() { class MapViewModel : ViewModel() {
@@ -114,7 +113,7 @@ class MapViewModel : ViewModel() {
menuType = ConstantInt.Close menuType = ConstantInt.Close
name = context.getString(R.string.tracker_manage_set_gps) name = context.getString(R.string.tracker_manage_set_gps)
value = value =
context.getString(R.string.tracker_manage_set_gps) + "" + context.getString(R.string.tracker_manage_set_led_off) context.getString(R.string.tracker_manage_set_gps) + "" + context.getString(R.string.txt_sleep)
deviceStateList.add(this) deviceStateList.add(this)
} }
DataBean().apply { DataBean().apply {
@@ -302,7 +301,7 @@ class MapViewModel : ViewModel() {
deviceStateList[1].apply { deviceStateList[1].apply {
menuType = ConstantInt.Close menuType = ConstantInt.Close
value = value =
context.getString(R.string.tracker_manage_set_gps) + "" + context.getString(R.string.tracker_manage_set_led_off) context.getString(R.string.tracker_manage_set_gps) + "" + context.getString(R.string.txt_sleep)
} }
deviceStateList[2].apply { deviceStateList[2].apply {
menuType = ConstantInt.Close menuType = ConstantInt.Close
@@ -344,13 +343,12 @@ class MapViewModel : ViewModel() {
val gpsValue = val gpsValue =
if (isTimeoutReport || it.powerSwitch == ConstantInt.Type0 || it.powerSwitch == ConstantInt.Type2 || it.powerSwitch == ConstantInt.Type3 || it.inWifiZone == ConstantInt.Type1) { if (isTimeoutReport || it.powerSwitch == ConstantInt.Type0 || it.powerSwitch == ConstantInt.Type2 || it.powerSwitch == ConstantInt.Type3 || it.inWifiZone == ConstantInt.Type1) {
menuType = ConstantInt.Close menuType = ConstantInt.Close
context.getString(R.string.tracker_manage_set_led_off) context.getString(R.string.txt_sleep)
} else if (it.gpsSignal > ConstantInt.WeakSignal) context.getString(R.string.txt_strong_signal) } else if (it.gpsSignal > ConstantInt.WeakSignal) context.getString(R.string.txt_strong_signal)
else if (it.gpsSignal == ConstantInt.NoSignal) { else if (it.gpsSignal == ConstantInt.NoSignal) {
menuType = ConstantInt.Close menuType = ConstantInt.Close
context.getString(R.string.txt_no_signal) context.getString(R.string.txt_no_signal)
} } else context.getString(R.string.txt_weak_signal)
else context.getString(R.string.txt_weak_signal)
value = context.getString(R.string.tracker_manage_set_gps) + "$gpsValue" value = context.getString(R.string.tracker_manage_set_gps) + "$gpsValue"
} }
deviceStateList[2].apply { deviceStateList[2].apply {
@@ -476,7 +474,7 @@ class MapViewModel : ViewModel() {
) )
it.text = String.format( it.text = String.format(
context.getString(R.string.txt_fell_asleep), context.getString(R.string.txt_fell_asleep),
getTimeDifference(updateTime * 1000, System.currentTimeMillis()) Utils.getTimeDifference(updateTime * 1000, System.currentTimeMillis())
) )
ViewUtil.instance.viewShow(closeBtn) ViewUtil.instance.viewShow(closeBtn)
} else if (powerSwitch == ConstantInt.Type0) { } else if (powerSwitch == ConstantInt.Type0) {
@@ -517,37 +515,6 @@ class MapViewModel : ViewModel() {
} }
} }
private fun getTimeDifference(startMillis: Long, endMillis: Long): String {
var diff = endMillis - startMillis
val days = TimeUnit.MILLISECONDS.toDays(diff)
diff -= TimeUnit.DAYS.toMillis(days)
val hours = TimeUnit.MILLISECONDS.toHours(diff)
diff -= TimeUnit.HOURS.toMillis(hours)
val minutes = TimeUnit.MILLISECONDS.toMinutes(diff)
var timeStr: String
if (days > 0) {
timeStr = if (days > 1) {
"$days days"
} else {
"$days day"
}
if (hours > 0) {
timeStr += " ${hours}h"
}
} else {
if (hours > 0) {
timeStr = "${hours}h"
if (minutes > 0) timeStr += " ${minutes}m"
} else {
timeStr = if (minutes > 0) "${minutes}m"
else "1m"
}
}
return timeStr
}
fun setPetLocationReverseGeocode( fun setPetLocationReverseGeocode(
context: Context, context: Context,
mapDeviceBean: MapDeviceBean, mapDeviceBean: MapDeviceBean,

View File

@@ -159,7 +159,8 @@ public class HorizontalCalenderViewV2 extends FrameLayout {
//获取当月的日期 //获取当月的日期
// List<DateItem> items = getItems(); // List<DateItem> items = getItems();
//获取最近365天的日期 //获取最近365天的日期
List<DateItem> items = getLast365DaysItems(); // List<DateItem> items = getLast365DaysItems();
List<DateItem> items = getLast30DaysItems();
adapter = new DayV2Adapter(context, items, dayTextColorSelected, dayTextColorNormal, adapter = new DayV2Adapter(context, items, dayTextColorSelected, dayTextColorNormal,
daySelectionColor, weekTextColor, pressShapeSelectorId, todayPointColor); daySelectionColor, weekTextColor, pressShapeSelectorId, todayPointColor);
adapter.setItemClick((year, month, day, week) -> { adapter.setItemClick((year, month, day, week) -> {

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android" <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" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -18,13 +19,22 @@
android:layout_marginVertical="@dimen/dp_18" android:layout_marginVertical="@dimen/dp_18"
android:orientation="vertical"> android:orientation="vertical">
<com.abbidot.tracker.widget.TypefaceTextView
style="@style/my_TextView_style_v2"
android:layout_marginHorizontal="@dimen/dp_22"
android:gravity="start"
android:text="@string/txt_first_use"
android:textSize="@dimen/textSize16"
android:textStyle="bold"
app:lineHeight="@dimen/textSize20" />
<include <include
android:id="@+id/il_help_power_on_off_title" android:id="@+id/il_help_power_on_off_title"
layout="@layout/layout_help_title1" layout="@layout/layout_help_title1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_22" /> android:layout_marginHorizontal="@dimen/dp_22"
android:layout_marginTop="@dimen/dp_6" />
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
@@ -38,13 +48,24 @@
android:paddingBottom="@dimen/dp_12" android:paddingBottom="@dimen/dp_12"
android:scaleType="fitCenter" /> android:scaleType="fitCenter" />
<com.abbidot.tracker.widget.TypefaceTextView
style="@style/my_TextView_style_v2"
android:layout_marginHorizontal="@dimen/dp_22"
android:layout_marginTop="@dimen/dp_26"
android:gravity="start"
android:text="@string/txt_daily_use"
android:textSize="@dimen/textSize16"
android:textStyle="bold"
app:lineHeight="@dimen/textSize20" />
<include <include
android:id="@+id/il_help_shake_title" android:id="@+id/il_help_shake_title"
layout="@layout/layout_help_title1" layout="@layout/layout_help_title1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_22" android:layout_marginHorizontal="@dimen/dp_22"
android:layout_marginVertical="@dimen/dp_26" /> android:layout_marginTop="@dimen/dp_6"
android:layout_marginBottom="@dimen/dp_26" />
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView

View File

@@ -32,9 +32,11 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_22" android:layout_marginHorizontal="@dimen/dp_22"
android:layout_marginTop="@dimen/dp_20" /> android:layout_marginTop="@dimen/dp_20"
android:visibility="gone" />
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_help_tracker_status_image"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"

View File

@@ -41,8 +41,9 @@
android:checked="true" /> android:checked="true" />
</androidx.appcompat.widget.LinearLayoutCompat> </androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat <androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll_map_type_show_accuracy_switch" android:id="@+id/ll_map_type_show_dashed_line_switch"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/ll_map_type_display_fences_switch" android:layout_below="@id/ll_map_type_display_fences_switch"
@@ -50,7 +51,6 @@
android:background="@drawable/shape8_gray_border_transparent_bg" android:background="@drawable/shape8_gray_border_transparent_bg"
android:gravity="center_vertical" android:gravity="center_vertical"
android:minHeight="@dimen/dp_47" android:minHeight="@dimen/dp_47"
android:visibility="gone"
android:orientation="horizontal" android:orientation="horizontal"
android:paddingHorizontal="@dimen/dp_16"> android:paddingHorizontal="@dimen/dp_16">
@@ -58,12 +58,14 @@
style="@style/my_TextView_style_v2" style="@style/my_TextView_style_v2"
android:layout_weight="1" android:layout_weight="1"
android:gravity="start" android:gravity="start"
android:text="@string/txt_show_accuracy" android:text="@string/txt_display_dashed_line"
android:textSize="@dimen/textSize14" android:textSize="@dimen/textSize14"
app:typeface="@string/roboto_bold_font" /> app:typeface="@string/roboto_bold_font" />
<androidx.appcompat.widget.AppCompatCheckBox <androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/cb_dialog_map_dashed_line_switch"
style="@style/my_checkbox_switch_style" style="@style/my_checkbox_switch_style"
android:layout_width="@dimen/dp_47" /> android:layout_width="@dimen/dp_47"
android:checked="true" />
</androidx.appcompat.widget.LinearLayoutCompat> </androidx.appcompat.widget.LinearLayoutCompat>
</RelativeLayout> </RelativeLayout>

View File

@@ -10,7 +10,7 @@
<com.abbidot.tracker.widget.TypefaceTextView <com.abbidot.tracker.widget.TypefaceTextView
android:id="@+id/tv_subscribe_summary_item_name" android:id="@+id/tv_subscribe_summary_item_name"
style="@style/my_TextView_style_v2" style="@style/my_TextView_style_v2"
android:text="@string/txt_total_tax" android:text="@string/txt_total"
android:textSize="@dimen/textSize14" android:textSize="@dimen/textSize14"
app:typeface="@string/roboto_regular_font" /> app:typeface="@string/roboto_regular_font" />

View File

@@ -30,6 +30,15 @@
android:textSize="@dimen/textSize12" android:textSize="@dimen/textSize12"
app:typeface="@string/roboto_regular_font" /> app:typeface="@string/roboto_regular_font" />
<com.abbidot.tracker.widget.TypefaceTextView
android:id="@+id/tv_pet_location_update_time_format"
style="@style/my_TextView_style_v2"
android:layout_alignBaseline="@id/tv_pet_location_update_time"
android:gravity="start"
android:textColor="@color/orange_color5"
android:textSize="@dimen/textSize10"
app:typeface="@string/roboto_regular_font" />
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_pet_location_navigation_btn" android:id="@+id/iv_pet_location_navigation_btn"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@@ -967,8 +967,8 @@
<string name="txt_load_more_pull_text">Ziehen zum Laden weiterer Inhalte</string> <string name="txt_load_more_pull_text">Ziehen zum Laden weiterer Inhalte</string>
<string name="txt_load_more_release_text">Loslassen zum Laden</string> <string name="txt_load_more_release_text">Loslassen zum Laden</string>
<string name="txt_fully_charged">Voll aufgeladen</string> <string name="txt_fully_charged">Voll aufgeladen</string>
<string name="txt_fell_asleep">Vor %@ eingeschlafen</string> <string name="txt_fell_asleep">Vor %s eingeschlafen</string>
<string name="txt_move_wake_up">Bewegen Sie %@ zum Aufwecken</string> <string name="txt_move_wake_up">Bewegen Sie %s zum Aufwecken</string>
<string name="txt_time_line">Zeitleiste</string> <string name="txt_time_line">Zeitleiste</string>
<string name="txt_phone_close_device">Halten Sie das Telefon nah ans Gerät</string> <string name="txt_phone_close_device">Halten Sie das Telefon nah ans Gerät</string>
<string name="txt_auto_renew_cancel">Auto-Verlängerung: Kündigen</string> <string name="txt_auto_renew_cancel">Auto-Verlängerung: Kündigen</string>
@@ -979,5 +979,14 @@
<string name="txt_fence_saved">espeichert. Aktiv, wenn online.</string> <string name="txt_fence_saved">espeichert. Aktiv, wenn online.</string>
<string name="txt_renewal_years">Verlängerung: $%s / %s Jahre am %s</string> <string name="txt_renewal_years">Verlängerung: $%s / %s Jahre am %s</string>
<string name="txt_renewal_months">Verlängerung: $%s / %s Monate am %s</string> <string name="txt_renewal_months">Verlängerung: $%s / %s Monate am %s</string>
<string name ="txt_refund_expired">Die Rückerstattungsfrist ist abgelaufen</string>
<string name ="txt_refund_policy">Rückerstattungsrichtlinie\n</string>
<string name ="txt_automatic_refund">Automatische Rückerstattung (innerhalb von 48 Stunden)</string>
<string name ="txt_automatic_refund_dec">Alle Abonnementkäufe sind innerhalb von 48 Stunden nach Zahlung für eine vollständige automatische Rückerstattung berechtigt. Die Rückerstattungen werden automatisch ohne manuelle Prüfung bearbeitet.\n</string>
<string name ="txt_standard_refund">Standard-Rückerstattungszeitraum (30 Tage)</string>
<string name ="txt_standard_refund_dec">Nach der ersten 48-Stunden-Frist können Benutzer innerhalb von 30 Tagen nach dem Kauf eine Rückerstattung beantragen.\n\t1. Alle Abonnementpläne (3 Monate, 1 Jahr, 2 Jahre) sind berechtigt\n\t2. Rückerstattungsanträge unterliegen der Prüfung und Genehmigung\n\t3. Rückerstattungen können je nach Nutzung und Serviceverbrauch teilweise angepasst werden\n</string>
<string name ="txt_no_refund_dec">Abonnements, die älter als 30 Tage sind, können nicht erstattet werden.</string>
<string name ="txt_no_refund">Keine Rückerstattung nach 30 Tagen</string>
<string name ="txt_display_dashed_line">Gestrichelte Linie anzeigen</string>
</resources> </resources>

View File

@@ -1023,5 +1023,14 @@
<string name="txt_fence_saved">已保存,上线时生效。</string> <string name="txt_fence_saved">已保存,上线时生效。</string>
<string name="txt_renewal_years">续订:$%s / %s 年,于 %s</string> <string name="txt_renewal_years">续订:$%s / %s 年,于 %s</string>
<string name="txt_renewal_months">续订:$%s / %s 月,于 %s</string> <string name="txt_renewal_months">续订:$%s / %s 月,于 %s</string>
<string name="txt_refund_expired">退款期限已过</string>
<string name="txt_refund_policy">退款政策\n</string>
<string name="txt_automatic_refund">自动退款48小时内</string>
<string name="txt_automatic_refund_dec">所有订阅购买在付款后48小时内均可享受全额自动退款。退款将自动处理无需人工审核。\n</string>
<string name="txt_standard_refund">标准退款窗口30天</string>
<string name="txt_standard_refund_dec">在最初的48小时之后用户可在购买后30天内申请退款。\n\t1. 所有订阅计划3个月、1年、2年均符合条件\n\t2. 退款申请需经过审核和批准\n\t3. 退款可能会根据使用情况和服务消耗进行部分调整\n</string>
<string name="txt_no_refund_dec">超过30天的订阅不可退款。</string>
<string name="txt_no_refund">30天后不退款</string>
<string name="txt_display_dashed_line">显示虚线</string>
</resources> </resources>

View File

@@ -379,4 +379,5 @@
<color name="light_yellow_color">#F9FFE8</color> <color name="light_yellow_color">#F9FFE8</color>
<color name="grey_color_91">#B0B0B0</color> <color name="grey_color_91">#B0B0B0</color>
<color name="grey_color_92">#758E94</color> <color name="grey_color_92">#758E94</color>
<color name="orange_color5">#FF996E</color>
</resources> </resources>

View File

@@ -847,8 +847,8 @@
<string name="txt_reminder">Reminder</string> <string name="txt_reminder">Reminder</string>
<string name="txt_yesterday">Yesterday</string> <string name="txt_yesterday">Yesterday</string>
<string name="txt_power_on_off">Power On/Off</string> <string name="txt_power_on_off">Power On/Off</string>
<string name="txt_power_on_off_tip">Fully charge the tracker, then remove the cable. When the green light flashes, the tracker is powered on.</string> <string name="txt_power_on_off_tip">Charge and unplug to turn on Flashing green light = on</string>
<string name="txt_active_tracker_tip">Select and complete your subscription, then click to activate the tracker on the app. Once activated, the tracker can be used for GPS tracking and cellular network connectivity.</string> <string name="txt_active_tracker_tip">Choose a subscription Tap to activate the tracker Enable GPS and cellular tracking</string>
<string name="txt_active_tracker">Active Tracker</string> <string name="txt_active_tracker">Active Tracker</string>
<string name="txt_check_tracker_status_tip">(The GPS and cellular network conditions can vary depending on the environment. Before placing it on your pet, check various locations around you to evaluate the GPS and network status.)</string> <string name="txt_check_tracker_status_tip">(The GPS and cellular network conditions can vary depending on the environment. Before placing it on your pet, check various locations around you to evaluate the GPS and network status.)</string>
<string name="txt_check_tracker_status">Check Tracker Status</string> <string name="txt_check_tracker_status">Check Tracker Status</string>
@@ -859,11 +859,11 @@
<string name="txt_tracker_battery_tip5">(Shorter network intervals drain the Tracker\'s battery faster. By default, the network reconnects every 15 minutes.)</string> <string name="txt_tracker_battery_tip5">(Shorter network intervals drain the Tracker\'s battery faster. By default, the network reconnects every 15 minutes.)</string>
<string name="txt_tracker_battery_tip6">When Live mode is activated, the Tracker enters a rapid positioning and networking state, usually within 1520 seconds. This mode drains the battery the quickest, so it\'s best reserved for emergency situations.</string> <string name="txt_tracker_battery_tip6">When Live mode is activated, the Tracker enters a rapid positioning and networking state, usually within 1520 seconds. This mode drains the battery the quickest, so it\'s best reserved for emergency situations.</string>
<string name="txt_tracker_battery_life">Tracker Battery Life</string> <string name="txt_tracker_battery_life">Tracker Battery Life</string>
<string name="txt_create_fence_tip1">1.Fence Settings: Select "Pet" > "My Pet Fence". Click "Manage" > "+ Add new" to create or edit a fence for Safe Zone or No-go Zone.</string> <string name="txt_create_fence_tip1">Go to Pet > My Pet Fence > Manage > + Add New</string>
<string name="txt_create_fence_tip2">2.Define Boundary: Choose a location on the map, adjust the fence\'s radius or shape.</string> <string name="txt_create_fence_tip2">Choose location and adjust radius or shapeSave fence to activate it</string>
<string name="txt_create_fence_tip3">3.Save Settings: Save to activate the geofence.</string> <string name="txt_create_fence_tip3">Alerts when pet enters or leaves the zone</string>
<string name="txt_create_fence_tip4">4.Turn on Notifications: Go to \'Account\' > \'Settings\'. Click \'Notifications\' and turn on</string> <string name="txt_create_fence_tip4">4.Turn on Notifications: Go to \'Account\' > \'Settings\'. Click \'Notifications\' and turn on</string>
<string name="txt_create_pet_fence">Creating My Pet Fence</string> <string name="txt_create_pet_fence">Create a Pet Fence</string>
<string name="txt_tracker_sleeping_mode">Tracker in Sleeping Mode</string> <string name="txt_tracker_sleeping_mode">Tracker in Sleeping Mode</string>
<string name="txt_low_power">(Super Low power usage)</string> <string name="txt_low_power">(Super Low power usage)</string>
<string name="txt_in_wifi_zone">Tracker in WiFi Zone</string> <string name="txt_in_wifi_zone">Tracker in WiFi Zone</string>
@@ -1010,8 +1010,8 @@
<string name="txt_sure_delete_card">Sure to delete this card?</string> <string name="txt_sure_delete_card">Sure to delete this card?</string>
<string name="txt_account_exists_log_in">Account exists. Log in now?</string> <string name="txt_account_exists_log_in">Account exists. Log in now?</string>
<string name="txt_time_out_of_range">Selected date is out of range</string> <string name="txt_time_out_of_range">Selected date is out of range</string>
<string name="txt_power_on_off_install_tip">Shake to wake your tracker next time.</string> <string name="txt_power_on_off_install_tip">Shake to turn on Flashing green light confirms on</string>
<string name="txt_check_tracker_status_top_tip">Turn on the tracker, open the app, go to \'Pet\' > \'Tracker\' on the dashboard, then tap \'Network\', \'GPS\', \'Battery\', \'WiFi zone\', \'Bluetooth\', or \'Light\' to check connectivity, signal, or battery status.</string> <string name="txt_check_tracker_status_top_tip">Go to Pet > Tracker Check Network GPS Battery WiFi Zone Bluetooth LED GPS and cellular signals may vary by location Test in different locations before use</string>
<string name="txt_on_charging">Tracker is on charging</string> <string name="txt_on_charging">Tracker is on charging</string>
<string name="txt_active_subscribed">Subscribed</string> <string name="txt_active_subscribed">Subscribed</string>
<string name="txt_send">Send</string> <string name="txt_send">Send</string>
@@ -1090,5 +1090,20 @@
<string name="txt_standard_refund_dec">After the initial 48-hour period, users may request a refund within 30 days of purchase.\n\t1.All subscription plans (3-Month, 1-Year, 2-Year) are eligible\n\t2.Refund requests are subject to review and approval\n\t3.Refunds may be partially adjusted based on usage and service consumption\n</string> <string name="txt_standard_refund_dec">After the initial 48-hour period, users may request a refund within 30 days of purchase.\n\t1.All subscription plans (3-Month, 1-Year, 2-Year) are eligible\n\t2.Refund requests are subject to review and approval\n\t3.Refunds may be partially adjusted based on usage and service consumption\n</string>
<string name="txt_no_refund_dec">Subscriptions older than 30 days are non-refundable.</string> <string name="txt_no_refund_dec">Subscriptions older than 30 days are non-refundable.</string>
<string name="txt_no_refund">No Refund After 30 Days</string> <string name="txt_no_refund">No Refund After 30 Days</string>
<string name="txt_display_dashed_line">Display Dashed Line</string>
<string name="txt_first_use">First use</string>
<string name="txt_daily_use">Daily use</string>
<string name="txt_sleep_mode">Sleep Mode</string>
<string name="txt_sleep_mode_help">15 minutes no movement → sleep mode Auto wake on movement Battery updates every 24 hours</string>
<string name="txt_wifi_zone_home">WiFi ZoneHome)</string>
<string name="txt_wifi_zone_home_help">Connect to home WiFi GPS off → save battery Update every ~60 minutes</string>
<string name="txt_gps_update_help">Pet > Tracker > GPS Update Select 315 min Short interval = higher battery use Default: 5 min</string>
<string name="txt_set_fence_type">Set Fence type</string>
<string name="txt_fence_type_help">Safe Zone or No-go Zone</string>
<string name="txt_set_boundary">Set boundary</string>
<string name="txt_enable_set_notify">Enable alerts in Account > Settings > Notifications</string>
<string name="txt_edit_delete_fence">Edit or delete fence in Manage</string>
<string name="txt_total">Total</string>
<string name="txt_location_ago">(%s ago)</string>
</resources> </resources>

View File

@@ -37,6 +37,7 @@ import androidx.annotation.StringDef
MMKVKey.isGpsToGCJ02, MMKVKey.isGpsToGCJ02,
MMKVKey.MapType, MMKVKey.MapType,
MMKVKey.ShowFence, MMKVKey.ShowFence,
MMKVKey.ShowDashedLine,
MMKVKey.isCrash, MMKVKey.isCrash,
MMKVKey.AvailableOrder, MMKVKey.AvailableOrder,
MMKVKey.isFirstCheckBleOpen, MMKVKey.isFirstCheckBleOpen,
@@ -92,6 +93,7 @@ annotation class MMKVKey {
//map页是否显示围栏 //map页是否显示围栏
const val ShowFence = "isShowFence" const val ShowFence = "isShowFence"
const val ShowDashedLine = "isShowDashedLine"
//是首次打开APP //是首次打开APP
const val FirstOpen = "firstOpen" const val FirstOpen = "firstOpen"

View File

@@ -11,6 +11,7 @@ import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import java.util.TimeZone import java.util.TimeZone
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern import java.util.regex.Pattern
import kotlin.math.atan2 import kotlin.math.atan2
import kotlin.math.cos import kotlin.math.cos
@@ -217,6 +218,40 @@ class Utils {
return "${fill2Digits(hour)}:${fill2Digits(minutes)}:${fill2Digits(second)}" return "${fill2Digits(hour)}:${fill2Digits(minutes)}:${fill2Digits(second)}"
} }
/**
* 格式化2个时间相差多少
*/
fun getTimeDifference(startMillis: Long, endMillis: Long): String {
var diff = endMillis - startMillis
val days = TimeUnit.MILLISECONDS.toDays(diff)
diff -= TimeUnit.DAYS.toMillis(days)
val hours = TimeUnit.MILLISECONDS.toHours(diff)
diff -= TimeUnit.HOURS.toMillis(hours)
val minutes = TimeUnit.MILLISECONDS.toMinutes(diff)
var timeStr: String
if (days > 0) {
timeStr = if (days > 1) {
"$days days"
} else {
"$days day"
}
if (hours > 0) {
timeStr += " ${hours}h"
}
} else {
if (hours > 0) {
timeStr = "${hours}h"
if (minutes > 0) timeStr += " ${minutes}m"
} else {
timeStr = if (minutes > 0) "${minutes}m"
else "1m"
}
}
return timeStr
}
/** /**
* 把秒转换为 day hour min * 把秒转换为 day hour min
*/ */