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:
@@ -28,9 +28,9 @@ android {
|
||||
applicationId "com.abbidot.tracker"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 35
|
||||
versionCode 2203
|
||||
// versionName "2.2.3"
|
||||
versionName "2.2.3-Beta1"
|
||||
versionCode 2204
|
||||
// versionName "2.2.4"
|
||||
versionName "2.2.4-Beta1"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
||||
@@ -2,19 +2,50 @@
|
||||
<body>
|
||||
<div>
|
||||
|
||||
<h3>ABBIDOT Tracker Subscription Terms and Conditions
|
||||
</h3>
|
||||
<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.
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<p>For support contact:</p>
|
||||
<p>support@abbidot.com</p>
|
||||
|
||||
<h2>ABBIDOT Tracker Subscription Terms and Conditions</h2>
|
||||
<hr>
|
||||
<h3>1. Subscription Plans</h3>
|
||||
<p>ABBIDOT offers three subscription plans:</p>
|
||||
<ul>
|
||||
<li>3-Month Plan</li>
|
||||
<li>1-Year Plan</li>
|
||||
<li>2-Year Plan</li>
|
||||
</ul>
|
||||
<p>All subscriptions are automatically renewed at the end of each billing cycle unless canceled by the user.</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>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>
|
||||
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ package com.abbidot.tracker.dialog
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.CompoundButton
|
||||
import com.abbidot.baselibrary.constant.MMKVKey
|
||||
import com.abbidot.baselibrary.list.BaseRecyclerAdapter
|
||||
import com.abbidot.baselibrary.util.AppUtils
|
||||
import com.abbidot.baselibrary.util.MMKVUtil
|
||||
import com.abbidot.tracker.base.BaseDialog
|
||||
import com.abbidot.tracker.bean.DataBean
|
||||
import com.abbidot.tracker.databinding.DialogSelectMapTypeLayoutBinding
|
||||
@@ -18,12 +20,14 @@ import com.abbidot.tracker.util.ViewUtil
|
||||
class SelectMapTypeDialog(
|
||||
context: Context,
|
||||
adapter: BaseRecyclerAdapter<*>,
|
||||
checkedChangeListener: CompoundButton.OnCheckedChangeListener? = null
|
||||
fenceCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null,
|
||||
dashedCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null
|
||||
) : BaseDialog<DialogSelectMapTypeLayoutBinding>(
|
||||
DialogSelectMapTypeLayoutBinding::inflate, context
|
||||
) {
|
||||
private var mAdapter = adapter
|
||||
private val mCheckedChangeListener = checkedChangeListener
|
||||
private val mFenceCheckedChangeListener = fenceCheckedChangeListener
|
||||
private val mDashedCheckedChangeListener = dashedCheckedChangeListener
|
||||
|
||||
override fun initView() {
|
||||
mViewBinding.apply {
|
||||
@@ -31,7 +35,10 @@ class SelectMapTypeDialog(
|
||||
context, rvShowMapTypeList, mAdapter, right = AppUtils.dpToPx(58)
|
||||
)
|
||||
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) {
|
||||
mViewBinding.cbDialogMapFencesSwitch.isChecked = checked
|
||||
}
|
||||
|
||||
fun setDashedSwitch(checked: Boolean) {
|
||||
mViewBinding.cbDialogMapDashedLineSwitch.isChecked = checked
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import java.util.Calendar
|
||||
* @link
|
||||
* @description:显示日历弹窗
|
||||
* @param canSelectFutureDate 平时正常日期,true不能选择未来时间
|
||||
* @param minLastDayRange 最小天数能选最近多少天,0表示没有限制
|
||||
*/
|
||||
class ShowCalenderAndTimeDialog(
|
||||
context: Context,
|
||||
@@ -29,7 +30,8 @@ class ShowCalenderAndTimeDialog(
|
||||
format: String = Utils.DATE_FORMAT_PATTERN_EN1,
|
||||
canSelectFutureDate: Boolean = false,
|
||||
calenderShowTimestamp: Long = 0,
|
||||
minYear: Int = 2023
|
||||
minYear: Int = 2023,
|
||||
minLastDayRange: Int = 0
|
||||
) : BaseDialog<DialogCalenderAndTimeLayoutBinding>(
|
||||
DialogCalenderAndTimeLayoutBinding::inflate, context
|
||||
), OnValueChangeListener {
|
||||
@@ -44,7 +46,8 @@ class ShowCalenderAndTimeDialog(
|
||||
private val mOkListener = okListener
|
||||
|
||||
private val mMinYear = minYear
|
||||
private val mCalenderShowTimestamp = calenderShowTimestamp
|
||||
private var mCalenderShowTimestamp = calenderShowTimestamp
|
||||
private val mMinLastDayRange = minLastDayRange
|
||||
|
||||
override fun initView() {
|
||||
mMonths = context.resources.getStringArray(R.array.array_month)
|
||||
@@ -58,7 +61,23 @@ class ShowCalenderAndTimeDialog(
|
||||
val cYear = calendar.get(Calendar.YEAR)
|
||||
val month = calendar.get(Calendar.MONTH) + 1
|
||||
val day = calendar.get(Calendar.DAY_OF_MONTH)
|
||||
it.setRange(mMinYear, 1, 1, cYear, month, day)
|
||||
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)
|
||||
}
|
||||
}
|
||||
updateMonthYear()
|
||||
|
||||
@@ -104,8 +123,6 @@ class ShowCalenderAndTimeDialog(
|
||||
)
|
||||
}
|
||||
|
||||
//根据传入的时间戳进行还原显示
|
||||
setSelectDate(mCalenderShowTimestamp)
|
||||
|
||||
setOnClickListenerViews(
|
||||
llDialogCalenderLayout.ivSelectCalendarMonthLeft,
|
||||
@@ -117,6 +134,12 @@ class ShowCalenderAndTimeDialog(
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
//根据传入的时间戳进行还原显示
|
||||
setSelectDate(mCalenderShowTimestamp)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据传入的时间戳进行还原显示
|
||||
* @param showTimestamp 13位时间戳
|
||||
@@ -174,11 +197,11 @@ class ShowCalenderAndTimeDialog(
|
||||
val nowTimestamp = System.currentTimeMillis()
|
||||
|
||||
if (timesTamp > nowTimestamp) {
|
||||
//时间戳还原
|
||||
setSelectDate(nowTimestamp)
|
||||
mCalenderShowTimestamp = nowTimestamp
|
||||
mShowCalenderTextView.text = Utils.formatTime(nowTimestamp, mDateFormat)
|
||||
mOkListener?.onSelectClick(this@ShowCalenderAndTimeDialog, nowTimestamp)
|
||||
} else {
|
||||
mCalenderShowTimestamp = timesTamp
|
||||
mShowCalenderTextView.text = Utils.stringToDate(
|
||||
selectMonthYear, Utils.DATE_FORMAT_PATTERN_CN2, mDateFormat
|
||||
)
|
||||
|
||||
@@ -100,7 +100,7 @@ class ShowCalenderDialog(
|
||||
* 根据传入的时间戳进行还原显示
|
||||
* @param showTimestamp 13位时间戳
|
||||
*/
|
||||
fun setSelectDate(showTimestamp: Long) {
|
||||
private fun setSelectDate(showTimestamp: Long) {
|
||||
if (showTimestamp > 0) {
|
||||
val calendar = java.util.Calendar.getInstance().apply {
|
||||
timeInMillis = showTimestamp
|
||||
|
||||
@@ -324,7 +324,7 @@ class MoreActivityActivity :
|
||||
)
|
||||
}
|
||||
}
|
||||
}, calenderShowTimestamp = cTimestamp, minLastDayRange = 364)
|
||||
}, calenderShowTimestamp = cTimestamp, minLastDayRange = 29)
|
||||
calenderDialog.show()
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ class MoreSleepActivity :
|
||||
)
|
||||
}
|
||||
}
|
||||
}, calenderShowTimestamp = cTimestamp, minLastDayRange = 364)
|
||||
}, calenderShowTimestamp = cTimestamp, minLastDayRange = 29)
|
||||
calenderDialog.show()
|
||||
}
|
||||
|
||||
|
||||
@@ -25,24 +25,39 @@ class HelpCreatePetFenceActivity :
|
||||
ViewUtil.instance.addMenuBean(
|
||||
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(
|
||||
menuList, getString(R.string.txt_create_fence_tip2), menuType = MultipleEntity.IMG_IMG
|
||||
)
|
||||
ViewUtil.instance.addMenuBean(
|
||||
menuList, "", imageResId = R.drawable.create_fence_help2, menuType = MultipleEntity.IMG
|
||||
)
|
||||
ViewUtil.instance.addMenuBean(
|
||||
menuList, getString(R.string.txt_enable_set_notify)
|
||||
)
|
||||
ViewUtil.instance.addMenuBean(
|
||||
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(
|
||||
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)
|
||||
ViewUtil.instance.setRecyclerViewVerticalLinearLayout(
|
||||
|
||||
@@ -1,18 +1,53 @@
|
||||
package com.abbidot.tracker.ui.activity.help
|
||||
|
||||
import android.view.View
|
||||
import com.abbidot.tracker.R
|
||||
import com.abbidot.tracker.base.BaseActivity
|
||||
import com.abbidot.tracker.constant.ConstantInt
|
||||
import com.abbidot.tracker.constant.ConstantString
|
||||
import com.abbidot.tracker.databinding.ActivityHelpTrackerStatusBinding
|
||||
|
||||
class HelpTrackerStatusActivity :
|
||||
BaseActivity<ActivityHelpTrackerStatusBinding>(ActivityHelpTrackerStatusBinding::inflate) {
|
||||
|
||||
private var mType = ConstantInt.Type0
|
||||
|
||||
override fun getTopBar() = mViewBinding.ilHelpTrackerStatusBar.titleTopBar
|
||||
|
||||
override fun initData() {
|
||||
super.initData()
|
||||
setTopBarTitle(R.string.txt_check_tracker_status)
|
||||
setLeftBackImage(R.drawable.icon_white_back_svg)
|
||||
mViewBinding.ilHelpTrackerStatusTitle1.tvHelpTitleOne.setText(R.string.txt_check_tracker_status_top_tip)
|
||||
intent.extras?.apply {
|
||||
mType = getInt(ConstantString.Type, ConstantInt.Type0)
|
||||
}
|
||||
mViewBinding.apply {
|
||||
when (mType) {
|
||||
0 -> {
|
||||
setTopBarTitle(R.string.txt_check_tracker_status)
|
||||
setLeftBackImage(R.drawable.icon_white_back_svg)
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import com.abbidot.tracker.R
|
||||
import com.abbidot.tracker.adapter.HowWorkAdapter
|
||||
import com.abbidot.tracker.base.BaseActivity
|
||||
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.util.ViewUtil
|
||||
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_active_tracker))
|
||||
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))
|
||||
mHowWorkAdapter = HowWorkAdapter(this, menuList).apply {
|
||||
setOnItemClickListener(object : BaseRecyclerAdapter.OnItemClickListener {
|
||||
@@ -35,8 +40,26 @@ class HowWorkActivity : BaseActivity<ActivityHowWorkBinding>(ActivityHowWorkBind
|
||||
0 -> startActivity(Intent(mContext, HelpPowerOnOffActivity::class.java))
|
||||
1 -> startActivity(Intent(mContext, HelpActiveTrackerActivity::class.java))
|
||||
2 -> startActivity(Intent(mContext, HelpTrackerStatusActivity::class.java))
|
||||
3 -> startActivity(Intent(mContext, HelpTrackerBatteryActivity::class.java))
|
||||
4 -> startActivity(Intent(mContext, HelpCreatePetFenceActivity::class.java))
|
||||
3 -> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -91,6 +91,9 @@ class LiveActivityV3 : BaseActivity<ActivityLiveV3Binding>(ActivityLiveV3Binding
|
||||
//是否显示围栏
|
||||
private var isShowFence = true
|
||||
|
||||
//是否显示虚线
|
||||
private var isShowDashed = true
|
||||
|
||||
//地图类型,标准和卫星地图
|
||||
private var mMapType = ConstantInt.Type0
|
||||
private var mShowCenterLocation = ConstantInt.PetLocationType
|
||||
@@ -138,6 +141,7 @@ class LiveActivityV3 : BaseActivity<ActivityLiveV3Binding>(ActivityLiveV3Binding
|
||||
}
|
||||
|
||||
isShowFence = Util.getShowFenceSp()
|
||||
isShowDashed = MMKVUtil.getBoolean(MMKVKey.ShowDashedLine, true)
|
||||
|
||||
mViewBinding.apply {
|
||||
ViewUtil.instance.viewRotationAnimator(
|
||||
@@ -775,7 +779,8 @@ class LiveActivityV3 : BaseActivity<ActivityLiveV3Binding>(ActivityLiveV3Binding
|
||||
private fun showMapTypeDialog() {
|
||||
if (null == mSelectMapTypeDialog) {
|
||||
mSelectMapTypeDialog = ViewUtil.instance.getMapTypeDialog(
|
||||
mContext, object : BaseRecyclerAdapter.OnItemClickListener {
|
||||
mContext,
|
||||
object : BaseRecyclerAdapter.OnItemClickListener {
|
||||
override fun onItemClick(itemView: View?, pos: Int) {
|
||||
mMapType = Util.getMapTypeSp()
|
||||
if (pos == mMapType) {
|
||||
@@ -783,8 +788,8 @@ class LiveActivityV3 : BaseActivity<ActivityLiveV3Binding>(ActivityLiveV3Binding
|
||||
}
|
||||
mHomeMapCommon.switchSatelliteAndNormalMapType()
|
||||
}
|
||||
}) { v, isChecked ->
|
||||
if (v.id == R.id.cb_dialog_map_fences_switch) {
|
||||
},
|
||||
{ _, isChecked ->
|
||||
isShowFence = isChecked
|
||||
MMKVUtil.putBoolean(MMKVKey.ShowFence, isChecked)
|
||||
if (isChecked) {
|
||||
@@ -794,8 +799,16 @@ class LiveActivityV3 : BaseActivity<ActivityLiveV3Binding>(ActivityLiveV3Binding
|
||||
} else {
|
||||
mFencesMapViewModel.setFencesData(mContext, null, mFragment)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{ _, isChecked ->
|
||||
isShowDashed = isChecked
|
||||
MMKVUtil.putBoolean(MMKVKey.ShowDashedLine, isChecked)
|
||||
if (isChecked) {
|
||||
mHomeMapCommon.addUserAndPetLine()
|
||||
} else {
|
||||
mHomeMapCommon.removeUserAndPetLine()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
mSelectMapTypeDialog!!.mapTypeSpToUpdate()
|
||||
}
|
||||
@@ -990,6 +1003,9 @@ class LiveActivityV3 : BaseActivity<ActivityLiveV3Binding>(ActivityLiveV3Binding
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isShowDashed) {
|
||||
mHomeMapCommon.addUserAndPetLine()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ class SureSubscriptionPlanActivity :
|
||||
|
||||
//升级套餐还剩下多少差价
|
||||
private var mResidualMoney = 0.0
|
||||
|
||||
//设备类型
|
||||
private var mType = ConstantInt.Type1
|
||||
|
||||
@@ -253,7 +254,7 @@ class SureSubscriptionPlanActivity :
|
||||
ViewUtil.instance.addMenuBean(
|
||||
mSummaryAdapter.getData(),
|
||||
p.planName,
|
||||
"$price",
|
||||
Utils.formatDecimal(p.planPrice, 2),
|
||||
colorRedId = R.color.data_black_color
|
||||
)
|
||||
mTotalMoney += price
|
||||
@@ -289,12 +290,12 @@ class SureSubscriptionPlanActivity :
|
||||
isSwitch = true
|
||||
)
|
||||
}
|
||||
ViewUtil.instance.addMenuBean(
|
||||
mSummaryAdapter.getData(),
|
||||
getString(R.string.txt_sales_tax),
|
||||
"0",
|
||||
colorRedId = R.color.data_black_color
|
||||
)
|
||||
// ViewUtil.instance.addMenuBean(
|
||||
// mSummaryAdapter.getData(),
|
||||
// getString(R.string.txt_sales_tax),
|
||||
// "0",
|
||||
// colorRedId = R.color.data_black_color
|
||||
// )
|
||||
}
|
||||
|
||||
//判断套餐是否过期 或者套餐没退款
|
||||
@@ -417,9 +418,10 @@ class SureSubscriptionPlanActivity :
|
||||
private fun updateMoney() {
|
||||
mViewBinding.apply {
|
||||
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
|
||||
list[list.size - 1].menuValue = taxMoney.toString()
|
||||
// list[list.size - 1].menuValue = taxMoney.toString()
|
||||
mTotalWithTaxMoney = taxMoney + mTotalMoney
|
||||
mTotalWithTaxMoney = abs(mTotalWithTaxMoney)
|
||||
ilSubscribePlanSummary.ilSureSubscribePlanTotalLayout.tvSubscribeSummaryItemMoney.text =
|
||||
|
||||
@@ -10,7 +10,6 @@ import com.abbidot.tracker.base.BaseMapCommon
|
||||
import com.abbidot.tracker.bean.HistoryDataBean
|
||||
import com.abbidot.tracker.bean.MapDeviceBean
|
||||
import com.abbidot.tracker.constant.ConstantInt
|
||||
import com.abbidot.tracker.constant.LinkMapCallback
|
||||
import com.abbidot.tracker.databinding.LayoutPetLocationInfoBinding
|
||||
import com.abbidot.tracker.ui.fragment.map.baidumap.HomeMapBaiduMapFragment
|
||||
import com.abbidot.tracker.ui.fragment.map.googlemap.HomeMapGoogleMapFragmentV3
|
||||
@@ -199,6 +198,14 @@ class HomeMapCommonV3 @Inject constructor() : BaseMapCommon() {
|
||||
return mHomeMapGoogleMapFragment?.mUserLatLng
|
||||
}
|
||||
|
||||
fun addUserAndPetLine() {
|
||||
mHomeMapGoogleMapFragment?.addUserAndPetLine()
|
||||
}
|
||||
|
||||
fun removeUserAndPetLine() {
|
||||
mHomeMapGoogleMapFragment?.removeUserAndPetLine()
|
||||
}
|
||||
|
||||
// fun getAddressShowMarkerInfoWindow(historyDataBean: HistoryDataBean) {
|
||||
// if (null != mHomeMapBaiduMapFragment) {
|
||||
// mHomeMapBaiduMapFragment!!.showMarkerInfoWindow(historyDataBean)
|
||||
|
||||
@@ -643,7 +643,8 @@ class RouteV3Fragment : BaseFragment<FragmentRouteV3Binding>(FragmentRouteV3Bind
|
||||
}
|
||||
},
|
||||
calenderShowTimestamp = mFromTimestamp,
|
||||
format = Utils.DATE_FORMAT_PATTERN_EN13
|
||||
format = Utils.DATE_FORMAT_PATTERN_EN13,
|
||||
minLastDayRange = 29
|
||||
)
|
||||
}
|
||||
mFromCalenderDialog?.show()
|
||||
@@ -672,7 +673,8 @@ class RouteV3Fragment : BaseFragment<FragmentRouteV3Binding>(FragmentRouteV3Bind
|
||||
}
|
||||
},
|
||||
calenderShowTimestamp = mToTimestamp,
|
||||
format = Utils.DATE_FORMAT_PATTERN_EN13
|
||||
format = Utils.DATE_FORMAT_PATTERN_EN13,
|
||||
minLastDayRange = 29
|
||||
)
|
||||
}
|
||||
mToCalenderDialog?.show()
|
||||
|
||||
@@ -503,7 +503,7 @@ class HomeTrackFragment :
|
||||
ViewUtil.instance.addMenuBean(
|
||||
mTrackStateList,
|
||||
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
|
||||
)
|
||||
ViewUtil.instance.addMenuBean(
|
||||
@@ -669,7 +669,7 @@ class HomeTrackFragment :
|
||||
it.menuValue =
|
||||
if (isTimeoutReport || powerSwitch == ConstantInt.Type0 || powerSwitch == ConstantInt.Type2 || powerSwitch == ConstantInt.Type3 || inWifiZone == ConstantInt.Type1) {
|
||||
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.NoSignal) {
|
||||
it.colorRedId = R.color.orange_color3
|
||||
|
||||
@@ -9,6 +9,8 @@ import android.location.LocationManager
|
||||
import android.provider.Settings
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.CompoundButton
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
@@ -63,7 +65,8 @@ import javax.inject.Inject
|
||||
* create an instance of this fragment.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::inflate) {
|
||||
class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::inflate),
|
||||
OnCheckedChangeListener {
|
||||
|
||||
private val mFencesMapViewModel: FencesMapViewModel by viewModels()
|
||||
private val mMapViewModel: MapViewModel by viewModels()
|
||||
@@ -93,6 +96,9 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
|
||||
//是否显示围栏
|
||||
private var isShowFence = true
|
||||
|
||||
//是否显示虚线
|
||||
private var isShowDashed = true
|
||||
|
||||
//地图类型,标准和卫星地图
|
||||
private var mMapType = ConstantInt.Type0
|
||||
|
||||
@@ -120,6 +126,7 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
|
||||
}
|
||||
|
||||
isShowFence = Util.getShowFenceSp()
|
||||
isShowDashed = MMKVUtil.getBoolean(MMKVKey.ShowDashedLine, true)
|
||||
|
||||
mViewBinding.apply {
|
||||
getHomeV2Activity()?.edgeToEdgeAdapterBars(
|
||||
@@ -208,6 +215,7 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
|
||||
}
|
||||
|
||||
val showFence = Util.getShowFenceSp()
|
||||
val showDashed = MMKVUtil.getBoolean(MMKVKey.ShowDashedLine, true)
|
||||
//检测直播页面有没有修改围栏显示
|
||||
if (isShowFence != showFence) {
|
||||
if (null == mSelectMapTypeDialog) {
|
||||
@@ -216,6 +224,13 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
|
||||
mSelectMapTypeDialog?.setFencesSwitch(showFence)
|
||||
}
|
||||
}
|
||||
if (isShowDashed != showDashed) {
|
||||
if (null == mSelectMapTypeDialog) {
|
||||
setDashedShow(showDashed)
|
||||
} else {
|
||||
mSelectMapTypeDialog?.setDashedSwitch(showDashed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getHomeV2Activity(): HomeV2Activity? {
|
||||
@@ -548,11 +563,8 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
|
||||
}
|
||||
mHomeMapCommon.switchSatelliteAndNormalMapType()
|
||||
}
|
||||
}) { v, isChecked ->
|
||||
if (v.id == R.id.cb_dialog_map_fences_switch) {
|
||||
setFencesShow(isChecked)
|
||||
}
|
||||
}
|
||||
}, this, this
|
||||
)
|
||||
else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
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?) {
|
||||
mViewBinding.apply {
|
||||
@@ -1008,5 +1042,4 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -406,14 +406,15 @@ abstract class BaseGoogleMapFragment :
|
||||
if (MMKVUtil.getBoolean(MMKVKey.isGpsToGCJ02)) {
|
||||
mUserLatLng?.let {
|
||||
if (null == mUserMarker) {
|
||||
mUserMarker = addImageMarker(it, R.drawable.icon_user_location_image)
|
||||
mUserMarker = addImageMarker(it, R.drawable.icon_user_location_image,false)
|
||||
} else {
|
||||
if (it.latitude == mUserMarker!!.position.latitude && it.longitude == mUserMarker!!.position.longitude) {
|
||||
} else {
|
||||
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 {
|
||||
@@ -791,7 +792,7 @@ abstract class BaseGoogleMapFragment :
|
||||
/**
|
||||
* 获取地图画线的PolylineOptions
|
||||
*/
|
||||
private fun getPolylineOptions(widthDp: Float, lineColorRes: Int): PolylineOptions {
|
||||
fun getPolylineOptions(widthDp: Float, lineColorRes: Int): PolylineOptions {
|
||||
return PolylineOptions().clickable(false).width(AppUtils.dpToPx(widthDp))
|
||||
.color(ContextCompat.getColor(mContext!!, lineColorRes)).geodesic(false)
|
||||
}
|
||||
|
||||
@@ -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.Marker
|
||||
import com.google.android.gms.maps.model.Polyline
|
||||
import com.google.android.gms.maps.model.PolylineOptions
|
||||
import kotlin.math.pow
|
||||
|
||||
/**
|
||||
@@ -47,7 +46,7 @@ class HomeMapGoogleMapFragmentV3 : BaseGoogleMapFragment() {
|
||||
|
||||
//启动动画移动地图摄像机
|
||||
private var isMoveCamera = true
|
||||
private var mPolyline: Polyline? = null
|
||||
private var mUserAndPetLine: Polyline? = null
|
||||
private var mRippleCircle: Circle? = null
|
||||
private var mValueAnimator: ValueAnimator? = null
|
||||
|
||||
@@ -111,6 +110,19 @@ class HomeMapGoogleMapFragmentV3 : BaseGoogleMapFragment() {
|
||||
mPetLocationLayoutBinding.let { layout ->
|
||||
layout.tvPetLocationReverseGeocode.text = address
|
||||
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) {
|
||||
mUserLatLng?.apply {
|
||||
mGoogleMap?.let {
|
||||
if (null == mPolyline) {
|
||||
val polylineOptions =
|
||||
PolylineOptions().clickable(false).width(AppUtils.dpToPx(1.5f))
|
||||
.color(ContextCompat.getColor(mContext!!, R.color.blue_color9))
|
||||
.geodesic(false)
|
||||
mPolyline = it.addPolyline(polylineOptions)
|
||||
mPolyline?.pattern = getDashedPatternStyle(18f)
|
||||
}
|
||||
mPolyline?.let { pLine ->
|
||||
val latList = mutableListOf<LatLng>()
|
||||
latList.add(petLatLng)
|
||||
latList.add(this)
|
||||
pLine.points = latList
|
||||
fun addUserAndPetLine() {
|
||||
mGoogleMap?.apply {
|
||||
mUserLatLng?.let { u ->
|
||||
mPetLatLng?.let { p ->
|
||||
mUserAndPetLine?.remove()
|
||||
getPolylineOptions(1.5f, R.color.blue_color9).let {
|
||||
it.add(toGCJ02LatLon(p))
|
||||
it.add(toGCJ02LatLon(u))
|
||||
mUserAndPetLine = addPolyline(it)
|
||||
}
|
||||
mUserAndPetLine?.pattern = getDashedPatternStyle(18f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun removeUserAndPetLine() {
|
||||
mUserAndPetLine?.remove()
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化并添加水波纹圆
|
||||
*/
|
||||
|
||||
@@ -878,7 +878,8 @@ class ViewUtil private constructor() {
|
||||
fun getMapTypeDialog(
|
||||
context: Context,
|
||||
onItemClickListener: BaseRecyclerAdapter.OnItemClickListener? = null,
|
||||
checkedChangeListener: CompoundButton.OnCheckedChangeListener? = null
|
||||
fenceCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null,
|
||||
dashedCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null
|
||||
): SelectMapTypeDialog {
|
||||
val mapType = Util.getMapTypeSp()
|
||||
val typeList = mutableListOf<DataBean>()
|
||||
@@ -902,7 +903,9 @@ class ViewUtil private constructor() {
|
||||
}
|
||||
})
|
||||
}
|
||||
return SelectMapTypeDialog(context, mapTypeAdapter, checkedChangeListener)
|
||||
return SelectMapTypeDialog(
|
||||
context, mapTypeAdapter, fenceCheckedChangeListener, dashedCheckedChangeListener
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,7 +35,6 @@ import com.abbidot.tracker.widget.TypefaceButton
|
||||
import com.abbidot.tracker.widget.TypefaceTextView
|
||||
import com.clj.fastble.BleManager
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class MapViewModel : ViewModel() {
|
||||
|
||||
@@ -114,7 +113,7 @@ class MapViewModel : ViewModel() {
|
||||
menuType = ConstantInt.Close
|
||||
name = context.getString(R.string.tracker_manage_set_gps)
|
||||
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)
|
||||
}
|
||||
DataBean().apply {
|
||||
@@ -302,7 +301,7 @@ class MapViewModel : ViewModel() {
|
||||
deviceStateList[1].apply {
|
||||
menuType = ConstantInt.Close
|
||||
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 {
|
||||
menuType = ConstantInt.Close
|
||||
@@ -344,13 +343,12 @@ class MapViewModel : ViewModel() {
|
||||
val gpsValue =
|
||||
if (isTimeoutReport || it.powerSwitch == ConstantInt.Type0 || it.powerSwitch == ConstantInt.Type2 || it.powerSwitch == ConstantInt.Type3 || it.inWifiZone == ConstantInt.Type1) {
|
||||
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.NoSignal) {
|
||||
menuType = ConstantInt.Close
|
||||
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"
|
||||
}
|
||||
deviceStateList[2].apply {
|
||||
@@ -476,7 +474,7 @@ class MapViewModel : ViewModel() {
|
||||
)
|
||||
it.text = String.format(
|
||||
context.getString(R.string.txt_fell_asleep),
|
||||
getTimeDifference(updateTime * 1000, System.currentTimeMillis())
|
||||
Utils.getTimeDifference(updateTime * 1000, System.currentTimeMillis())
|
||||
)
|
||||
ViewUtil.instance.viewShow(closeBtn)
|
||||
} 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(
|
||||
context: Context,
|
||||
mapDeviceBean: MapDeviceBean,
|
||||
|
||||
@@ -159,7 +159,8 @@ public class HorizontalCalenderViewV2 extends FrameLayout {
|
||||
//获取当月的日期
|
||||
// List<DateItem> items = getItems();
|
||||
//获取最近365天的日期
|
||||
List<DateItem> items = getLast365DaysItems();
|
||||
// List<DateItem> items = getLast365DaysItems();
|
||||
List<DateItem> items = getLast30DaysItems();
|
||||
adapter = new DayV2Adapter(context, items, dayTextColorSelected, dayTextColorNormal,
|
||||
daySelectionColor, weekTextColor, pressShapeSelectorId, todayPointColor);
|
||||
adapter.setItemClick((year, month, day, week) -> {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?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"
|
||||
@@ -18,13 +19,22 @@
|
||||
android:layout_marginVertical="@dimen/dp_18"
|
||||
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
|
||||
android:id="@+id/il_help_power_on_off_title"
|
||||
layout="@layout/layout_help_title1"
|
||||
android:layout_width="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
|
||||
@@ -38,13 +48,24 @@
|
||||
android:paddingBottom="@dimen/dp_12"
|
||||
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
|
||||
android:id="@+id/il_help_shake_title"
|
||||
layout="@layout/layout_help_title1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
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
|
||||
|
||||
@@ -32,9 +32,11 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
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
|
||||
android:id="@+id/iv_help_tracker_status_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
|
||||
@@ -41,8 +41,9 @@
|
||||
android:checked="true" />
|
||||
</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_height="wrap_content"
|
||||
android:layout_below="@id/ll_map_type_display_fences_switch"
|
||||
@@ -50,7 +51,6 @@
|
||||
android:background="@drawable/shape8_gray_border_transparent_bg"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/dp_47"
|
||||
android:visibility="gone"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="@dimen/dp_16">
|
||||
|
||||
@@ -58,12 +58,14 @@
|
||||
style="@style/my_TextView_style_v2"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start"
|
||||
android:text="@string/txt_show_accuracy"
|
||||
android:text="@string/txt_display_dashed_line"
|
||||
android:textSize="@dimen/textSize14"
|
||||
app:typeface="@string/roboto_bold_font" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatCheckBox
|
||||
android:id="@+id/cb_dialog_map_dashed_line_switch"
|
||||
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>
|
||||
</RelativeLayout>
|
||||
@@ -10,7 +10,7 @@
|
||||
<com.abbidot.tracker.widget.TypefaceTextView
|
||||
android:id="@+id/tv_subscribe_summary_item_name"
|
||||
style="@style/my_TextView_style_v2"
|
||||
android:text="@string/txt_total_tax"
|
||||
android:text="@string/txt_total"
|
||||
android:textSize="@dimen/textSize14"
|
||||
app:typeface="@string/roboto_regular_font" />
|
||||
|
||||
|
||||
@@ -30,6 +30,15 @@
|
||||
android:textSize="@dimen/textSize12"
|
||||
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
|
||||
android:id="@+id/iv_pet_location_navigation_btn"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -967,8 +967,8 @@
|
||||
<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_fully_charged">Voll aufgeladen</string>
|
||||
<string name="txt_fell_asleep">Vor %@ eingeschlafen</string>
|
||||
<string name="txt_move_wake_up">Bewegen Sie %@ zum Aufwecken</string>
|
||||
<string name="txt_fell_asleep">Vor %s eingeschlafen</string>
|
||||
<string name="txt_move_wake_up">Bewegen Sie %s zum Aufwecken</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_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_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_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>
|
||||
@@ -1023,5 +1023,14 @@
|
||||
<string name="txt_fence_saved">已保存,上线时生效。</string>
|
||||
<string name="txt_renewal_years">续订:$%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>
|
||||
@@ -379,4 +379,5 @@
|
||||
<color name="light_yellow_color">#F9FFE8</color>
|
||||
<color name="grey_color_91">#B0B0B0</color>
|
||||
<color name="grey_color_92">#758E94</color>
|
||||
<color name="orange_color5">#FF996E</color>
|
||||
</resources>
|
||||
@@ -847,8 +847,8 @@
|
||||
<string name="txt_reminder">Reminder</string>
|
||||
<string name="txt_yesterday">Yesterday</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_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_power_on_off_tip">Charge and unplug to turn on Flashing green light = on</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_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>
|
||||
@@ -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_tip6">When Live mode is activated, the Tracker enters a rapid positioning and networking state, usually within 15–20 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_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_tip2">2.Define Boundary: Choose a location on the map, adjust the fence\'s radius or shape.</string>
|
||||
<string name="txt_create_fence_tip3">3.Save Settings: Save to activate the geofence.</string>
|
||||
<string name="txt_create_fence_tip1">Go to Pet > My Pet Fence > Manage > + Add New</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">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_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_low_power">(Super Low power usage)</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_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_power_on_off_install_tip">Shake to wake your tracker next time.</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_power_on_off_install_tip">Shake to turn on Flashing green light confirms on</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_active_subscribed">Subscribed</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_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_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 Zone(Home)</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 3–15 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>
|
||||
@@ -37,6 +37,7 @@ import androidx.annotation.StringDef
|
||||
MMKVKey.isGpsToGCJ02,
|
||||
MMKVKey.MapType,
|
||||
MMKVKey.ShowFence,
|
||||
MMKVKey.ShowDashedLine,
|
||||
MMKVKey.isCrash,
|
||||
MMKVKey.AvailableOrder,
|
||||
MMKVKey.isFirstCheckBleOpen,
|
||||
@@ -92,6 +93,7 @@ annotation class MMKVKey {
|
||||
|
||||
//map页是否显示围栏
|
||||
const val ShowFence = "isShowFence"
|
||||
const val ShowDashedLine = "isShowDashedLine"
|
||||
|
||||
//是首次打开APP
|
||||
const val FirstOpen = "firstOpen"
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.math.atan2
|
||||
import kotlin.math.cos
|
||||
@@ -217,6 +218,40 @@ class Utils {
|
||||
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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user