diff --git a/app/build.gradle b/app/build.gradle index 3fda936..eebcae9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8887a14..0aa0666 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -391,6 +391,10 @@ android:name=".ui.activity.map.LiveActivityV2" android:exported="false" android:screenOrientation="portrait" /> + ?, var wifiZones: MutableList?, 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 ) } diff --git a/app/src/main/java/com/abbidot/tracker/ui/activity/HomeV2Activity.kt b/app/src/main/java/com/abbidot/tracker/ui/activity/HomeV2Activity.kt index 23913fa..f50bd48 100644 --- a/app/src/main/java/com/abbidot/tracker/ui/activity/HomeV2Activity.kt +++ b/app/src/main/java/com/abbidot/tracker/ui/activity/HomeV2Activity.kt @@ -102,6 +102,7 @@ class HomeV2Activity : BaseActivity(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 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 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 } } } + (mFragments[2] as MapV3Fragment).showPetNameAndHead(mSelectPetPosition) } } @@ -406,7 +412,7 @@ class HomeV2Activity : BaseActivity(ActivityHomeV2Binding * 选择宠物弹窗 */ fun selectPetDialog() { - if (isRequestPetData && mPetList.size == 0) { + if (mPetList.size == 0) { showToast(R.string.no_bind_pet) return } diff --git a/app/src/main/java/com/abbidot/tracker/ui/activity/map/LiveActivityV3.kt b/app/src/main/java/com/abbidot/tracker/ui/activity/map/LiveActivityV3.kt new file mode 100644 index 0000000..274b2ad --- /dev/null +++ b/app/src/main/java/com/abbidot/tracker/ui/activity/map/LiveActivityV3.kt @@ -0,0 +1,1030 @@ +package com.abbidot.tracker.ui.activity.map + +import android.content.Intent +import android.graphics.Typeface +import android.view.View +import android.widget.RelativeLayout +import androidx.activity.viewModels +import androidx.core.view.isGone +import androidx.fragment.app.Fragment +import androidx.fragment.app.commit +import androidx.lifecycle.lifecycleScope +import com.abbidot.baselibrary.constant.ConState +import com.abbidot.baselibrary.constant.EventName +import com.abbidot.baselibrary.constant.MMKVKey +import com.abbidot.baselibrary.eventbus.XEventBus +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.HomeMapDeviceStateAdapter +import com.abbidot.tracker.base.BaseActivity +import com.abbidot.tracker.base.BaseDialog +import com.abbidot.tracker.bean.BleReportDataBean +import com.abbidot.tracker.bean.BleTrackDeviceBean +import com.abbidot.tracker.bean.DataBean +import com.abbidot.tracker.bean.HistoryDataBean +import com.abbidot.tracker.bean.LiveDataBean +import com.abbidot.tracker.bean.MapDeviceBean +import com.abbidot.tracker.bean.PetBean +import com.abbidot.tracker.bean.ReceiveDeviceData +import com.abbidot.tracker.constant.ConstantInt +import com.abbidot.tracker.constant.ConstantString +import com.abbidot.tracker.constant.GetResultCallback +import com.abbidot.tracker.databinding.ActivityLiveV3Binding +import com.abbidot.tracker.deprecated.ui.activity.vm.LedLightViewModel +import com.abbidot.tracker.dialog.CommonDialog1 +import com.abbidot.tracker.dialog.SelectMapTypeDialog +import com.abbidot.tracker.ui.DebugActivity +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.SRBleCmdUtil +import com.abbidot.tracker.util.bluetooth.SRBleUtil +import com.abbidot.tracker.vm.ConnectionDeviceViewModel +import com.abbidot.tracker.vm.CountDownTimerViewModel +import com.abbidot.tracker.vm.FencesMapViewModel +import com.abbidot.tracker.vm.FindBleDeviceViewModel +import com.abbidot.tracker.vm.MapLiveViewModel +import com.abbidot.tracker.vm.MapViewModel +import com.clj.fastble.BleManager +import com.daimajia.androidanimations.library.Techniques +import com.daimajia.androidanimations.library.YoYo +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import javax.inject.Inject + +@AndroidEntryPoint +class LiveActivityV3 : BaseActivity(ActivityLiveV3Binding::inflate) { + + private val mFencesMapViewModel: FencesMapViewModel by viewModels() + private val mMapViewModel: MapViewModel by viewModels() + private val mFindBleDeviceViewModel: FindBleDeviceViewModel by viewModels() + private val mMapLiveViewModel: MapLiveViewModel by viewModels() + private val mLedLightViewModel: LedLightViewModel by viewModels() + private val mCountDownViewModel: CountDownTimerViewModel by viewModels() + private val mConDeviceViewModel: ConnectionDeviceViewModel by viewModels() + + private var mSelectMapTypeDialog: SelectMapTypeDialog? = null + + private lateinit var mDeviceStateList: MutableList + private lateinit var mDeviceStateAdapter: HomeMapDeviceStateAdapter + + @Inject + lateinit var mHomeMapCommon: HomeMapCommonV3 + private lateinit var mFragment: Fragment + + private var mMapDeviceBean: MapDeviceBean? = null + + //启动动画移动地图摄像机 + private var isMoveCamera = true + + //是否显示围栏 + private var isShowFence = true + + //地图类型,标准和卫星地图 + private var mMapType = ConstantInt.Type0 + private var mShowCenterLocation = ConstantInt.PetLocationType + + //是否是直播跳转 + private var isLiveJump = true + private var mLiveStatus = 1 + private var mPetBean: PetBean? = null + private var mTrackBleDevice: BleTrackDeviceBean? = null + + //直播是否开始 + private var isStartLive = false + + // private val mLiveStateTips = mutableListOf( +// R.string.txt_starting_live, R.string.txt_con_network, R.string.txt_gps_position +// ) + private var mStartLiveIndex = 0 + + //直播时间 分钟 + private var mLiveTime = 5 + private lateinit var mSpeedUnit: String + private lateinit var mDistanceUnit: String + + //是否打开了找设备的声音 + private var isOpenSound = false + + //设备Led灯开关 + private var isLedOpen = false + private var mRequestModeType = ConstantInt.Type1 + + override fun getTopBar() = null + + override fun initData() { + super.initData() + mSpeedUnit = Util.getMetricUnits(mContext, ConstantInt.Type2) + mDistanceUnit = Util.getMetricUnits(mContext, ConstantInt.Type3) + intent.extras?.apply { + isLiveJump = getBoolean(ConstantString.JumpActivity, true) + mPetBean = Util.getParcelableAdaptive(intent, ConstantString.Pet, PetBean::class.java) + } + + isShowFence = Util.getShowFenceSp() + + mViewBinding.apply { + ilLiveV2BluetoothFindDevice.ivMapLiveV2BleConState.setValue(0) + mFragment = mHomeMapCommon.getMapFragment( + mContext, + ilLiveV3MapPetLocation, + llLiveV3MapDeviceBatteryLayout, + Utils.DATE_FORMAT_PATTERN_EN12 + ) { mapLoadOk() } + ViewUtil.instance.setMapSwitchLocationButtonImage( + ivMapLiveV2RefreshBtn, mShowCenterLocation + ) + ilLiveV2OperateLayout.tvLiveV2Speed.text = "--$mSpeedUnit" + ilLiveV2OperateLayout.tvLiveV2Distance.text = "--$mDistanceUnit" + llLiveV2MapTopPet.ivTopPetBtnSmall.setImageResource(R.drawable.icon_map_type) + lavLiveV2StateAnim.let { + it.setAnimation("lottie/loading_dog.json") + it.playAnimation() + } + + mDeviceStateList = mutableListOf() + mMapViewModel.addDeviceDefaultStateData(mContext, mDeviceStateList) + mDeviceStateAdapter = HomeMapDeviceStateAdapter(mContext, mDeviceStateList) + ViewUtil.instance.setRecyclerViewVerticalLinearLayout( + mContext, rvMapLiveV2DeviceState, mDeviceStateAdapter, bottom = 10 + ) + ilLiveV2BluetoothFindDevice.liveV2BluetoothSignal.setValue(0) + ilLiveV2BluetoothFindDevice.findBleDeviceRadoView.setValue(0) + + setOnClickListenerViews( + ilLiveV2OperateLayout.llLiveV2StopLive, + ivMapLiveV2RefreshBtn, + ivMapLiveV2BluetoothBtn, + ilLiveV2BluetoothFindDevice.btnLiveV2StopRadar, + llLiveV2MapTopPet.ivTopPetBtnSmall, + ilLiveV2OperateLayout.ilLiveV2DataLightSwitch.root, + ilLiveV2OperateLayout.ilLiveV2DataLightSwitch.cbDeviceLightSwitch, + ilLiveV2BluetoothFindDevice.ilLiveV2RadarLightSwitch.cbDeviceLightSwitch, + ilLiveV2BluetoothFindDevice.ilLiveV2RadarLightSwitch.root, + ilLiveV2BluetoothFindDevice.ivLiveV2FindDeviceSound, + ilLiveV2OperateLayout.btnLiveV2Issue, + ilMapLiveV2IssueLayout.tvCloseIssueBtn, + ilLiveV3MapDeviceBatteryLayout.ivDeviceCloseBtn, + ilLiveV3MapDeviceMsg.ivDeviceMsgCloseBtn + ) + + supportFragmentManager.commit { + add(R.id.fc_live_v2_map_fragment, mFragment) + } + + mPetBean?.let { pet -> + if (!isLiveJump) { + findBleDevice(pet.macID) + llLiveV2StateLayout.visibility = View.GONE + } + + if (AppUtils.isDebug()) { + llLiveV2MapTopPet.homeDataPetHeadSmall.root.setOnLongClickListener { + goToDebugActivity(pet) + true + } + } + } + } + } + + /** + * 地图加载好了 + */ + private fun mapLoadOk() { + showPetNameAndHead() + } + + override fun liveDataObserve() { + mCountDownViewModel.mCountDownEndLiveData.observe(this) { + when (mStartLiveIndex) { +// 0 -> { +// mStartLiveIndex++ +// //显示Connecting to network 30秒 +// mViewBinding.tvLiveV2StateContent.setText(mLiveStateTips[mStartLiveIndex]) +// mCountDownViewModel.startCountDown(30) +// } +// +// 1 -> { +// mStartLiveIndex++ +// //显示GPS positioning +// mCountDownViewModel.startCountDown(3 * 60) +// mViewBinding.tvLiveV2StateContent.setText(mLiveStateTips[mStartLiveIndex]) +// } +// +// 2 -> { +// if (isStartLive) { +// mStartLiveIndex++ +// //显示Starting 5-min Live +// val str = String.format(getString(R.string.txt_start_min_live), mLiveTime) +// mViewBinding.tvLiveV2StateContent.text = str +// mCountDownViewModel.startCountDown(2) +// } else { +// //直播超时 +// mLiveStatus = -1 +// stopLive() +// } +// } +// + 2 -> { + mViewBinding.llLiveV2StateLayout.visibility = View.VISIBLE + mStartLiveIndex++ + //显示Starting 5-min Live + val str = String.format(getString(R.string.txt_start_min_live), "$mLiveTime") + mViewBinding.tvLiveV2StateContent.text = str + mCountDownViewModel.startCountDown(5) + } + + 3 -> mViewBinding.llLiveV2StateLayout.visibility = View.GONE + } + } + //获取当前宠物位置和围栏信息 + mMapViewModel.mMapDeviceLiveData.observe(this) { + dealRequestResult(it, object : GetResultCallback { + override fun onResult(any: Any) { + val data = it.getOrNull() + data?.apply { + mMapDeviceBean = data + setMapData(data) + mMapViewModel.setDeviceStateAndWarningData( + mContext, + mPetBean, + data, + mViewBinding.ilLiveV3MapDeviceMsg.root, + mViewBinding.ilLiveV3MapDeviceMsg.tvDeviceMsgContent, + mViewBinding.ilLiveV3MapDeviceMsg.ivDeviceMsgCloseBtn, + mDeviceStateList, + mDeviceStateAdapter + ) + } + } + + override fun onRequestError(exceptionCode: String?) { + LogUtil.e("LiveV2Activity获取当前宠物位置和围栏信息onRequestError,再次请求") + if (exceptionCode == mNetworkRequestsFailLimit) { + finish() + } else { + mPetBean?.apply { + //获取首页设备信息状态 + mMapViewModel.getMapDeviceStatus(deviceId, false) + } + } + } + }, showLoading = false) + } + + mMapLiveViewModel.mMapLiveStatusLiveData.observe(this) { + dealRequestResult(it, object : GetResultCallback { + override fun onResult(any: Any) { + mPetBean?.apply { +// SRBleUtil.instance.isConnectBleSendNotifyData(macID) + when (mLiveStatus) { + //直播超时 + -1 -> { + XEventBus.post(EventName.LiveOpenTimeOut) + finish() + } + //直播结束 + 0 -> { + mViewBinding.llLiveV2StateLayout.visibility = View.GONE +// showToast(R.string.txt_change_successful, true) + finish() + } + //直播开始 + else -> { + //直播开启后,就去获取直播轨迹 + if (!BleManager.getInstance().isConnected(macID)) { + mMapLiveViewModel.mGetPetLivePointTimeStamp = + System.currentTimeMillis() / 1000 + mMapLiveViewModel.getPetLivePoint(deviceId) + } + } + } + } + } + + override fun onRequestError(exceptionCode: String?) { + LogUtil.e("HomeV2Activity直播开启错误onRequestError,再次请求") + if (exceptionCode == mNetworkRequestsFailLimit) { + finish() + } else { + mPetBean?.apply { + mMapLiveViewModel.setupDeviceLiveStatus( + this@LiveActivityV3, deviceId, mLiveStatus, mRequestModeType + ) + } + } + } + }) + } + + //获取直播轨迹 + mMapLiveViewModel.mMapLiveLiveData.observe(this) { + mHomeMapCommon.startRefreshUserLocation() + dealRequestResult(it, object : GetResultCallback { + override fun onResult(any: Any) { + it.getOrNull()?.apply { + setTrackData(this) + } + } + }, isShowRequestErrorTip = false) + } + + //接收蓝牙连接状态 + XEventBus.observe(this, EventName.ConnectDeviceState) { trackBle: BleTrackDeviceBean -> + mPetBean?.apply { + if (trackBle.mac == macID && trackBle.conState != ConState.CONNECTED) { + //隐藏蓝牙nearby + mViewBinding.ilLiveV3MapDeviceMsg.root.visibility = View.GONE + } + } + mMapDeviceBean?.apply { + if (trackBle.mac == deviceMacId) { + updateConState(trackBle) + } + } + } + //搜索蓝牙的设备状态 + XEventBus.observe(this, EventName.ActionConDeviceState) { conState: Int -> + if (conState == ConState.DEVICE_NOT_FOUND) { + openNetLive(ConstantInt.Type2) + } + } + + mLedLightViewModel.mLedSwitchLiveData.observe(this) { + dealRequestResult(it, object : GetResultCallback { + override fun onResult(any: Any) { +// mViewBinding.cbLiveV2DeviceLightSwitch.isChecked = +// !mViewBinding.cbLiveV2DeviceLightSwitch.isChecked +// showToast(R.string.txt_please_wait) + } + }) + } + + //蓝牙上报的数据 + XEventBus.observe(this, EventName.BleReportData) { reportData: BleReportDataBean -> + mPetBean?.apply { + if (macID == reportData.mac) updateBleReportData(reportData) + } + } + + //接收发送指令后设备返回的数据 + XEventBus.observe(this, EventName.DeviceReceiveData) { receiveData: ReceiveDeviceData -> + mPetBean?.apply { + if (macID == receiveData.mac) { + val data = receiveData.data + parseData(data) + } + } + } + } + + + /** + * 跳转debug调试页面 + */ + private fun goToDebugActivity(petBean: PetBean) { + val intent = Intent(mContext, DebugActivity::class.java) + ArrayList().apply { + add(petBean) + intent.putParcelableArrayListExtra(ConstantString.Pet, this) + } + intent.putExtra(ConstantString.Index, 0) + startActivity(intent) + } + + /** + * 解析蓝牙返回的数据 + */ + private fun parseData(data: ByteArray?) { + if (null != data && data.isNotEmpty()) { + val data0 = SRBleCmdUtil.instance.byteToInt(data[0]) + val data1 = SRBleCmdUtil.instance.byteToInt(data[1]) + val data2 = SRBleCmdUtil.instance.byteToInt(data[2]) + if (data0 == 0x06 && data1 == 1) { + val data3 = SRBleCmdUtil.instance.byteToInt(data[3]) + //开启直播 + if (data2 == 1) { + if (data3 == 0) { + LogUtil.e("蓝牙开启直播成功") + mPetBean?.apply { + mRequestModeType = ConstantInt.Type1 + mMapLiveViewModel.setupDeviceLiveStatus( + this@LiveActivityV3, deviceId, mLiveStatus, mRequestModeType + ) + } + } else { + LogUtil.e("蓝牙开启直播失败") + openNetLive(ConstantInt.Type3) + } + } else if (data2 == 0) { + mPetBean?.apply { + //停止Live直播 + mRequestModeType = if (data3 == 0) { + LogUtil.e("蓝牙停止直播成功") + ConstantInt.Type1 + } else { + LogUtil.e("蓝牙停止直播失败") + ConstantInt.Type3 + } + mMapLiveViewModel.setupDeviceLiveStatus( + this@LiveActivityV3, deviceId, 0, mRequestModeType + ) + } + } + } else if (data0 == 3 && data1 == 1) { + val modeType = if (data2 == 0) { + ConstantInt.Type1 + } else { + ConstantInt.Type3 + } + mMapDeviceBean?.apply { + mLedLightViewModel.setLedSwitch( + null, deviceServerId, ledSwitch, modeType + ) + } + } + } + } + + /** + * 开启网络上报直播 + */ + private fun openNetLive(modeType: Int) { + if (isLiveJump) { + mPetBean?.apply { + //刚开始显示Starting Live. + mCountDownViewModel.startCountDown(2) + mRequestModeType = modeType + mMapLiveViewModel.setupDeviceLiveStatus( + this@LiveActivityV3, deviceId, mLiveStatus, modeType + ) + } + } + } + + /** + * 更新蓝牙上报的数据 + */ + private fun updateBleReportData(bleReportDataBean: BleReportDataBean) { + mHomeMapCommon.startRefreshUserLocation() + bleReportDataBean.apply { + if (haveDeviceStateData) { + if (null == mMapDeviceBean) mMapDeviceBean = MapDeviceBean() + mMapDeviceBean?.let { + Util.bleReportDataToMapDevice(it, bleReportDataBean) + + val isOpen = ledSwitch > ConstantInt.Close + mViewBinding.ilLiveV2OperateLayout.ilLiveV2DataLightSwitch.cbDeviceLightSwitch.isChecked = + isOpen + mViewBinding.ilLiveV2BluetoothFindDevice.ilLiveV2RadarLightSwitch.cbDeviceLightSwitch.isChecked = + isOpen + +// if (haveLocationData && liveFlag == ConstantInt.Type1) { + if (liveFlag == ConstantInt.Type1) { + if (!isStartLive) { + isStartLive = true + liveStartTip() + } + if (haveLocationData) { + lifecycleScope.launch { + locationList?.let { location -> + liveDrawLines(location) + } + } + } + setMapDeviceBean(it) + } else if (liveFlag == ConstantInt.Type0) { + //直播自动结束 + if (isStartLive) { + XEventBus.post(EventName.LiveAutoEnd) + finish() + } + } + + mMapViewModel.setDeviceStateAndWarningData( + mContext, + mPetBean, + it, + mViewBinding.ilLiveV3MapDeviceMsg.root, + mViewBinding.ilLiveV3MapDeviceMsg.tvDeviceMsgContent, + mViewBinding.ilLiveV3MapDeviceMsg.ivDeviceMsgCloseBtn, + mDeviceStateList, + mDeviceStateAdapter + ) + } + } + } + } + + /** + * 远程设置led开关 + */ + private fun setLedSwitch() { + isLedOpen = !isLedOpen + mViewBinding.apply { + //屏蔽点击就变状态 +// cbLiveV2DeviceLightSwitch.isChecked = !cbLiveV2DeviceLightSwitch.isChecked + ilLiveV2OperateLayout.ilLiveV2DataLightSwitch.cbDeviceLightSwitch.isChecked = isLedOpen + ilLiveV2BluetoothFindDevice.ilLiveV2RadarLightSwitch.cbDeviceLightSwitch.isChecked = + isLedOpen + val ledSwitch = if (isLedOpen) ConstantInt.Open + else ConstantInt.Close + + mMapDeviceBean?.apply { + this.ledSwitch = ledSwitch + if (BleManager.getInstance().isConnected(deviceMacId)) { + setLedSwitch(ledSwitch) + } else { + mLedLightViewModel.setLedSwitch( + null, deviceServerId, ledSwitch, ConstantInt.Type2 + ) + } + } + } + } + + /** + *发送设备开启关闭led蓝牙指令 + */ + private fun setLedSwitch(mode: Int) { + mTrackBleDevice?.apply { + SRBleUtil.instance.setBleLedSwitch(mContext, bleDevice, mode) + } + } + + /** + * 更新设备连接状态 + */ + private fun updateConState(trackBleDevice: BleTrackDeviceBean) { + mTrackBleDevice = trackBleDevice + if (trackBleDevice.conState == ConState.CONNECTED) { + LogUtil.e("更新设备连接状态") + if (isLiveJump) { + if (isStartLive) { + mMapLiveViewModel.stopGetData() + } else { + mCountDownViewModel.startCountDown(2) + lifecycleScope.launch { + //延时几秒发送消息 + delay(1000) + trackBleDevice.apply { + SRBleUtil.instance.writeData( + bleDevice, SRBleCmdUtil.instance.setLiveSwitch(1, mLiveTime * 60L) + ) + } + } + } + } +// showToast(R.string.tracker_manage_set_ble_connect) +// mViewBinding.ilLiveV2BluetoothFindDevice.ivMapLiveV2BleConState.setValue(2) + } else if (trackBleDevice.conState == ConState.CONNECTION_FAIL) { + if (isLiveJump) { + openNetLive(ConstantInt.Type2) + } + } else { + if (isLiveJump && isStartLive) { + mPetBean?.apply { + //直播开启后,就去获取直播轨迹 + mMapLiveViewModel.mGetPetLivePointTimeStamp = System.currentTimeMillis() / 1000 + mMapLiveViewModel.getPetLivePoint(deviceId) + } + } + } + } + + + /** + * 显示地图类型选择弹窗 + */ + private fun showMapTypeDialog() { + if (null == mSelectMapTypeDialog) { + mSelectMapTypeDialog = ViewUtil.instance.getMapTypeDialog( + mContext, object : BaseRecyclerAdapter.OnItemClickListener { + override fun onItemClick(itemView: View?, pos: Int) { + mMapType = Util.getMapTypeSp() + if (pos == mMapType) { + return + } + mHomeMapCommon.switchSatelliteAndNormalMapType() + } + }) { v, isChecked -> + if (v.id == R.id.cb_dialog_map_fences_switch) { + isShowFence = isChecked + MMKVUtil.putBoolean(MMKVKey.ShowFence, isChecked) + if (isChecked) { + mMapDeviceBean?.fences?.let { fences -> + mFencesMapViewModel.setFencesData(mContext, fences, mFragment) + } + } else { + mFencesMapViewModel.setFencesData(mContext, null, mFragment) + } + } + } + } else { + mSelectMapTypeDialog!!.mapTypeSpToUpdate() + } + mSelectMapTypeDialog?.show() + } + + /** + * 设置地图相关数据 + */ + private fun setMapData(mapDeviceBean: MapDeviceBean) { + mapDeviceBean.apply { + mLiveTime = liveTime / 60 + + mPetBean?.apply { + //查找是否连接了蓝牙 + val bleConDevice = SRBleUtil.instance.getConnectMacDevice(macID) + if (null == bleConDevice) { + if (isLiveJump) { + //没有连接,一进入页面就尝试连接 + if (SRBleUtil.instance.isBleEnable(mContext)) { + mConDeviceViewModel.connectDeviceToMac(this@LiveActivityV3, macID) + } else { + openNetLive(ConstantInt.Type2) + } + } + } else { + updateConState(bleConDevice) + } + } + + mViewBinding.let { + isLedOpen = ledSwitch == ConstantInt.Open + it.ilLiveV2OperateLayout.ilLiveV2DataLightSwitch.cbDeviceLightSwitch.isChecked = + isLedOpen + it.ilLiveV2BluetoothFindDevice.ilLiveV2RadarLightSwitch.cbDeviceLightSwitch.isChecked = + isLedOpen +// it.tvLiveV2Speed.text = String.format( +// getString(R.string.txt_mph_unit), +// Utils.formatDecimal(Util.kmhToMph(speed.toDouble())) +// ) + } + + if (isShowFence) { + fences?.let { fences -> + mFencesMapViewModel.setFencesData(mContext, fences, mFragment) + } + } + + mHomeMapCommon.let { + setMapDeviceBean(this) + it.refreshPetCurrentLocation(latitude, longitude, isMoveCamera) + it.startRippleCircleAnim() + isMoveCamera = false +// val userAndPetDistance = it.getUserAndPetDistance() +// mViewBinding.tvLiveV2Distance.text = String.format( +// getString(R.string.txt_ft_unit), Utils.formatDecimal(userAndPetDistance) +// ) + } + } + } + + private fun setMapDeviceBean(mapDeviceBean: MapDeviceBean) { + mapDeviceBean.apply { + mViewBinding.ilLiveV3MapDeviceBatteryLayout.let { + mMapViewModel.setMapDeviceBattery( + mContext, mapDeviceBean, it.root, it.tvDeviceBatteryInfo, it.ivDeviceCloseBtn + ) + } + mViewBinding.ilLiveV3MapPetLocation.let { + mMapViewModel.setPetLocationReverseGeocode( + mContext, mapDeviceBean, it.root, it.tvPetLocationReverseGeocode + ) + } + mHomeMapCommon.setMapDeviceBean(this) + } + } + + + /** + * 显示选择宠物弹窗 + */ + private fun showPetNameAndHead() { + mPetBean?.apply { + showLoading(true) + mViewBinding.llLiveV2MapTopPet.homeDataPetNameSmall.let { + it.text = petName + it.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0) + } + mViewBinding.llLiveV2MapTopPet.homeDataPetHeadSmall.appHeadImage.let { + ViewUtil.instance.setPetTypeHead(it, imgurl, petType) + ViewUtil.instance.viewAlphaAndRotationObjectAnimator(it) + } + //重新设置地图宠物头像 + mHomeMapCommon.setPetHeadIcon(imgurl, petType) + + //获取首页设备信息状态 + mMapViewModel.getMapDeviceStatus(deviceId, false) + } + } + + private fun setTrackData(liveDataBean: LiveDataBean) { + //测试经纬度移动 +// mFencesViewModel.setFencesData(mContext!!, isInFence, mFencesList, mFragment) + + mViewBinding.apply { + + liveDataBean.deviceInfo?.apply { + if (liveFlag == ConstantInt.Type0) { + //直播自动结束 + if (isStartLive) { + XEventBus.post(EventName.LiveAutoEnd) + finish() + } + return + } else if (liveFlag == ConstantInt.Type1) { + if (!isStartLive) { + liveStartTip() + isStartLive = true + } + } + + val speedStr = Util.metricConvertUnits( + speed, ConstantInt.Type2, 2 + ).toString() + mSpeedUnit + ilLiveV2OperateLayout.tvLiveV2Speed.text = speedStr + + setMapDeviceBean(this) + val isOpen = ledSwitch == ConstantInt.Open + ilLiveV2OperateLayout.ilLiveV2DataLightSwitch.cbDeviceLightSwitch.isChecked = isOpen + ilLiveV2BluetoothFindDevice.ilLiveV2RadarLightSwitch.cbDeviceLightSwitch.isChecked = + isOpen + mMapViewModel.setDeviceStateAndWarningData( + mContext, + mPetBean, + this, + mViewBinding.ilLiveV3MapDeviceMsg.root, + mViewBinding.ilLiveV3MapDeviceMsg.tvDeviceMsgContent, + mViewBinding.ilLiveV3MapDeviceMsg.ivDeviceMsgCloseBtn, + mDeviceStateList, + mDeviceStateAdapter + ) + + liveDataBean.livePoints?.apply { + if (size > 0) { + mMapLiveViewModel.mGetPetLivePointTimeStamp = + System.currentTimeMillis() / 1000 + //只有一个点的时候,不用休眠 + val sleepTime = + if (size - 1 > 0) mMapLiveViewModel.mRefreshTime / (size - 1) * 1000L + else 0 + lifecycleScope.launch { + forEach { + liveDrawLine(it.latitude, it.longitude) + //休眠几秒再画线 + if (sleepTime > 0) delay(sleepTime) + } + } + } + } + } + } + } + + /** + * 直播开始提示 + */ + private fun liveStartTip() { + LogUtil.e("直播开始了") + if (mStartLiveIndex == 0) { + mStartLiveIndex = 2 + //直播开始显示Starting 5-min Live + mCountDownViewModel.startCountDown(1) + mHomeMapCommon.greenRippleCircleAnim() + } + } + + /** + * 直播画线 + */ + private fun liveDrawLine(latitude: Double, longitude: Double) { + mHomeMapCommon.addTrackLine(latitude, longitude) + val userAndPetDistance = mHomeMapCommon.getUserAndPetDistance() + val distanceStr = Util.metricConvertUnits( + userAndPetDistance.toFloat(), ConstantInt.Type3, 2 + ).toString() + mDistanceUnit + mViewBinding.ilLiveV2OperateLayout.tvLiveV2Distance.text = distanceStr + } + + /** + * 直播画线 + */ + private fun liveDrawLines(trackList: MutableList) { + mHomeMapCommon.addTrackLines(trackList) + val userAndPetDistance = mHomeMapCommon.getUserAndPetDistance() + val distanceStr = Util.metricConvertUnits( + userAndPetDistance.toFloat(), ConstantInt.Type3, 2 + ).toString() + mDistanceUnit + mViewBinding.ilLiveV2OperateLayout.tvLiveV2Distance.text = distanceStr + } + + /** + * 显示隐藏找蓝牙设备布局 + */ + private fun showAndHideFindLayout() { + mViewBinding.apply { + ilLiveV3MapPetLocation.root.visibility = View.GONE + val relativeLayout = ivMapLiveV2RefreshBtn.layoutParams as RelativeLayout.LayoutParams + ivMapLiveV2RefreshBtn.visibility = View.GONE + if (ilLiveV2BluetoothFindDevice.root.isGone) { + //找蓝牙设备布局显示 + YoYo.with(Techniques.BounceInUp).duration(800).onStart { + ilLiveV2OperateLayout.root.visibility = View.GONE + ilLiveV2BluetoothFindDevice.root.visibility = View.VISIBLE + }.onEnd { + //刷新定位按钮显示动画 + ViewUtil.instance.viewShowFadeInAnimation(ivMapLiveV2RefreshBtn) + }.playOn(ilLiveV2BluetoothFindDevice.root) + + ivMapLiveV2BluetoothBtn.visibility = View.GONE + relativeLayout.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM) + relativeLayout.addRule(RelativeLayout.ABOVE, R.id.il_live_v2_bluetooth_find_device) + } else { + //找蓝牙设备布局退出 + YoYo.with(Techniques.SlideOutDown).duration(600).onEnd { + ilLiveV2BluetoothFindDevice.root.visibility = View.GONE + ilLiveV2OperateLayout.root.visibility = View.VISIBLE + }.playOn(ilLiveV2BluetoothFindDevice.root) + //直播操作按钮布局显示 + YoYo.with(Techniques.BounceInUp).duration(800).delay(400).onEnd { + //蓝牙图标按钮显示动画 + ViewUtil.instance.viewShowFadeInAnimation(ivMapLiveV2BluetoothBtn) + //刷新定位按钮显示动画 + ViewUtil.instance.viewShowFadeInAnimation(ivMapLiveV2RefreshBtn) + }.playOn(ilLiveV2OperateLayout.root) + + relativeLayout.removeRule(RelativeLayout.ABOVE) + relativeLayout.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM) + } + + root.postDelayed({ + ilLiveV3MapPetLocation.root.visibility = View.VISIBLE + mHomeMapCommon.setMarkerInfoViewOffset() + }, 1000) + } + } + + /** + * 显示直播问题 + */ + private fun showLiveIssue() { + mViewBinding.apply { + ilLiveV3MapPetLocation.root.visibility = View.GONE + if (ilMapLiveV2IssueLayout.root.isGone) { + YoYo.with(Techniques.BounceInUp).duration(700).onStart { + ilLiveV2OperateLayout.root.visibility = View.GONE + ilMapLiveV2IssueLayout.root.visibility = View.VISIBLE + }.playOn(ilMapLiveV2IssueLayout.root) + } else { + YoYo.with(Techniques.SlideOutDown).duration(600).onEnd { + ilMapLiveV2IssueLayout.root.visibility = View.GONE + YoYo.with(Techniques.BounceInUp).duration(600).onStart { + ilLiveV2OperateLayout.root.visibility = View.VISIBLE + }.playOn(ilLiveV2OperateLayout.root) + }.playOn(ilMapLiveV2IssueLayout.root) + } + + root.postDelayed({ + ilLiveV3MapPetLocation.root.visibility = View.VISIBLE + mHomeMapCommon.setMarkerInfoViewOffset() + }, 1000) + } + } + + /** + * 找蓝牙设备 + */ + private fun findBleDevice(mac: String) { + Util.checkBluetoothPermissionsEnabled(mContext, { + showAndHideFindLayout() + mViewBinding.ilLiveV2BluetoothFindDevice.apply { + mFindBleDeviceViewModel.startScanFind( + this@LiveActivityV3, + mac.uppercase(), + liveV2BluetoothSignal, + findBleDeviceRadoView, + ivMapLiveV2BleConState + ) + } + }) + } + + override fun listenBackPressed() { + if (isLiveJump) stopMapLive() + else super.listenBackPressed() + } + + private fun stopMapLive() { + CommonDialog1( + mContext, + "", + getString(R.string.txt_stop_live_tips), + false, + 5f, + Typeface.BOLD, + R.color.data_black_color, + canceledOnTouchOutside = true, + okClickListener = object : BaseDialog.OnDialogOkListener { + override fun onOkClick(dialog: BaseDialog<*>) { + mMapDeviceBean?.apply { + mLiveStatus = 0 + stopLive() + } + } + }).show() + } + + /** + * 停止直播 + */ + private fun stopLive() { + mPetBean?.apply { + setButtonEnabled(mViewBinding.ilLiveV2OperateLayout.llLiveV2StopLive, ConstantInt.Type0) + if (BleManager.getInstance().isConnected(macID)) { + SRBleUtil.instance.isConnectBleSendCmdData( + macID, SRBleCmdUtil.instance.setLiveSwitch(0, 0) + ) + } else { + mRequestModeType = ConstantInt.Type2 + mMapLiveViewModel.setupDeviceLiveStatus( + this@LiveActivityV3, mPetBean!!.deviceId, 0, mRequestModeType + ) + } + } + + } + + /** + * 设置找设备声音音量 + */ + private fun setSound() { + if (isOpenSound) { + mFindBleDeviceViewModel.setVolume(0) + mViewBinding.ilLiveV2BluetoothFindDevice.ivLiveV2FindDeviceSound.setImageResource(R.drawable.icon_sound_off_svg) + } else { + mFindBleDeviceViewModel.setVolume(mFindBleDeviceViewModel.mMaxVolume) + mViewBinding.ilLiveV2BluetoothFindDevice.ivLiveV2FindDeviceSound.setImageResource(R.drawable.icon_sound_on_svg) + } + isOpenSound = !isOpenSound + } + + override fun onClick(v: View?) { + mViewBinding.apply { + when (v!!) { + ivMapLiveV2RefreshBtn -> { + mShowCenterLocation = if (mShowCenterLocation == ConstantInt.PetLocationType) { + ConstantInt.UserLocationType + } else { + ConstantInt.PetLocationType + } + ViewUtil.instance.setMapSwitchLocationButtonImage( + ivMapLiveV2RefreshBtn, mShowCenterLocation + ) + mHomeMapCommon.switchShowLocation(mShowCenterLocation) + } + + ivMapLiveV2BluetoothBtn -> mPetBean?.apply { + findBleDevice(macID) + } + + ilLiveV2BluetoothFindDevice.btnLiveV2StopRadar -> { + if (isLiveJump) { + isOpenSound = true + setSound() + showAndHideFindLayout() + } else { + mFindBleDeviceViewModel.stopFindDevice() + finish() + } + } + + llLiveV2MapTopPet.ivTopPetBtnSmall -> showMapTypeDialog() + ilLiveV2OperateLayout.llLiveV2StopLive -> stopMapLive() + ilLiveV2OperateLayout.ilLiveV2DataLightSwitch.root, ilLiveV2OperateLayout.ilLiveV2DataLightSwitch.cbDeviceLightSwitch, ilLiveV2BluetoothFindDevice.ilLiveV2RadarLightSwitch.cbDeviceLightSwitch, ilLiveV2BluetoothFindDevice.ilLiveV2RadarLightSwitch.root -> setLedSwitch() + + ilLiveV2OperateLayout.btnLiveV2Issue -> showLiveIssue() + ilMapLiveV2IssueLayout.tvCloseIssueBtn -> showLiveIssue() + ilLiveV2BluetoothFindDevice.ivLiveV2FindDeviceSound -> setSound() + ilLiveV3MapDeviceBatteryLayout.ivDeviceCloseBtn -> llLiveV3MapDeviceBatteryLayout.visibility = + View.INVISIBLE + + ilLiveV3MapDeviceMsg.ivDeviceMsgCloseBtn -> ilLiveV3MapDeviceMsg.root.visibility = + View.GONE + } + } + } + + override fun onDestroy() { + super.onDestroy() + mViewBinding.lavLiveV2StateAnim.cancelAnimation() +// stopLive() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/abbidot/tracker/ui/common/map/HomeMapCommonV3.kt b/app/src/main/java/com/abbidot/tracker/ui/common/map/HomeMapCommonV3.kt new file mode 100644 index 0000000..ad7e34a --- /dev/null +++ b/app/src/main/java/com/abbidot/tracker/ui/common/map/HomeMapCommonV3.kt @@ -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) { + 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) +// } +// } + +} \ No newline at end of file diff --git a/app/src/main/java/com/abbidot/tracker/ui/fragment/map/MapV3Fragment.kt b/app/src/main/java/com/abbidot/tracker/ui/fragment/map/MapV3Fragment.kt index 53205ba..e47aceb 100644 --- a/app/src/main/java/com/abbidot/tracker/ui/fragment/map/MapV3Fragment.kt +++ b/app/src/main/java/com/abbidot/tracker/ui/fragment/map/MapV3Fragment.kt @@ -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::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 private lateinit var mDeviceStateAdapter: HomeMapDeviceStateAdapter - private lateinit var mDeviceMsgList: MutableList - private lateinit var mDeviceMsgAdapter: HomeMapDeviceMsgAdapter +// private lateinit var mDeviceMsgList: MutableList +// private lateinit var mDeviceMsgAdapter: HomeMapDeviceMsgAdapter //启动移动地图摄像机 private var isMoveCamera = true @@ -113,7 +112,10 @@ class MapV3Fragment : BaseFragment(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::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::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::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::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::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::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::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::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::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::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::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::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::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::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 + } } } diff --git a/app/src/main/java/com/abbidot/tracker/ui/fragment/map/googlemap/BaseGoogleMapFragment.kt b/app/src/main/java/com/abbidot/tracker/ui/fragment/map/googlemap/BaseGoogleMapFragment.kt index c4d5889..c27aa11 100644 --- a/app/src/main/java/com/abbidot/tracker/ui/fragment/map/googlemap/BaseGoogleMapFragment.kt +++ b/app/src/main/java/com/abbidot/tracker/ui/fragment/map/googlemap/BaseGoogleMapFragment.kt @@ -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 + ) + } + } + /** * 设置地图网络类型显示位置 */ diff --git a/app/src/main/java/com/abbidot/tracker/ui/fragment/map/googlemap/HomeMapGoogleMapFragmentV3.kt b/app/src/main/java/com/abbidot/tracker/ui/fragment/map/googlemap/HomeMapGoogleMapFragmentV3.kt new file mode 100644 index 0000000..6e939a1 --- /dev/null +++ b/app/src/main/java/com/abbidot/tracker/ui/fragment/map/googlemap/HomeMapGoogleMapFragmentV3.kt @@ -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() + 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) { + val latLngList = mutableListOf() + 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() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/abbidot/tracker/util/ViewUtil.kt b/app/src/main/java/com/abbidot/tracker/util/ViewUtil.kt index 8de9828..1b253a3 100644 --- a/app/src/main/java/com/abbidot/tracker/util/ViewUtil.kt +++ b/app/src/main/java/com/abbidot/tracker/util/ViewUtil.kt @@ -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 } } \ No newline at end of file diff --git a/app/src/main/java/com/abbidot/tracker/vm/MapViewModel.kt b/app/src/main/java/com/abbidot/tracker/vm/MapViewModel.kt index 2a831a8..c1b25c2 100644 --- a/app/src/main/java/com/abbidot/tracker/vm/MapViewModel.kt +++ b/app/src/main/java/com/abbidot/tracker/vm/MapViewModel.kt @@ -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, + deviceStateAdapter: BaseRecyclerAdapter, + ) { + 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 + ) + } + } + /** * 停止获取数据 */ diff --git a/app/src/main/java/com/abbidot/tracker/widget/MapBatteryView.kt b/app/src/main/java/com/abbidot/tracker/widget/MapBatteryView.kt deleted file mode 100644 index 38fb2ac..0000000 --- a/app/src/main/java/com/abbidot/tracker/widget/MapBatteryView.kt +++ /dev/null @@ -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() - } -} \ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi/icon_charge_image.png b/app/src/main/res/drawable-xhdpi/icon_charge_image.png new file mode 100644 index 0000000..180c924 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_charge_image.png differ diff --git a/app/src/main/res/drawable-xhdpi/icon_low_battery_image.png b/app/src/main/res/drawable-xhdpi/icon_low_battery_image.png new file mode 100644 index 0000000..d89a6a7 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_low_battery_image.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_charge_image.png b/app/src/main/res/drawable-xxhdpi/icon_charge_image.png new file mode 100644 index 0000000..ec97750 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_charge_image.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_low_battery_image.png b/app/src/main/res/drawable-xxhdpi/icon_low_battery_image.png new file mode 100644 index 0000000..d1c94b6 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_low_battery_image.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/icon_charge_image.png b/app/src/main/res/drawable-xxxhdpi/icon_charge_image.png new file mode 100644 index 0000000..564d77b Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_charge_image.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/icon_low_battery_image.png b/app/src/main/res/drawable-xxxhdpi/icon_low_battery_image.png new file mode 100644 index 0000000..5a45f97 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_low_battery_image.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/icon_white_trigon.png b/app/src/main/res/drawable-xxxhdpi/icon_white_trigon.png new file mode 100644 index 0000000..e0742b2 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_white_trigon.png differ diff --git a/app/src/main/res/drawable/shape16_light_green_color_bg.xml b/app/src/main/res/drawable/shape16_light_green_color_bg.xml new file mode 100644 index 0000000..fc75cb9 --- /dev/null +++ b/app/src/main/res/drawable/shape16_light_green_color_bg.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/app/src/main/res/layout/activity_live_v3.xml b/app/src/main/res/layout/activity_live_v3.xml new file mode 100644 index 0000000..b726390 --- /dev/null +++ b/app/src/main/res/layout/activity_live_v3.xml @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_map_v3.xml b/app/src/main/res/layout/fragment_map_v3.xml index a76f0cc..1914d67 100644 --- a/app/src/main/res/layout/fragment_map_v3.xml +++ b/app/src/main/res/layout/fragment_map_v3.xml @@ -10,10 +10,17 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - + + + + + - + android:layout_marginTop="@dimen/dp_6" + android:visibility="gone" /> + android:layout_marginBottom="@dimen/dp_38" + android:visibility="invisible" /> + android:visibility="invisible"> - @@ -9,11 +9,22 @@ - + + + + diff --git a/app/src/main/res/layout/layout_map_device_battery.xml b/app/src/main/res/layout/layout_map_device_battery.xml new file mode 100644 index 0000000..71a45b7 --- /dev/null +++ b/app/src/main/res/layout/layout_map_device_battery.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_pet_location_info.xml b/app/src/main/res/layout/layout_pet_location_info.xml index c91b0e3..739b6e1 100644 --- a/app/src/main/res/layout/layout_pet_location_info.xml +++ b/app/src/main/res/layout/layout_pet_location_info.xml @@ -18,6 +18,7 @@ hours Searching… Keep tracker on and nearby to scan. - Battery less than %s%% + Less than %s%% Outside Inside 7 Days Avg. @@ -1050,5 +1050,8 @@ The program has an exception and is about to exit Activate Subscription + Powered off + Near %s + Charging \ No newline at end of file diff --git a/baselibrary/src/main/java/com/abbidot/baselibrary/util/Utils.kt b/baselibrary/src/main/java/com/abbidot/baselibrary/util/Utils.kt index fc161ee..1946d50 100644 --- a/baselibrary/src/main/java/com/abbidot/baselibrary/util/Utils.kt +++ b/baselibrary/src/main/java/com/abbidot/baselibrary/util/Utils.kt @@ -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"