map和直播页面改版

This commit is contained in:
yezhiqiu
2025-11-27 18:22:51 +08:00
parent 11b6ba16bd
commit 314508e924
27 changed files with 2057 additions and 214 deletions

View File

@@ -30,7 +30,7 @@ android {
targetSdkVersion 35
versionCode 2101
// versionName "2.1.1"
versionName "2.1.1-Beta2"
versionName "2.1.1-Beta4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -391,6 +391,10 @@
android:name=".ui.activity.map.LiveActivityV2"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".ui.activity.map.LiveActivityV3"
android:exported="false"
android:screenOrientation="portrait" />
<activity
android:name=".ui.activity.data.MoreSleepActivity"
android:exported="false"

View File

@@ -34,7 +34,10 @@ data class MapDeviceBean(
var fences: MutableList<FencesBean>?,
var wifiZones: MutableList<WiFiZoneBean>?,
var startTime: String,
var endTime: String
var endTime: String,
var canShowBattery: Boolean,
var isCloseBattery: Boolean,
var isCloseMsg: Boolean
) : Parcelable {
constructor() : this(
"",
@@ -65,6 +68,9 @@ data class MapDeviceBean(
null,
null,
"",
""
"",
false,
false,
false
)
}

View File

@@ -102,6 +102,7 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
private val mBleReportManage: BleReportManage by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
mSocketUtilManage = SocketUtilManage()
mSocketUtilManage?.initEasySocket(mContext)
LogUtil.e("创建Socket连接")
BleReportManage(mSocketSendMessageViewModel, mSocketUtilManage!!)
}
@@ -222,8 +223,13 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
XEventBus.observe(this, EventName.ConnectDeviceState) { ble: BleTrackDeviceBean ->
getPet(false)?.apply {
//蓝牙连接断开上传日志
if (ble.mac == macID && ble.conState == ConState.DISCONNECTED) {
mLogBleReportViewModel.uploadLog(mContext, macID)
if (ble.mac == macID) {
if (ble.conState == ConState.CONNECTED) {
//蓝牙连接就去连接socket
mBleReportManage.dealBleReportData(macID, null)
} else {
mLogBleReportViewModel.uploadLog(mContext, macID)
}
}
}
}
@@ -338,7 +344,6 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
getPet(false)?.apply {
mLogBleReportViewModel.uploadLog(mContext, macID)
}
(mFragments[2] as MapV3Fragment).showPetNameAndHead(mSelectPetPosition)
} else {
onChangeClick(mSelectPetPosition)
when (mViewBinding.homeV2ViewPager2.currentItem) {
@@ -364,6 +369,7 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
}
}
}
(mFragments[2] as MapV3Fragment).showPetNameAndHead(mSelectPetPosition)
}
}
@@ -406,7 +412,7 @@ class HomeV2Activity : BaseActivity<ActivityHomeV2Binding>(ActivityHomeV2Binding
* 选择宠物弹窗
*/
fun selectPetDialog() {
if (isRequestPetData && mPetList.size == 0) {
if (mPetList.size == 0) {
showToast(R.string.no_bind_pet)
return
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,199 @@
package com.abbidot.tracker.ui.common.map
import android.content.Context
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.abbidot.baselibrary.constant.MMKVKey
import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.baselibrary.util.MMKVUtil
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.databinding.LayoutPetLocationInfoBinding
import com.abbidot.tracker.ui.fragment.map.baidumap.HomeMapBaiduMapFragment
import com.abbidot.tracker.ui.fragment.map.googlemap.HomeMapGoogleMapFragmentV3
import com.google.android.gms.maps.model.LatLng
import javax.inject.Inject
/**
*Created by .yzq on 2022/7/5/005.
* @link
* @description:
*/
class HomeMapCommonV3 @Inject constructor() : BaseMapCommon() {
private var mHomeMapGoogleMapFragment: HomeMapGoogleMapFragmentV3? = null
private var mHomeMapBaiduMapFragment: HomeMapBaiduMapFragment? = null
fun getMapFragment(
context: Context,
locationLayoutViewBinding: LayoutPetLocationInfoBinding,
deviceBatteryLayout: ViewGroup,
petAddressTimeFormat: String,
mapLoadOk: () -> Unit
): Fragment {
return if (AppUtils.isChina(AppUtils.SWITCH_MAP_TYPE)) {
mHomeMapBaiduMapFragment = HomeMapBaiduMapFragment.newInstance(context, mapLoadOk)
mHomeMapBaiduMapFragment!!
} else {
mHomeMapGoogleMapFragment = HomeMapGoogleMapFragmentV3.newInstance(
context,
locationLayoutViewBinding,
deviceBatteryLayout,
petAddressTimeFormat,
mapLoadOk
)
mHomeMapGoogleMapFragment!!
}
}
fun setMapDeviceBean(mapDeviceBean: MapDeviceBean?) {
if (null != mHomeMapBaiduMapFragment) {
mHomeMapBaiduMapFragment!!.setMapDeviceBean(mapDeviceBean)
} else if (null != mHomeMapGoogleMapFragment) {
mHomeMapGoogleMapFragment!!.setMapDeviceBean(mapDeviceBean)
}
}
/**
* 开始每隔几秒刷新用户位置
*/
fun startRefreshUserLocation() {
if (isMapLoadOk()) startRefreshUserLocation(
mHomeMapBaiduMapFragment, mHomeMapGoogleMapFragment
)
}
/**
* 获取宠物反编译好的位置信息
*/
fun getDecPetAddressData(): HistoryDataBean? {
if (null != mHomeMapBaiduMapFragment) {
return mHomeMapBaiduMapFragment!!.mDecPetAddressData
} else if (null != mHomeMapGoogleMapFragment) {
return mHomeMapGoogleMapFragment!!.mDecPetAddressData
}
return null
}
fun clearMarker() {
if (null != mHomeMapBaiduMapFragment) {
mHomeMapBaiduMapFragment!!.mBaiduMap?.clear()
} else if (null != mHomeMapGoogleMapFragment) {
mHomeMapGoogleMapFragment!!.clearAllMarker()
}
}
fun refreshPetCurrentLocation(latitude: Double, longitude: Double, isMoveCamera: Boolean) {
if (null != mHomeMapBaiduMapFragment) {
mHomeMapBaiduMapFragment?.apply {
refreshPetCurrentLocation(
latitude, longitude, isMoveCamera
)
}
} else if (null != mHomeMapGoogleMapFragment) {
MMKVUtil.putDouble(MMKVKey.MapShowDefaultLat, latitude)
MMKVUtil.putDouble(MMKVKey.MapShowDefaultLon, longitude)
mHomeMapGoogleMapFragment?.apply {
refreshPetCurrentLocation(
LatLng(latitude, longitude), needMoveCamera = isMoveCamera
)
}
}
}
/**
* 重新设置宠物头像
*/
fun setPetHeadIcon(imageUrl: String, petType: Int) {
if (null != mHomeMapBaiduMapFragment) {
mHomeMapBaiduMapFragment!!.setPetHeadIconUrl(imageUrl)
} else if (null != mHomeMapGoogleMapFragment) {
mHomeMapGoogleMapFragment!!.setPetHeadIconUrl(imageUrl, petType)
}
}
/**
* 地图是否加载好了,准备好了
*/
fun isMapLoadOk() = isMapLoadOk(mHomeMapBaiduMapFragment, mHomeMapGoogleMapFragment)
/**
* 切换地图类型
*/
fun switchSatelliteAndNormalMapType() {
switchSatelliteAndNormalMapType(mHomeMapBaiduMapFragment, mHomeMapGoogleMapFragment)
}
/**
* 切换用户和宠物的位置居中显示
*/
fun switchShowLocation(@ConstantInt type: Int) {
switchShowLocationType(type, mHomeMapBaiduMapFragment, mHomeMapGoogleMapFragment)
}
/**
* 画轨迹线
*/
fun addTrackLine(latitude: Double, longitude: Double) {
if (null != mHomeMapBaiduMapFragment) {
mHomeMapBaiduMapFragment!!.addLine(latitude, longitude)
} else if (null != mHomeMapGoogleMapFragment) {
mHomeMapGoogleMapFragment!!.addLine(LatLng(latitude, longitude))
}
}
/**
* 画轨迹线
*/
fun addTrackLines(trackList: MutableList<HistoryDataBean>) {
if (null != mHomeMapBaiduMapFragment) {
} else if (null != mHomeMapGoogleMapFragment) {
mHomeMapGoogleMapFragment!!.addLines(trackList)
}
}
/**
* 计算用户和宠物的距离
*/
fun getUserAndPetDistance(): Double {
var distance = 0.0
if (null != mHomeMapBaiduMapFragment) {
distance = mHomeMapBaiduMapFragment!!.getUserAndPetDistance()
} else if (null != mHomeMapGoogleMapFragment) {
distance = mHomeMapGoogleMapFragment!!.getUserAndPetDistance()
}
return distance
}
/**
* 开始水波纹动画
*/
fun startRippleCircleAnim() {
if (null != mHomeMapBaiduMapFragment) {
} else if (null != mHomeMapGoogleMapFragment) {
mHomeMapGoogleMapFragment!!.startRippleCircleAnim()
}
}
fun greenRippleCircleAnim() {
mHomeMapGoogleMapFragment?.greenRippleCircleAnim()
}
fun setMarkerInfoViewOffset() {
if (null != mHomeMapBaiduMapFragment) {
} else if (null != mHomeMapGoogleMapFragment) {
mHomeMapGoogleMapFragment!!.setMarkerInfoViewOffset()
}
}
// fun getAddressShowMarkerInfoWindow(historyDataBean: HistoryDataBean) {
// if (null != mHomeMapBaiduMapFragment) {
// mHomeMapBaiduMapFragment!!.showMarkerInfoWindow(historyDataBean)
// } else if (null != mHomeMapGoogleMapFragment) {
// mHomeMapGoogleMapFragment!!.showMarkerInfoWindow(historyDataBean)
// }
// }
}

View File

@@ -18,8 +18,8 @@ import com.abbidot.baselibrary.list.BaseRecyclerAdapter
import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.baselibrary.util.MMKVUtil
import com.abbidot.baselibrary.util.Utils
import com.abbidot.tracker.R
import com.abbidot.tracker.adapter.HomeMapDeviceMsgAdapter
import com.abbidot.tracker.adapter.HomeMapDeviceStateAdapter
import com.abbidot.tracker.base.BaseDialog
import com.abbidot.tracker.base.BaseFragment
@@ -37,15 +37,14 @@ import com.abbidot.tracker.dialog.CommonDialog1
import com.abbidot.tracker.dialog.SelectMapTypeDialog
import com.abbidot.tracker.ui.activity.HomeV2Activity
import com.abbidot.tracker.ui.activity.device.MyTrackerV2Activity
import com.abbidot.tracker.ui.activity.map.LiveActivityV2
import com.abbidot.tracker.ui.common.map.HomeMapCommon
import com.abbidot.tracker.ui.activity.map.LiveActivityV3
import com.abbidot.tracker.ui.common.map.HomeMapCommonV3
import com.abbidot.tracker.util.Util
import com.abbidot.tracker.util.ViewUtil
import com.abbidot.tracker.util.bluetooth.SRBleUtil
import com.abbidot.tracker.vm.FamilyViewModel
import com.abbidot.tracker.vm.FencesMapViewModel
import com.abbidot.tracker.vm.MapViewModel
import com.abbidot.tracker.widget.MapDeviceNetView
import com.clj.fastble.BleManager
import com.hjq.permissions.XXPermissions
import com.hjq.permissions.permission.PermissionLists
@@ -74,14 +73,14 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
private var mCurrentShowPetPos = -1
@Inject
lateinit var mHomeMapCommon: HomeMapCommon
lateinit var mHomeMapCommon: HomeMapCommonV3
private lateinit var mFragment: Fragment
private var mMapDeviceBean: MapDeviceBean? = null
private lateinit var mDeviceStateList: MutableList<DataBean>
private lateinit var mDeviceStateAdapter: HomeMapDeviceStateAdapter
private lateinit var mDeviceMsgList: MutableList<DataBean>
private lateinit var mDeviceMsgAdapter: HomeMapDeviceMsgAdapter
// private lateinit var mDeviceMsgList: MutableList<DataBean>
// private lateinit var mDeviceMsgAdapter: HomeMapDeviceMsgAdapter
//启动移动地图摄像机
private var isMoveCamera = true
@@ -113,7 +112,10 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
rlHomeMapTopLayout, WindowInsetsCompat.Type.statusBars()
)
mFragment = mHomeMapCommon.getMapFragment(
mContext!!, miHomeMapAddressView, MapDeviceNetView(mContext!!)
mContext!!,
ilHomeMapPetLocation,
llHomeMapDeviceBatteryLayout,
Utils.DATE_FORMAT_PATTERN_EN11
) { mapLoadOk() }
llHomeMapTopPet.ivTopPetBtnSmall.setImageResource(R.drawable.icon_map_type)
@@ -123,17 +125,16 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
)
mDeviceStateList = mutableListOf()
mDeviceMsgList = mutableListOf()
mMapViewModel.addDeviceDefaultStateData(mContext!!, mDeviceStateList)
mDeviceStateAdapter = HomeMapDeviceStateAdapter(mContext!!, mDeviceStateList)
ViewUtil.instance.setRecyclerViewVerticalLinearLayout(
mContext!!, rvHomeMapDeviceState, mDeviceStateAdapter, bottom = 10
)
mDeviceMsgAdapter = HomeMapDeviceMsgAdapter(mContext!!, mDeviceMsgList)
ViewUtil.instance.setRecyclerViewVerticalLinearLayout(
mContext!!, rvHomeMapDeviceMsg, mDeviceMsgAdapter, bottom = 10
)
// mDeviceMsgAdapter = HomeMapDeviceMsgAdapter(mContext!!, mDeviceMsgList)
// ViewUtil.instance.setRecyclerViewVerticalLinearLayout(
// mContext!!, rvHomeMapDeviceMsg, mDeviceMsgAdapter, bottom = 10
// )
setOnClickListenerViews(
homeMapRefreshBtn,
@@ -141,7 +142,9 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
homeMapLiveBtn,
llHomeMapTopPet.ivTopPetBtnSmall,
llHomeMapTopPet.homeDataPetNameSmall,
llHomeMapTopPet.homeDataPetHeadSmall.root
llHomeMapTopPet.homeDataPetHeadSmall.root,
ilHomeMapDeviceBatteryLayout.ivDeviceCloseBtn,
ilHomeMapDeviceMsg.ivDeviceMsgCloseBtn
)
if (AppUtils.isDebug()) {
@@ -230,17 +233,22 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
override fun onResult(any: Any) {
val data = it.getOrNull()
data?.apply {
mMapDeviceBean?.let { m ->
data.isCloseMsg = m.isCloseMsg
data.isCloseBattery = m.isCloseBattery
data.canShowBattery = m.canShowBattery
}
mMapDeviceBean = data
setMapData(data)
mMapViewModel.setDeviceStateAndWarningData(
mContext!!,
getHomeV2Activity()?.getPet(),
data,
mViewBinding.ilHomeMapDeviceMsg.root,
mViewBinding.ilHomeMapDeviceMsg.tvDeviceMsgContent,
mViewBinding.ilHomeMapDeviceMsg.ivDeviceMsgCloseBtn,
mDeviceStateList,
mDeviceStateAdapter,
mDeviceMsgList,
mDeviceMsgAdapter,
mViewBinding.rvHomeMapDeviceMsg
mDeviceStateAdapter
)
}
}
@@ -288,11 +296,26 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
//接收蓝牙连接状态
XEventBus.observe(this, EventName.ConnectDeviceState) { trackBle: BleTrackDeviceBean ->
getHomeV2Activity()?.getPet(false)?.apply {
//蓝牙断开就重新获取服务器数据,蓝牙数据上报断开
if (trackBle.mac == macID && trackBle.conState != ConState.CONNECTED) {
//隐藏蓝牙nearby
mViewBinding.rvHomeMapDeviceMsg.visibility = View.GONE
updateMapDeviceStatus()
if (trackBle.mac == macID) {
if (trackBle.conState == ConState.CONNECTED) {
mMapDeviceBean?.let {
mMapViewModel.setDeviceStateAndWarningData(
mContext!!,
getHomeV2Activity()?.getPet(),
it,
mViewBinding.ilHomeMapDeviceMsg.root,
mViewBinding.ilHomeMapDeviceMsg.tvDeviceMsgContent,
mViewBinding.ilHomeMapDeviceMsg.ivDeviceMsgCloseBtn,
mDeviceStateList,
mDeviceStateAdapter
)
}
} else {
//隐藏蓝牙nearby
mViewBinding.ilHomeMapDeviceMsg.root.visibility = View.GONE
//蓝牙断开就重新获取服务器数据,蓝牙数据上报断开
updateMapDeviceStatus()
}
}
}
}
@@ -314,26 +337,24 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
it.longitude = location.longitude
it.latitude = location.latitude
}
mHomeMapCommon.setMapDeviceBean(mMapDeviceBean)
setMapDeviceBean(it)
mHomeMapCommon.refreshPetCurrentLocation(
it.latitude, it.longitude, isMoveCamera
)
mHomeMapCommon.startRefreshUserLocation()
}
ViewUtil.instance.viewShow(mViewBinding.homeMapLiveBtn)
mMapViewModel.setDeviceStateAndWarningData(
mContext!!,
getHomeV2Activity()?.getPet(),
it,
mViewBinding.ilHomeMapDeviceMsg.root,
mViewBinding.ilHomeMapDeviceMsg.tvDeviceMsgContent,
mViewBinding.ilHomeMapDeviceMsg.ivDeviceMsgCloseBtn,
mDeviceStateList,
mDeviceStateAdapter
)
}
mViewBinding.homeMapLiveBtn.visibility = View.VISIBLE
mMapViewModel.setDeviceStateAndWarningData(
mContext!!,
getHomeV2Activity()?.getPet(),
mMapDeviceBean!!,
mDeviceStateList,
mDeviceStateAdapter,
mDeviceMsgList,
mDeviceMsgAdapter,
mViewBinding.rvHomeMapDeviceMsg
)
}
}
}
@@ -438,10 +459,6 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
private fun updateMapDeviceStatus(
isNeedCountDown: Boolean = true, useBleLocation: Boolean = false
) {
// mShowCenterLocationType = ConstantInt.PetLocationType
// ViewUtil.instance.setMapSwitchLocationButtonImage(
// mViewBinding.homeMapRefreshBtn, mShowCenterLocationType
// )
getHomeV2Activity()?.apply {
if (mPetList.size <= mCurrentShowPetPos) return
getPet()?.apply {
@@ -531,8 +548,12 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
if (mHomeMapCommon.isMapLoadOk()) {
isMoveCamera = true
mHomeMapCommon.clearMarker()
mViewBinding.miHomeMapAddressView.visibility = View.GONE
mViewBinding.rvHomeMapDeviceMsg.visibility = View.GONE
mMapDeviceBean?.let {
it.isCloseMsg = false
it.isCloseBattery = false
it.canShowBattery = false
}
mViewBinding.ilHomeMapDeviceMsg.root.visibility = View.GONE
showLoading(true)
val pet = mPetList[position]
//重新设置地图宠物头像
@@ -555,7 +576,7 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
if (Util.isTimeoutReport(updateTime) || powerSwitch == ConstantInt.Type0 || powerSwitch == ConstantInt.Type2 || inWifiZone == ConstantInt.Type1) View.GONE
else View.VISIBLE
mHomeMapCommon.setMapDeviceBean(this)
setMapDeviceBean(this)
//设置循环查询时间间隔 30秒
mMapViewModel.updateMillisInFuture(0.5f)
@@ -565,10 +586,6 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
}
}
// mShowCenterLocationType = ConstantInt.PetLocationType
// ViewUtil.instance.setMapSwitchLocationButtonImage(
// mViewBinding.homeMapRefreshBtn, mShowCenterLocationType
// )
mHomeMapCommon.refreshPetCurrentLocation(latitude, longitude, isMoveCamera)
mHomeMapCommon.startRefreshUserLocation()
@@ -576,6 +593,22 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
}
}
private fun setMapDeviceBean(mapDeviceBean: MapDeviceBean) {
mapDeviceBean.apply {
mViewBinding.ilHomeMapDeviceBatteryLayout.let {
mMapViewModel.setMapDeviceBattery(
mContext!!, mapDeviceBean, it.root, it.tvDeviceBatteryInfo, it.ivDeviceCloseBtn
)
}
mViewBinding.ilHomeMapPetLocation.let {
mMapViewModel.setPetLocationReverseGeocode(
mContext!!, mapDeviceBean, it.root, it.tvPetLocationReverseGeocode
)
}
mHomeMapCommon.setMapDeviceBean(this)
}
}
/**
* 检查获取定位,蓝牙权限
*/
@@ -591,7 +624,7 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
} else {
getPet()?.apply {
mViewBinding.homeMapLiveBtn.isEnabled = false
val intent = Intent(mContext, LiveActivityV2::class.java)
val intent = Intent(mContext, LiveActivityV3::class.java)
intent.putExtra(ConstantString.JumpActivity, true)
intent.putExtra(ConstantString.Pet, this)
startActivity(intent)
@@ -605,7 +638,7 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
} else {
getPet()?.apply {
mViewBinding.homeMapBluetoothBtn.isEnabled = false
val intent = Intent(mContext, LiveActivityV2::class.java)
val intent = Intent(mContext, LiveActivityV3::class.java)
intent.putExtra(ConstantString.JumpActivity, false)
intent.putExtra(ConstantString.Pet, this)
startActivity(intent)
@@ -644,7 +677,7 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
getHomeV2Activity()?.let {
it.getPet()?.apply {
mViewBinding.homeMapLiveBtn.isEnabled = false
val intent = Intent(mContext, LiveActivityV2::class.java)
val intent = Intent(mContext, LiveActivityV3::class.java)
intent.putExtra(ConstantString.JumpActivity, true)
intent.putExtra(ConstantString.Pet, this)
startActivity(intent)
@@ -655,6 +688,15 @@ class MapV3Fragment : BaseFragment<FragmentMapV3Binding>(FragmentMapV3Binding::i
llHomeMapTopPet.ivTopPetBtnSmall -> showMapTypeDialog()
homeMapBluetoothBtn -> checkPermissions(1)
llHomeMapTopPet.homeDataPetNameSmall, llHomeMapTopPet.homeDataPetHeadSmall.root -> getHomeV2Activity()?.selectPetDialog()
ilHomeMapDeviceBatteryLayout.ivDeviceCloseBtn -> {
mMapDeviceBean?.isCloseBattery = true
llHomeMapDeviceBatteryLayout.visibility = View.INVISIBLE
}
ilHomeMapDeviceMsg.ivDeviceMsgCloseBtn -> {
mMapDeviceBean?.isCloseMsg = true
ilHomeMapDeviceMsg.root.visibility = View.GONE
}
}
}

View File

@@ -21,6 +21,7 @@ import com.abbidot.tracker.R
import com.abbidot.tracker.base.BaseFragment
import com.abbidot.tracker.bean.FencesBean
import com.abbidot.tracker.bean.HistoryDataBean
import com.abbidot.tracker.bean.MapDeviceBean
import com.abbidot.tracker.constant.ConstantInt
import com.abbidot.tracker.databinding.FragmentGoogleMapBinding
import com.abbidot.tracker.util.ImageUtil
@@ -392,13 +393,16 @@ abstract class BaseGoogleMapFragment :
}
//刷新当前位置ok,延时等待移动地图摄像头动画
if (isAnimMoveCamera) {
mGoogleMapView.postDelayed({
onRefreshPetCurrentLocationOk(mGoogleMap!!)
}, 1000)
} else {
// if (isAnimMoveCamera) {
// mGoogleMapView.postDelayed({
// onRefreshPetCurrentLocationOk(mGoogleMap!!)
// }, 1000)
// } else {
// onRefreshPetCurrentLocationOk(mGoogleMap!!)
// }
mGoogleMapView.postDelayed({
onRefreshPetCurrentLocationOk(mGoogleMap!!)
}
}, 500)
}
}
}
@@ -1066,6 +1070,21 @@ abstract class BaseGoogleMapFragment :
}
}
/**
* 设置Marker弹窗设备电量的位置
*/
fun setMapDeviceBatteryOffset(
viewGroup: ViewGroup, latLng: LatLng, mapDeviceBean: MapDeviceBean
) {
mGoogleMap?.projection?.toScreenLocation(latLng)?.let {
viewGroup.x = it.x.toFloat() - viewGroup.width / 2 + AppUtils.dpToPx(5)
viewGroup.y = it.y.toFloat() - AppUtils.dpToPx(56) - viewGroup.height
if (mapDeviceBean.canShowBattery && !mapDeviceBean.isCloseBattery) ViewUtil.instance.viewShow(
viewGroup
)
}
}
/**
* 设置地图网络类型显示位置
*/

View File

@@ -0,0 +1,320 @@
package com.abbidot.tracker.ui.fragment.map.googlemap
import android.animation.ValueAnimator
import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import androidx.core.content.ContextCompat
import androidx.core.view.isGone
import androidx.fragment.app.viewModels
import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.baselibrary.util.Utils
import com.abbidot.tracker.R
import com.abbidot.tracker.bean.HistoryDataBean
import com.abbidot.tracker.bean.MapDeviceBean
import com.abbidot.tracker.databinding.LayoutPetLocationInfoBinding
import com.abbidot.tracker.util.Util
import com.abbidot.tracker.util.ViewUtil
import com.abbidot.tracker.vm.GeoCoderViewModel
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.Circle
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
/**
*Created by .yzq on 2022/1/13/013.
* @link
* @description:首页map谷歌地图
*/
class HomeMapGoogleMapFragmentV3 : BaseGoogleMapFragment() {
private val mGeoCoderViewModel: GeoCoderViewModel by viewModels()
private lateinit var mPetLocationLayoutBinding: LayoutPetLocationInfoBinding
private lateinit var mDeviceBatteryLayout: ViewGroup
//宠物当前反地理位置信息
var mDecPetAddressData: HistoryDataBean? = null
private var mMapDeviceBean: MapDeviceBean? = null
private lateinit var mMapLoadOk: () -> Unit
//启动动画移动地图摄像机
private var isMoveCamera = true
private var mPolyline: Polyline? = null
private var mRippleCircle: Circle? = null
private var mValueAnimator: ValueAnimator? = null
private var mRippleCirclePercent = 0.0
private var mRippleCircleRadius = 200
private var isMapCameraMove = false
private var mPetAddressTimeFormat = Utils.DATE_FORMAT_PATTERN_EN11
companion object {
@JvmStatic
fun newInstance(
context: Context,
locationLayoutViewBinding: LayoutPetLocationInfoBinding,
deviceBatteryLayout: ViewGroup,
petAddressTimeFormat: String,
mapLoadOk: () -> Unit
) = HomeMapGoogleMapFragmentV3().apply {
mContext = context
mDeviceBatteryLayout = deviceBatteryLayout
mPetLocationLayoutBinding = locationLayoutViewBinding
mPetAddressTimeFormat = petAddressTimeFormat
mMapLoadOk = mapLoadOk
}
}
fun setMapDeviceBean(mapDeviceBean: MapDeviceBean?) {
mMapDeviceBean = mapDeviceBean
}
override fun liveDataObserve() {
//反地理编码成功返回
mGeoCoderViewModel.mLatLonAddressLiveData.observe(viewLifecycleOwner) {
//保存地理信息,方便传参给导航页面
if (null == mDecPetAddressData) mDecPetAddressData = HistoryDataBean()
mMapDeviceBean?.apply {
val timeString = Utils.formatTime(latLonUpdateTime * 1000, mPetAddressTimeFormat)
mDecPetAddressData?.let { history ->
//更新位置时间
history.dayTime = timeString
//详细位置
history.address = it
//传递位置信息给InfoWindowAdapter窗口
// mMarker?.tag = history
// showMarkerInfoWindow(history)
val address = String.format(mContext!!.getString(R.string.txt_near), it)
ViewUtil.instance.viewShow(mPetLocationLayoutBinding.root)
mPetLocationLayoutBinding.let { layout ->
layout.tvPetLocationReverseGeocode.text = address
layout.tvPetLocationUpdateTime.text = timeString
}
}
}
}
}
override fun onMapLoadOk(googleMap: GoogleMap) {
//设置自定义头部地点布局
mGoogleMap?.apply {
setOnCameraIdleListener {
if (isMapCameraMove) {
isMapCameraMove = false
} else {
setMarkerInfoViewOffset()
}
}
setOnCameraMoveListener {
isMapCameraMove = true
setMarkerInfoViewOffset()
}
setOnMarkerClickListener(object : GoogleMap.OnMarkerClickListener {
override fun onMarkerClick(marker: Marker): Boolean {
if (marker == mMarker) {
mMapDeviceBean?.let {
if (it.canShowBattery) {
mDeviceBatteryLayout.visibility = if (mDeviceBatteryLayout.isGone) {
it.isCloseBattery = false
View.VISIBLE
} else {
it.isCloseBattery = true
View.GONE
}
}
}
return true
}
return false
}
})
getLastLocation()
}
//变量是否初始化
if (::mMapLoadOk.isInitialized) mMapLoadOk()
}
override fun onRefreshPetCurrentLocationOk(googleMap: GoogleMap) {
if (null == mMarker) return
else startReverseGeocode()
}
/**
* 刚开始的反编译地理位置
*/
private fun startReverseGeocode() {
mMapDeviceBean?.apply {
mGeoCoderViewModel.getLatLonAddress(latitude, longitude, false)
setMarkerInfoViewOffset()
}
}
fun setMarkerInfoViewOffset() {
mPetLatLng?.apply {
mMapDeviceBean?.let {
setMapDeviceBatteryOffset(
mDeviceBatteryLayout, LatLng(latitude, longitude), it
)
}
}
}
/**
* 计算用户和宠物的距离
*/
fun getUserAndPetDistance(): Double {
var distance = 0.0
mUserLatLng?.apply {
mPetLatLng?.let {
distance =
Util.measureLatLonDistance(latitude, longitude, it.latitude, it.longitude)
}
}
return distance
}
/**
* 画用户和宠物之间的虚线
*/
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
}
}
}
}
/**
* 初始化并添加水波纹圆
*/
private fun addRippleCircle() {
mPetLatLng?.apply {
mGoogleMap?.let {
if (null == mRippleCircle) {
mRippleCircle = it.addCircle(
CircleOptions().center(this)
.radius(mRippleCircleRadius * mRippleCirclePercent)
.strokeWidth(AppUtils.dpToPx(2).toFloat())
.fillColor(ContextCompat.getColor(mContext!!, R.color.black10))
.strokeColor(ContextCompat.getColor(mContext!!, R.color.black10))
)
setRippleCircleAnim()
}
}
}
}
/**
* 设置水波纹动画
*/
private fun setRippleCircleAnim() {
if (null == mValueAnimator) {
mValueAnimator = ViewUtil.instance.setValueAnimator(
0.0, 100.0, 1500, LinearInterpolator()
) {
mRippleCirclePercent = it.animatedValue as Float / 100.0
mRippleCircle?.apply {
mPetLatLng?.let { petLatLng ->
center = petLatLng
radius = mRippleCircleRadius * mRippleCirclePercent
}
}
}?.apply {
repeatMode = ValueAnimator.RESTART
repeatCount = ValueAnimator.INFINITE
}
}
}
/**
* 画线
*/
fun addLine(latLng: LatLng) {
// addPolyline(mGoogleMap!!, latLng)
// addUserAndPetLine(latLng)
refreshPetCurrentLocation(latLng, needMoveCamera = isMoveCamera)
// mRippleCircle?.apply {
// //一像素对应几米
// val pxDis = 2.0.pow(15.5 - getGoogleMapZoom())
// mRippleCircleRadius = (pxDis * 150).toInt()
// fillColor = (ContextCompat.getColor(mContext!!, R.color.select_color5))
// strokeColor = (ContextCompat.getColor(mContext!!, R.color.select_color5))
// mValueAnimator?.duration = 2000
// }
}
/**
* 画多条线
*/
fun addLines(trackList: MutableList<HistoryDataBean>) {
val latLngList = mutableListOf<LatLng>()
for (i in 0 until trackList.size) {
trackList[i].apply {
val latLng = LatLng(latitude, longitude)
latLngList.add(latLng)
if (i == trackList.size - 1) {
// addUserAndPetLine(latLng)
refreshPetCurrentLocation(latLng, needMoveCamera = isMoveCamera)
}
}
}
// addPolyLines(mGoogleMap!!, latLngList)
}
/**
* 开始水波纹动画
*/
fun startRippleCircleAnim() {
mPetLatLng?.apply {
//一像素对应几米
val pxDis = 2.0.pow(15.5 - getGoogleMapZoom())
mRippleCircleRadius = (pxDis * 150).toInt()
// addUserAndPetLine(this)
addRippleCircle()
}
}
/**
* 直播开始之后,改变绿色波纹动画
*/
fun greenRippleCircleAnim() {
mRippleCircle?.apply {
//一像素对应几米
val pxDis = 2.0.pow(15.5 - getGoogleMapZoom())
mRippleCircleRadius = (pxDis * 150).toInt()
fillColor = (ContextCompat.getColor(mContext!!, R.color.select_color5))
strokeColor = (ContextCompat.getColor(mContext!!, R.color.select_color5))
mValueAnimator?.duration = 2000
}
}
override fun onDetach() {
super.onDetach()
mValueAnimator?.cancel()
}
}

View File

@@ -36,6 +36,7 @@ import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.core.view.setPadding
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.FragmentActivity
@@ -1116,6 +1117,6 @@ class ViewUtil private constructor() {
}
fun viewShow(view: View) {
if (view.isGone) view.visibility = View.VISIBLE
if (view.isGone || view.isInvisible) view.visibility = View.VISIBLE
}
}

View File

@@ -2,6 +2,10 @@ package com.abbidot.tracker.vm
import android.content.Context
import android.os.CountDownTimer
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.ContextCompat
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@@ -17,6 +21,8 @@ import com.abbidot.tracker.retrofit2.NetworkApi
import com.abbidot.tracker.util.Util
import com.abbidot.tracker.util.ViewUtil
import com.abbidot.tracker.util.bluetooth.SRBleUtil
import com.abbidot.tracker.widget.TypefaceButton
import com.abbidot.tracker.widget.TypefaceTextView
import kotlinx.coroutines.launch
class MapViewModel : ViewModel() {
@@ -28,8 +34,7 @@ class MapViewModel : ViewModel() {
private var mRefreshDataMin = 0.5f
private var mDeviceId = ""
//警告动画是否结束
private var isWarningAnimEnd = true
private var mDeviceMsgType = ConstantInt.SpecialType
fun getMapDeviceStatus(deviceId: String, isNeedCountDown: Boolean = true) {
viewModelScope.launch {
@@ -199,6 +204,63 @@ class MapViewModel : ViewModel() {
}
}
/**
* 设置设备状态和告警信息显示
*/
fun setDeviceStateAndWarningData(
context: Context,
petBean: PetBean?,
mapDeviceBean: MapDeviceBean,
rootView: ViewGroup,
tvDeviceMsgView: TypefaceButton,
deviceMsgCloseBtn: AppCompatImageView,
deviceStateList: MutableList<DataBean>,
deviceStateAdapter: BaseRecyclerAdapter<DataBean>,
) {
mapDeviceBean.apply {
tvDeviceMsgView.setBackgroundResource(R.color.device_msg_color1)
if (null != petBean && null != SRBleUtil.instance.getConnectMacDevice(petBean.macID)) {
if (isCloseMsg && mDeviceMsgType == ConstantInt.Type0) {
} else {
val nearby =
String.format(context.getString(R.string.txt_is_nearby), petBean.petName)
tvDeviceMsgView.text = nearby
isCloseMsg = false
tvDeviceMsgView.setBackgroundResource(R.color.green_color10)
ViewUtil.instance.viewShow(rootView)
deviceMsgCloseBtn.visibility = View.GONE
}
} else if (inNoGoZone == ConstantInt.BadZone) {
if (isCloseMsg && mDeviceMsgType == ConstantInt.Type1) {
} else {
tvDeviceMsgView.text = context.getString(R.string.txt_in_no_go_zone)
ViewUtil.instance.viewShow(deviceMsgCloseBtn)
ViewUtil.instance.viewShow(rootView)
isCloseMsg = false
mDeviceMsgType = ConstantInt.Type1
}
} else if (inSafeZone == ConstantInt.BadZone) {
if (isCloseMsg && mDeviceMsgType == ConstantInt.Type2) {
} else {
tvDeviceMsgView.text = context.getString(R.string.txt_out_save_zone)
ViewUtil.instance.viewShow(rootView)
ViewUtil.instance.viewShow(deviceMsgCloseBtn)
isCloseMsg = false
mDeviceMsgType = ConstantInt.Type2
}
} else {
mDeviceMsgType = ConstantInt.Type3
rootView.visibility = View.GONE
}
setDeviceState(context, mapDeviceBean, deviceStateList)
deviceStateAdapter.notifyItemRangeChanged(0, deviceStateList.size)
}
}
/**
* 设置没有的状态
*/
@@ -363,6 +425,71 @@ class MapViewModel : ViewModel() {
}
}
fun setMapDeviceBattery(
context: Context,
mapDeviceBean: MapDeviceBean,
rootView: ViewGroup,
batteryText: TypefaceTextView,
closeBtn: AppCompatImageView
) {
mapDeviceBean.apply {
if (isCloseBattery) return@apply
batteryText.let {
canShowBattery = true
rootView.visibility = View.VISIBLE
if (powerSwitch == ConstantInt.Type0) {
it.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)
it.text = context.getString(R.string.txt_powered_off)
ViewUtil.instance.viewShow(closeBtn)
} else if (powerSwitch == ConstantInt.Type3) {
it.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.icon_charge_image, 0, 0, 0
)
it.text = context.getString(R.string.txt_charging)
ViewUtil.instance.viewShow(closeBtn)
} else if (batteryLevel <= ConstantInt.LowBattery30) {
val lowBattery =
if (batteryLevel <= ConstantInt.LowBattery10) ConstantInt.LowBattery10
else if (batteryLevel <= ConstantInt.LowBattery20) ConstantInt.LowBattery20
else ConstantInt.LowBattery30
it.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.icon_low_battery_image, 0, 0, 0
)
it.text = String.format(
context.getString(R.string.txt_battery_less_than), "$lowBattery"
)
} else {
rootView.visibility = View.INVISIBLE
canShowBattery = false
}
}
}
}
fun setPetLocationReverseGeocode(
context: Context,
mapDeviceBean: MapDeviceBean,
rootView: ViewGroup,
locationText: TypefaceTextView,
) {
mapDeviceBean.apply {
val imageResId = if (inWifiZone == ConstantInt.Type1) {
rootView.background =
ContextCompat.getDrawable(context, R.drawable.shape16_light_green_color_bg)
R.drawable.icon_wifi_image
} else {
rootView.background =
ContextCompat.getDrawable(context, R.drawable.shape16_white_color_bg)
R.drawable.icon_wifi_image
0
}
locationText.setCompoundDrawablesWithIntrinsicBounds(
imageResId, 0, 0, 0
)
}
}
/**
* 停止获取数据
*/

View File

@@ -1,133 +0,0 @@
package com.abbidot.tracker.widget
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.text.TextUtils
import android.util.AttributeSet
import android.view.View
import androidx.core.content.ContextCompat
import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.tracker.R
import com.qmuiteam.qmui.util.QMUIDisplayHelper
/**
*Created by .yzq on 2024/8/26/026.
* @link
* @description:
*/
class MapBatteryView : View {
private lateinit var mContext: Context
private var mOffsetX = 0
private var mOffsetY = 0
//文字和边界的距离。三角形的直线长
private var mPadding = 0
private lateinit var mTextPaint: Paint
private lateinit var mPaint: Paint
//小三角形的path
private lateinit var mTrianglePath: Path
private var mTimeText = ""
private var mAddressText = ""
constructor(context: Context) : super(context) {
init(context)
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context, attrs, defStyleAttr
) {
init(context)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context)
}
private fun init(context: Context) {
//禁用硬件加速,防止返回到界面多次执行onDraw
setLayerType(LAYER_TYPE_SOFTWARE, null)
mContext = context
mPaint = Paint().apply {
color = ContextCompat.getColor(mContext, R.color.white)
}
//开启抗锯齿
mTextPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = ContextCompat.getColor(mContext, R.color.black)
textSize = QMUIDisplayHelper.sp2px(mContext, 12).toFloat()
}
mPadding = AppUtils.dpToPx(6)
mTrianglePath = Path()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.apply {
startDraw(this)
}
}
private fun startDraw(canvas: Canvas) {
if (TextUtils.isEmpty(mAddressText) && TextUtils.isEmpty(mTimeText)) return
mTrianglePath.apply {
reset()
moveTo((mOffsetX - mPadding).toFloat(), (mOffsetY - mPadding).toFloat())
lineTo(mOffsetX.toFloat(), mOffsetY.toFloat())
lineTo((mOffsetX + mPadding).toFloat(), (mOffsetY - mPadding).toFloat())
close()
}
canvas.apply {
drawPath(mTrianglePath, mPaint)
val fontMetrics = mTextPaint.fontMetrics
//文字高度
val textHeight = fontMetrics.bottom - fontMetrics.top
//时间文字宽度
val timeTextWith = mTextPaint.measureText(mTimeText)
//地址文字宽度
val addressTextWith = mTextPaint.measureText(mAddressText)
val maxTextWith = maxOf(timeTextWith, addressTextWith)
drawRoundRect(
mOffsetX - maxTextWith / 2 - mPadding,
mOffsetY - textHeight * 2 - mPadding * 2,
mOffsetX + maxTextWith / 2 + mPadding,
mOffsetY.toFloat() - mPadding,
AppUtils.dpToPx(6f),
AppUtils.dpToPx(6f),
mPaint
)
drawText(
mTimeText,
mOffsetX - timeTextWith / 2,
mOffsetY - textHeight / 2 - mPadding,
mTextPaint
)
drawText(
mAddressText,
mOffsetX - addressTextWith / 2,
mOffsetY - textHeight / 2 - textHeight - mPadding,
mTextPaint
)
}
}
fun setShowText(time: String, address: String) {
mTimeText = time
mAddressText = address
invalidate()
}
fun setOffsetXY(x: Int, y: Int) {
mOffsetX = x
mOffsetY = y
invalidate()
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 B

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/green_color10" />
<corners android:radius="@dimen/dp_16" />
</shape>

View File

@@ -0,0 +1,145 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.activity.map.LiveActivityV2">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fc_live_v2_map_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll_live_v3_map_device_battery_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible">
<include
android:id="@+id/il_live_v3_map_device_battery_layout"
layout="@layout/layout_map_device_battery" />
</androidx.appcompat.widget.LinearLayoutCompat>
<include
android:id="@+id/ll_live_v2_map_top_pet"
layout="@layout/layout_top_pet_data_small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_8"
android:layout_marginTop="@dimen/dp_40" />
<com.qmuiteam.qmui.widget.roundwidget.QMUIRoundLinearLayout
android:id="@+id/ll_live_v2_state_layout"
android:layout_width="wrap_content"
android:layout_height="@dimen/dp_34"
android:layout_below="@id/ll_live_v2_map_top_pet"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/dp_8"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="@dimen/dp_12"
android:visibility="gone"
app:qmui_backgroundColor="@color/select_color2"
app:qmui_radius="@dimen/dp_28">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lav_live_v2_state_anim"
android:layout_width="@dimen/dp_40"
android:layout_height="wrap_content"
android:visibility="gone"
app:lottie_loop="true" />
<com.abbidot.tracker.widget.TypefaceTextView
android:id="@+id/tv_live_v2_state_content"
style="@style/my_TextView_style_v2"
android:text="@string/txt_starting_live"
android:textColor="@color/select_color"
android:textSize="@dimen/textSize12"
app:typeface="@string/roboto_regular_font" />
</com.qmuiteam.qmui.widget.roundwidget.QMUIRoundLinearLayout>
<include
android:id="@+id/il_live_v3_map_device_msg"
layout="@layout/item_home_map_device_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/ll_live_v2_state_layout"
android:layout_centerInParent="true"
android:layout_marginTop="@dimen/dp_6"
android:visibility="gone" />
<com.abbidot.tracker.widget.NonSwipeRecyclerView
android:id="@+id/rv_map_live_v2_device_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/ll_live_v2_map_top_pet"
android:layout_alignParentEnd="true"
android:layout_marginTop="@dimen/dp_18"
android:layout_marginEnd="@dimen/dp_12"
android:layoutDirection="rtl" />
<include
android:id="@+id/il_live_v2_bluetooth_find_device"
layout="@layout/layout_bluetooth_find_device"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:visibility="gone" />
<include
android:id="@+id/il_live_v3_map_pet_location"
layout="@layout/layout_pet_location_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginHorizontal="@dimen/dp_8"
android:layout_marginBottom="@dimen/dp_4"
android:visibility="invisible" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_map_live_v2_refresh_btn"
style="@style/map_image_yellow_btn_style"
android:layout_above="@id/il_live_v3_map_pet_location"
android:layout_alignParentEnd="true"
android:layout_marginEnd="@dimen/dp_12"
android:layout_marginBottom="@dimen/dp_16" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_map_live_v2_bluetooth_btn"
style="@style/map_image_white_btn_style"
android:layout_alignTop="@id/iv_map_live_v2_refresh_btn"
android:layout_alignBottom="@id/iv_map_live_v2_refresh_btn"
android:layout_marginStart="@dimen/dp_12"
android:padding="@dimen/dp_8"
android:src="@drawable/icon_map_bluetooth" />
<include
android:id="@+id/il_map_live_v2_issue_layout"
layout="@layout/layout_live_issue"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:visibility="gone" />
</RelativeLayout>
<include
android:id="@+id/il_live_v2_operate_layout"
layout="@layout/layout_live_v2_data_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white" />
</androidx.appcompat.widget.LinearLayoutCompat>

View File

@@ -10,10 +10,17 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.abbidot.tracker.widget.MapMarkerInfoView
android:id="@+id/mi_home_map_address_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/ll_home_map_device_battery_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible">
<include
android:id="@+id/il_home_map_device_battery_layout"
layout="@layout/layout_map_device_battery" />
</androidx.appcompat.widget.LinearLayoutCompat>
<RelativeLayout
@@ -29,13 +36,15 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_8" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_home_map_device_msg"
<include
android:id="@+id/il_home_map_device_msg"
layout="@layout/item_home_map_device_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/ll_home_map_top_pet"
android:layout_centerInParent="true"
android:layout_marginTop="@dimen/dp_8" />
android:layout_marginTop="@dimen/dp_6"
android:visibility="gone" />
<com.abbidot.tracker.widget.NonSwipeRecyclerView
android:id="@+id/rv_home_map_device_state"
@@ -53,7 +62,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="@dimen/dp_40" />
android:layout_marginBottom="@dimen/dp_38"
android:visibility="invisible" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/home_map_bluetooth_btn"
@@ -80,7 +90,7 @@
android:orientation="vertical"
android:paddingHorizontal="@dimen/dp_14"
android:paddingVertical="@dimen/dp_16"
android:visibility="visible">
android:visibility="invisible">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="@dimen/dp_255"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center">
@@ -9,11 +9,22 @@
<com.abbidot.tracker.widget.TypefaceButton
android:id="@+id/tv_device_msg_content"
style="@style/my_TextView_style_v2"
android:background="@color/orange_color3"
android:layout_marginTop="@dimen/dp_4"
android:layout_marginEnd="@dimen/dp_4"
android:background="@color/device_msg_color1"
android:paddingHorizontal="@dimen/dp_18"
android:paddingVertical="@dimen/dp_12"
android:textColor="@color/data_black_color"
android:textSize="@dimen/textSize12"
app:qmui_radius="@dimen/dp_28" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_device_msg_close_btn"
android:layout_width="@dimen/dp_16"
android:layout_height="@dimen/dp_16"
android:layout_gravity="end"
android:src="@drawable/ic_delete_easyy_photos"
android:tint="@color/gray_color3" />
</FrameLayout>

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_6"
android:layout_marginEnd="@dimen/dp_8"
android:gravity="center"
android:orientation="vertical">
<com.abbidot.tracker.widget.TypefaceTextView
android:id="@+id/tv_device_battery_info"
style="@style/my_TextView_style_v2"
android:background="@drawable/shape8_white_bg"
android:drawableStart="@drawable/icon_low_battery_image"
android:drawablePadding="@dimen/dp_4"
android:padding="@dimen/dp_10"
android:text="@string/txt_powered_off"
android:textSize="@dimen/textSize12"
app:typeface="@string/roboto_regular_font" />
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon_white_trigon" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_device_close_btn"
android:layout_width="@dimen/dp_16"
android:layout_height="@dimen/dp_16"
android:layout_gravity="end"
android:src="@drawable/ic_delete_easyy_photos"
android:tint="@color/gray_color3" />
</FrameLayout>

View File

@@ -18,6 +18,7 @@
<com.abbidot.tracker.widget.TypefaceTextView
android:id="@+id/tv_pet_location_update_time"
style="@style/my_TextView_style_v2"
android:layout_below="@id/tv_pet_location_reverse_geocode"
android:layout_alignParentEnd="true"

View File

@@ -796,7 +796,7 @@
<string name="txt_hours">hours</string>
<string name="txt_search_device">Searching…</string>
<string name="txt_no_search_device">Keep tracker on and nearby to scan.</string>
<string name="txt_battery_less_than">Battery less than %s%%</string>
<string name="txt_battery_less_than">Less than %s%%</string>
<string name="txt_outside">Outside</string>
<string name="txt_inside">Inside</string>
<string name="txt_7days_avg">7 Days Avg.</string>
@@ -1050,5 +1050,8 @@
<string name="txt_show_crash">The program has an exception and is about to exit</string>
<string name="txt_activate_subscribe">Activate Subscription</string>
<string name="txt_powered_off">Powered off</string>
<string name="txt_near">Near %s</string>
<string name="txt_charging">Charging</string>
</resources>

View File

@@ -42,6 +42,8 @@ class Utils {
const val DATE_FORMAT_PATTERN_EN8 = "hh:mm a"
const val DATE_FORMAT_PATTERN_EN9 = "MMM d, yyyy hh:mm a"
const val DATE_FORMAT_PATTERN_EN10 = "dd/MM/yyyy HH:mm:ss"
const val DATE_FORMAT_PATTERN_EN11 = "dd/MM HH:mm"
const val DATE_FORMAT_PATTERN_EN12 = "dd/MM HH:mm:ss"
//返回星期几 简写
const val WEEK_FORMAT_PATTERN = "E"