diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 529403a..8908a3e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,7 +55,7 @@ - + - + +) : FragmentPagerAdapter(manager) { + + override fun getItem(position: Int): Fragment = pages[position] + + override fun getCount(): Int = pages.size + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + //注释掉父类方法,一直不销毁Fragment + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 529403a..8908a3e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,7 +55,7 @@ - + +) : FragmentPagerAdapter(manager) { + + override fun getItem(position: Int): Fragment = pages[position] + + override fun getCount(): Int = pages.size + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + //注释掉父类方法,一直不销毁Fragment + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt deleted file mode 100644 index ab6743f..0000000 --- a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt +++ /dev/null @@ -1,387 +0,0 @@ -package com.casic.smarttube.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.CoordinateConverter -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.Marker -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.FragmentHomeBinding -import com.casic.smarttube.model.MapDeviceModel -import com.casic.smarttube.model.ProjectGroupModel -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.view.AddDeviceActivity -import com.casic.smarttube.vm.DeviceViewModel -import com.casic.smarttube.vm.ProjectGroupViewModel -import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter -import com.pengxh.kt.lite.adapter.ViewHolder -import com.pengxh.kt.lite.base.KotlinBaseFragment -import com.pengxh.kt.lite.extensions.navigatePageTo -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView -import com.pengxh.kt.lite.widget.dialog.AlertControlDialog - - -class HomePageFragment : KotlinBaseFragment(), AMap.OnCameraChangeListener, - AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener, - AMap.OnMapClickListener { - - private val kTag = "HomePageFragment" - private val geocoderSearch by lazy { GeocodeSearch(requireContext()) } - private lateinit var aMap: AMap - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var groupViewModel: ProjectGroupViewModel - private lateinit var groupListAdapter: NormalRecyclerAdapter - private var clickedMarker: Marker? = null - - /** - * 自定义Marker弹出框 - * */ - private var infoView: View? = null - - /** - * 所有设备列表信息集合 - * */ - private var deviceModels: MutableList = ArrayList() - - override fun initViewBinding( - inflater: LayoutInflater, container: ViewGroup? - ): FragmentHomeBinding { - return FragmentHomeBinding.inflate(inflater, container, false) - } - - override fun setupTopBarLayout() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - - } - - override fun onRightClick() { - requireContext().navigatePageTo() - } - }) - } - - override fun observeRequestState() { - groupViewModel.loadState.observe(this) { state -> - when (state) { - LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - //地图初始化 - initMap(savedInstanceState) - - //默认显示所有设备 - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - deviceViewModel.mapDeviceModel.observe(this) { - if (it.code == 200) { - val allMarkerOptions = ArrayList() - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //缓存所有设备详情,点击Marker时候需要 - deviceModels.add(device) - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - //将所有设备信息转化缓存为Marker点 - allMarkerOptions.add( - MarkerOptions().position(LatLng(latitude, longitude)) - .title(device.devcode).snippet(device.modelName) - ) - } - } - } - - allMarkerOptions.forEach { marker -> - aMap.addMarker(marker) - } - - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate, 1500, null) - } - } - deviceViewModel.getMapDeviceList() - - groupViewModel = ViewModelProvider(this)[ProjectGroupViewModel::class.java] - groupViewModel.groupModel.observe(this) { - if (it.code == 200) { - bindRecyclerView(it) - } - } - - groupViewModel.groupDeviceModel.observe(this) { - if (it.code == 200) { - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - } - } - } - //计算所有点的中心点位置 - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate) - } - } - } - - private fun bindRecyclerView(it: ProjectGroupModel) { - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - binding.homeRecyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - // 根据groupId查询组下设备 - groupViewModel.getDeviceListByGroup(item.groupId) - } - }) - } - - override fun initEvent() { - - } - - private fun initMap(savedInstanceState: Bundle?) { - binding.mapView.onCreate(savedInstanceState) - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 - - // 地图缩放监听 - aMap.addOnCameraChangeListener(this) - // marker 点击事件监听 - aMap.addOnMarkerClickListener(this) - // 点击marker弹出自定义popup - aMap.setInfoWindowAdapter(this) - //信息窗点击事件 - aMap.addOnInfoWindowClickListener(this) - //地图点击事件,用于隐藏infoWindow - aMap.setOnMapClickListener(this) - } - - override fun onCameraChange(cameraPosition: CameraPosition?) { - - } - - //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker - override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { - - } - - override fun onMarkerClick(marker: Marker?): Boolean { - marker?.apply { - clickedMarker = this - if (isInfoWindowShown) { - hideInfoWindow() - } else { - showInfoWindow() - } - } - return true - } - - override fun onMapClick(p0: LatLng?) { - clickedMarker?.apply { - if (isInfoWindowShown) { - hideInfoWindow() - } - } - } - - override fun getInfoWindow(marker: Marker?): View? { - if (infoView == null) { - infoView = LayoutInflater.from(requireContext()).inflate( - R.layout.popu_map_info, null - ) - } - marker?.apply { - renderWindow(this, infoView!!) - } - return infoView - } - - private fun renderWindow(marker: Marker, view: View) { - //反射得到popup里面的控件对象 - val deviceCodeView = view.findViewById(R.id.deviceCodeView) - val deviceModelView = view.findViewById(R.id.deviceModelView) - val deviceValueView = view.findViewById(R.id.deviceValueView) - val updateTimeView = view.findViewById(R.id.updateTimeView) - val locationView = view.findViewById(R.id.locationView) - - //绑定数据 - val clicked = marker.position - deviceModels.forEach { device -> - if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { - deviceCodeView.text = String.format("设备编号: ${device.devcode}") - deviceModelView.text = String.format("设备模型: ${device.modelName}") - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(requireActivity()) { - if (it.code == 200) { - deviceValueView.text = String.format("最新浓度: ${it.data.strength}") - updateTimeView.text = String.format("更新时间: ${it.data.uptime}") - } else { - deviceValueView.text = String.format("最新浓度: 未知") - updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - locationView.text = "经纬度异常,无法查看具体位置" - } else { - val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - val address = result?.regeocodeAddress?.formatAddress - val temp = StringBuilder() - if (address!!.length > 16) { - temp.append(address.substring(0, 14)).append("\r\n") - .append(address.substring(16)) - } else { - temp.append(address) - } - locationView.text = String.format("详细位置: $temp") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - } - - /** - * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 - * */ - override fun getInfoContents(p0: Marker?): View? = null - - override fun onInfoWindowClick(marker: Marker?) { - marker?.apply { - AlertControlDialog.Builder().setContext(requireContext()).setTitle("操作提示") - .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - val lat = position.latitude.toString() - val lng = position.longitude.toString() - if (lat.isBlank() || lng.isBlank()) { - "窨井经纬度异常,无法开启导航".show(requireContext()) - return - } - RouteOnMap.startNavigation(requireContext(), snippet, position) - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - - /***以下是地图生命周期管理************************************************************************/ - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - groupViewModel.getProGroupList() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } - - override fun onDestroy() { - super.onDestroy() - binding.mapView.onDestroy() - } -} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 529403a..8908a3e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,7 +55,7 @@ - + +) : FragmentPagerAdapter(manager) { + + override fun getItem(position: Int): Fragment = pages[position] + + override fun getCount(): Int = pages.size + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + //注释掉父类方法,一直不销毁Fragment + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt deleted file mode 100644 index ab6743f..0000000 --- a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt +++ /dev/null @@ -1,387 +0,0 @@ -package com.casic.smarttube.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.CoordinateConverter -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.Marker -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.FragmentHomeBinding -import com.casic.smarttube.model.MapDeviceModel -import com.casic.smarttube.model.ProjectGroupModel -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.view.AddDeviceActivity -import com.casic.smarttube.vm.DeviceViewModel -import com.casic.smarttube.vm.ProjectGroupViewModel -import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter -import com.pengxh.kt.lite.adapter.ViewHolder -import com.pengxh.kt.lite.base.KotlinBaseFragment -import com.pengxh.kt.lite.extensions.navigatePageTo -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView -import com.pengxh.kt.lite.widget.dialog.AlertControlDialog - - -class HomePageFragment : KotlinBaseFragment(), AMap.OnCameraChangeListener, - AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener, - AMap.OnMapClickListener { - - private val kTag = "HomePageFragment" - private val geocoderSearch by lazy { GeocodeSearch(requireContext()) } - private lateinit var aMap: AMap - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var groupViewModel: ProjectGroupViewModel - private lateinit var groupListAdapter: NormalRecyclerAdapter - private var clickedMarker: Marker? = null - - /** - * 自定义Marker弹出框 - * */ - private var infoView: View? = null - - /** - * 所有设备列表信息集合 - * */ - private var deviceModels: MutableList = ArrayList() - - override fun initViewBinding( - inflater: LayoutInflater, container: ViewGroup? - ): FragmentHomeBinding { - return FragmentHomeBinding.inflate(inflater, container, false) - } - - override fun setupTopBarLayout() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - - } - - override fun onRightClick() { - requireContext().navigatePageTo() - } - }) - } - - override fun observeRequestState() { - groupViewModel.loadState.observe(this) { state -> - when (state) { - LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - //地图初始化 - initMap(savedInstanceState) - - //默认显示所有设备 - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - deviceViewModel.mapDeviceModel.observe(this) { - if (it.code == 200) { - val allMarkerOptions = ArrayList() - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //缓存所有设备详情,点击Marker时候需要 - deviceModels.add(device) - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - //将所有设备信息转化缓存为Marker点 - allMarkerOptions.add( - MarkerOptions().position(LatLng(latitude, longitude)) - .title(device.devcode).snippet(device.modelName) - ) - } - } - } - - allMarkerOptions.forEach { marker -> - aMap.addMarker(marker) - } - - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate, 1500, null) - } - } - deviceViewModel.getMapDeviceList() - - groupViewModel = ViewModelProvider(this)[ProjectGroupViewModel::class.java] - groupViewModel.groupModel.observe(this) { - if (it.code == 200) { - bindRecyclerView(it) - } - } - - groupViewModel.groupDeviceModel.observe(this) { - if (it.code == 200) { - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - } - } - } - //计算所有点的中心点位置 - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate) - } - } - } - - private fun bindRecyclerView(it: ProjectGroupModel) { - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - binding.homeRecyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - // 根据groupId查询组下设备 - groupViewModel.getDeviceListByGroup(item.groupId) - } - }) - } - - override fun initEvent() { - - } - - private fun initMap(savedInstanceState: Bundle?) { - binding.mapView.onCreate(savedInstanceState) - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 - - // 地图缩放监听 - aMap.addOnCameraChangeListener(this) - // marker 点击事件监听 - aMap.addOnMarkerClickListener(this) - // 点击marker弹出自定义popup - aMap.setInfoWindowAdapter(this) - //信息窗点击事件 - aMap.addOnInfoWindowClickListener(this) - //地图点击事件,用于隐藏infoWindow - aMap.setOnMapClickListener(this) - } - - override fun onCameraChange(cameraPosition: CameraPosition?) { - - } - - //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker - override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { - - } - - override fun onMarkerClick(marker: Marker?): Boolean { - marker?.apply { - clickedMarker = this - if (isInfoWindowShown) { - hideInfoWindow() - } else { - showInfoWindow() - } - } - return true - } - - override fun onMapClick(p0: LatLng?) { - clickedMarker?.apply { - if (isInfoWindowShown) { - hideInfoWindow() - } - } - } - - override fun getInfoWindow(marker: Marker?): View? { - if (infoView == null) { - infoView = LayoutInflater.from(requireContext()).inflate( - R.layout.popu_map_info, null - ) - } - marker?.apply { - renderWindow(this, infoView!!) - } - return infoView - } - - private fun renderWindow(marker: Marker, view: View) { - //反射得到popup里面的控件对象 - val deviceCodeView = view.findViewById(R.id.deviceCodeView) - val deviceModelView = view.findViewById(R.id.deviceModelView) - val deviceValueView = view.findViewById(R.id.deviceValueView) - val updateTimeView = view.findViewById(R.id.updateTimeView) - val locationView = view.findViewById(R.id.locationView) - - //绑定数据 - val clicked = marker.position - deviceModels.forEach { device -> - if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { - deviceCodeView.text = String.format("设备编号: ${device.devcode}") - deviceModelView.text = String.format("设备模型: ${device.modelName}") - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(requireActivity()) { - if (it.code == 200) { - deviceValueView.text = String.format("最新浓度: ${it.data.strength}") - updateTimeView.text = String.format("更新时间: ${it.data.uptime}") - } else { - deviceValueView.text = String.format("最新浓度: 未知") - updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - locationView.text = "经纬度异常,无法查看具体位置" - } else { - val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - val address = result?.regeocodeAddress?.formatAddress - val temp = StringBuilder() - if (address!!.length > 16) { - temp.append(address.substring(0, 14)).append("\r\n") - .append(address.substring(16)) - } else { - temp.append(address) - } - locationView.text = String.format("详细位置: $temp") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - } - - /** - * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 - * */ - override fun getInfoContents(p0: Marker?): View? = null - - override fun onInfoWindowClick(marker: Marker?) { - marker?.apply { - AlertControlDialog.Builder().setContext(requireContext()).setTitle("操作提示") - .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - val lat = position.latitude.toString() - val lng = position.longitude.toString() - if (lat.isBlank() || lng.isBlank()) { - "窨井经纬度异常,无法开启导航".show(requireContext()) - return - } - RouteOnMap.startNavigation(requireContext(), snippet, position) - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - - /***以下是地图生命周期管理************************************************************************/ - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - groupViewModel.getProGroupList() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } - - override fun onDestroy() { - super.onDestroy() - binding.mapView.onDestroy() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt index 1d0aa3d..dd09cf5 100644 --- a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt +++ b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt @@ -15,12 +15,16 @@ import com.casic.smarttube.databinding.FragmentOverviewBinding import com.casic.smarttube.model.ProjectGroupModel import com.casic.smarttube.view.GroupDeviceActivity +import com.casic.smarttube.view.GroupDeviceMapActivity import com.casic.smarttube.vm.ProjectGroupViewModel import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseFragment import com.pengxh.kt.lite.divider.RecyclerViewItemDivider import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.EmptyView import com.pengxh.kt.lite.widget.TitleBarView import com.pengxh.kt.lite.widget.dialog.AlertInputDialog @@ -32,6 +36,7 @@ private lateinit var groupViewModel: ProjectGroupViewModel private lateinit var groupListAdapter: NormalRecyclerAdapter private var clickedPosition = 0 + private var isRefresh = false override fun initViewBinding( inflater: LayoutInflater, container: ViewGroup? @@ -40,7 +45,15 @@ } override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + } + + override fun onRightClick() { + requireContext().navigatePageTo() + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { @@ -55,66 +68,93 @@ groupListAdapter.notifyItemChanged(clickedPosition) } } - groupViewModel.getGroupList() + } + + override fun onResume() { + super.onResume() + groupViewModel.getProGroupList() } private fun bindRecyclerView(it: ProjectGroupModel) { val dataRows = it.data - if (dataRows.size == 0) { - binding.emptyView.visibility = View.VISIBLE - binding.recyclerView.visibility = View.GONE - } else { - binding.emptyView.visibility = View.GONE - binding.recyclerView.visibility = View.VISIBLE + when { + isRefresh -> { + binding.refreshView.finishRefresh() + isRefresh = false + groupListAdapter.refresh(dataRows) + } - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_over_view_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - .setOnClickListener(R.id.editGroupNameView) { - clickedPosition = position - editGroupName(item) - } - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) + else -> { + if (dataRows.size == 0) { + binding.emptyView.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE + } else { + binding.emptyView.visibility = View.GONE + binding.recyclerView.visibility = View.VISIBLE + + groupListAdapter = object : NormalRecyclerAdapter( + R.layout.item_group_over_view_rv_l, it.data + ) { + override fun convertView( + viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel + ) { + viewHolder.setText(R.id.groupNameView, item.groupId) + .setText(R.id.totalDeviceNumView, item.totalDevice) + .setText(R.id.inUseDeviceNumView, item.alive) + .setText(R.id.notUseDeviceNumView, item.unalive) + .setOnClickListener(R.id.editGroupNameView) { + clickedPosition = position + editGroupName(item) } - } + if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { + viewHolder.setText( + R.id.groupLocationView, + "经纬度异常,无法查看具体位置" + ) + } else { + val point = + LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched( + result: RegeocodeResult?, + rCode: Int + ) { + if (rCode == 1000) { + viewHolder.setText( + R.id.groupLocationView, + String.format("${result?.regeocodeAddress?.formatAddress}") + ) + } + } - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + override fun onGeocodeSearched( + result: GeocodeResult?, + rCode: Int + ) { + } + }) } - }) + } } + binding.recyclerView.addItemDecoration( + RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) + ) + binding.recyclerView.adapter = groupListAdapter + groupListAdapter.setOnItemClickedListener(object : + NormalRecyclerAdapter.OnItemClickedListener { + override fun onItemClicked( + position: Int, + item: ProjectGroupModel.DataModel + ) { + requireContext().navigatePageTo(item.groupId) + } + }) } } - binding.recyclerView.addItemDecoration( - RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) - ) - binding.recyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - requireContext().navigatePageTo(item.groupId) - } - }) } } @@ -139,18 +179,31 @@ } override fun observeRequestState() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - + groupViewModel.loadState.observe(this) { + if (isRefresh) { + return@observe } + when (it) { + LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中,请稍后...") - override fun onRightClick() { - groupViewModel.getProGroupList() + LoadState.Success -> { + LoadingDialog.dismiss() + } + + LoadState.Fail -> { + LoadingDialog.dismiss() + "数据加载失败,请重试".show(requireContext()) + } } - }) + } } override fun initEvent() { + binding.refreshView.setOnRefreshListener { + isRefresh = true + groupViewModel.getProGroupList() + } + binding.emptyView.setOnClickListener(object : EmptyView.OnClickListener { override fun onReloadButtonClicked() { groupViewModel.getProGroupList() diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 529403a..8908a3e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,7 +55,7 @@ - + +) : FragmentPagerAdapter(manager) { + + override fun getItem(position: Int): Fragment = pages[position] + + override fun getCount(): Int = pages.size + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + //注释掉父类方法,一直不销毁Fragment + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt deleted file mode 100644 index ab6743f..0000000 --- a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt +++ /dev/null @@ -1,387 +0,0 @@ -package com.casic.smarttube.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.CoordinateConverter -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.Marker -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.FragmentHomeBinding -import com.casic.smarttube.model.MapDeviceModel -import com.casic.smarttube.model.ProjectGroupModel -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.view.AddDeviceActivity -import com.casic.smarttube.vm.DeviceViewModel -import com.casic.smarttube.vm.ProjectGroupViewModel -import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter -import com.pengxh.kt.lite.adapter.ViewHolder -import com.pengxh.kt.lite.base.KotlinBaseFragment -import com.pengxh.kt.lite.extensions.navigatePageTo -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView -import com.pengxh.kt.lite.widget.dialog.AlertControlDialog - - -class HomePageFragment : KotlinBaseFragment(), AMap.OnCameraChangeListener, - AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener, - AMap.OnMapClickListener { - - private val kTag = "HomePageFragment" - private val geocoderSearch by lazy { GeocodeSearch(requireContext()) } - private lateinit var aMap: AMap - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var groupViewModel: ProjectGroupViewModel - private lateinit var groupListAdapter: NormalRecyclerAdapter - private var clickedMarker: Marker? = null - - /** - * 自定义Marker弹出框 - * */ - private var infoView: View? = null - - /** - * 所有设备列表信息集合 - * */ - private var deviceModels: MutableList = ArrayList() - - override fun initViewBinding( - inflater: LayoutInflater, container: ViewGroup? - ): FragmentHomeBinding { - return FragmentHomeBinding.inflate(inflater, container, false) - } - - override fun setupTopBarLayout() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - - } - - override fun onRightClick() { - requireContext().navigatePageTo() - } - }) - } - - override fun observeRequestState() { - groupViewModel.loadState.observe(this) { state -> - when (state) { - LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - //地图初始化 - initMap(savedInstanceState) - - //默认显示所有设备 - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - deviceViewModel.mapDeviceModel.observe(this) { - if (it.code == 200) { - val allMarkerOptions = ArrayList() - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //缓存所有设备详情,点击Marker时候需要 - deviceModels.add(device) - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - //将所有设备信息转化缓存为Marker点 - allMarkerOptions.add( - MarkerOptions().position(LatLng(latitude, longitude)) - .title(device.devcode).snippet(device.modelName) - ) - } - } - } - - allMarkerOptions.forEach { marker -> - aMap.addMarker(marker) - } - - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate, 1500, null) - } - } - deviceViewModel.getMapDeviceList() - - groupViewModel = ViewModelProvider(this)[ProjectGroupViewModel::class.java] - groupViewModel.groupModel.observe(this) { - if (it.code == 200) { - bindRecyclerView(it) - } - } - - groupViewModel.groupDeviceModel.observe(this) { - if (it.code == 200) { - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - } - } - } - //计算所有点的中心点位置 - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate) - } - } - } - - private fun bindRecyclerView(it: ProjectGroupModel) { - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - binding.homeRecyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - // 根据groupId查询组下设备 - groupViewModel.getDeviceListByGroup(item.groupId) - } - }) - } - - override fun initEvent() { - - } - - private fun initMap(savedInstanceState: Bundle?) { - binding.mapView.onCreate(savedInstanceState) - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 - - // 地图缩放监听 - aMap.addOnCameraChangeListener(this) - // marker 点击事件监听 - aMap.addOnMarkerClickListener(this) - // 点击marker弹出自定义popup - aMap.setInfoWindowAdapter(this) - //信息窗点击事件 - aMap.addOnInfoWindowClickListener(this) - //地图点击事件,用于隐藏infoWindow - aMap.setOnMapClickListener(this) - } - - override fun onCameraChange(cameraPosition: CameraPosition?) { - - } - - //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker - override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { - - } - - override fun onMarkerClick(marker: Marker?): Boolean { - marker?.apply { - clickedMarker = this - if (isInfoWindowShown) { - hideInfoWindow() - } else { - showInfoWindow() - } - } - return true - } - - override fun onMapClick(p0: LatLng?) { - clickedMarker?.apply { - if (isInfoWindowShown) { - hideInfoWindow() - } - } - } - - override fun getInfoWindow(marker: Marker?): View? { - if (infoView == null) { - infoView = LayoutInflater.from(requireContext()).inflate( - R.layout.popu_map_info, null - ) - } - marker?.apply { - renderWindow(this, infoView!!) - } - return infoView - } - - private fun renderWindow(marker: Marker, view: View) { - //反射得到popup里面的控件对象 - val deviceCodeView = view.findViewById(R.id.deviceCodeView) - val deviceModelView = view.findViewById(R.id.deviceModelView) - val deviceValueView = view.findViewById(R.id.deviceValueView) - val updateTimeView = view.findViewById(R.id.updateTimeView) - val locationView = view.findViewById(R.id.locationView) - - //绑定数据 - val clicked = marker.position - deviceModels.forEach { device -> - if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { - deviceCodeView.text = String.format("设备编号: ${device.devcode}") - deviceModelView.text = String.format("设备模型: ${device.modelName}") - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(requireActivity()) { - if (it.code == 200) { - deviceValueView.text = String.format("最新浓度: ${it.data.strength}") - updateTimeView.text = String.format("更新时间: ${it.data.uptime}") - } else { - deviceValueView.text = String.format("最新浓度: 未知") - updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - locationView.text = "经纬度异常,无法查看具体位置" - } else { - val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - val address = result?.regeocodeAddress?.formatAddress - val temp = StringBuilder() - if (address!!.length > 16) { - temp.append(address.substring(0, 14)).append("\r\n") - .append(address.substring(16)) - } else { - temp.append(address) - } - locationView.text = String.format("详细位置: $temp") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - } - - /** - * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 - * */ - override fun getInfoContents(p0: Marker?): View? = null - - override fun onInfoWindowClick(marker: Marker?) { - marker?.apply { - AlertControlDialog.Builder().setContext(requireContext()).setTitle("操作提示") - .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - val lat = position.latitude.toString() - val lng = position.longitude.toString() - if (lat.isBlank() || lng.isBlank()) { - "窨井经纬度异常,无法开启导航".show(requireContext()) - return - } - RouteOnMap.startNavigation(requireContext(), snippet, position) - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - - /***以下是地图生命周期管理************************************************************************/ - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - groupViewModel.getProGroupList() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } - - override fun onDestroy() { - super.onDestroy() - binding.mapView.onDestroy() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt index 1d0aa3d..dd09cf5 100644 --- a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt +++ b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt @@ -15,12 +15,16 @@ import com.casic.smarttube.databinding.FragmentOverviewBinding import com.casic.smarttube.model.ProjectGroupModel import com.casic.smarttube.view.GroupDeviceActivity +import com.casic.smarttube.view.GroupDeviceMapActivity import com.casic.smarttube.vm.ProjectGroupViewModel import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseFragment import com.pengxh.kt.lite.divider.RecyclerViewItemDivider import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.EmptyView import com.pengxh.kt.lite.widget.TitleBarView import com.pengxh.kt.lite.widget.dialog.AlertInputDialog @@ -32,6 +36,7 @@ private lateinit var groupViewModel: ProjectGroupViewModel private lateinit var groupListAdapter: NormalRecyclerAdapter private var clickedPosition = 0 + private var isRefresh = false override fun initViewBinding( inflater: LayoutInflater, container: ViewGroup? @@ -40,7 +45,15 @@ } override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + } + + override fun onRightClick() { + requireContext().navigatePageTo() + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { @@ -55,66 +68,93 @@ groupListAdapter.notifyItemChanged(clickedPosition) } } - groupViewModel.getGroupList() + } + + override fun onResume() { + super.onResume() + groupViewModel.getProGroupList() } private fun bindRecyclerView(it: ProjectGroupModel) { val dataRows = it.data - if (dataRows.size == 0) { - binding.emptyView.visibility = View.VISIBLE - binding.recyclerView.visibility = View.GONE - } else { - binding.emptyView.visibility = View.GONE - binding.recyclerView.visibility = View.VISIBLE + when { + isRefresh -> { + binding.refreshView.finishRefresh() + isRefresh = false + groupListAdapter.refresh(dataRows) + } - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_over_view_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - .setOnClickListener(R.id.editGroupNameView) { - clickedPosition = position - editGroupName(item) - } - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) + else -> { + if (dataRows.size == 0) { + binding.emptyView.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE + } else { + binding.emptyView.visibility = View.GONE + binding.recyclerView.visibility = View.VISIBLE + + groupListAdapter = object : NormalRecyclerAdapter( + R.layout.item_group_over_view_rv_l, it.data + ) { + override fun convertView( + viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel + ) { + viewHolder.setText(R.id.groupNameView, item.groupId) + .setText(R.id.totalDeviceNumView, item.totalDevice) + .setText(R.id.inUseDeviceNumView, item.alive) + .setText(R.id.notUseDeviceNumView, item.unalive) + .setOnClickListener(R.id.editGroupNameView) { + clickedPosition = position + editGroupName(item) } - } + if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { + viewHolder.setText( + R.id.groupLocationView, + "经纬度异常,无法查看具体位置" + ) + } else { + val point = + LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched( + result: RegeocodeResult?, + rCode: Int + ) { + if (rCode == 1000) { + viewHolder.setText( + R.id.groupLocationView, + String.format("${result?.regeocodeAddress?.formatAddress}") + ) + } + } - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + override fun onGeocodeSearched( + result: GeocodeResult?, + rCode: Int + ) { + } + }) } - }) + } } + binding.recyclerView.addItemDecoration( + RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) + ) + binding.recyclerView.adapter = groupListAdapter + groupListAdapter.setOnItemClickedListener(object : + NormalRecyclerAdapter.OnItemClickedListener { + override fun onItemClicked( + position: Int, + item: ProjectGroupModel.DataModel + ) { + requireContext().navigatePageTo(item.groupId) + } + }) } } - binding.recyclerView.addItemDecoration( - RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) - ) - binding.recyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - requireContext().navigatePageTo(item.groupId) - } - }) } } @@ -139,18 +179,31 @@ } override fun observeRequestState() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - + groupViewModel.loadState.observe(this) { + if (isRefresh) { + return@observe } + when (it) { + LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中,请稍后...") - override fun onRightClick() { - groupViewModel.getProGroupList() + LoadState.Success -> { + LoadingDialog.dismiss() + } + + LoadState.Fail -> { + LoadingDialog.dismiss() + "数据加载失败,请重试".show(requireContext()) + } } - }) + } } override fun initEvent() { + binding.refreshView.setOnRefreshListener { + isRefresh = true + groupViewModel.getProGroupList() + } + binding.emptyView.setOnClickListener(object : EmptyView.OnClickListener { override fun onReloadButtonClicked() { groupViewModel.getProGroupList() diff --git a/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt new file mode 100644 index 0000000..c33c40e --- /dev/null +++ b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt @@ -0,0 +1,288 @@ +package com.casic.smarttube.view + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.lifecycle.ViewModelProvider +import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.CameraUpdateFactory +import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.CameraPosition +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.Marker +import com.amap.api.maps.model.MarkerOptions +import com.amap.api.services.core.LatLonPoint +import com.amap.api.services.geocoder.GeocodeResult +import com.amap.api.services.geocoder.GeocodeSearch +import com.amap.api.services.geocoder.RegeocodeQuery +import com.amap.api.services.geocoder.RegeocodeResult +import com.casic.smarttube.R +import com.casic.smarttube.databinding.ActivityGroupDeviceMapBinding +import com.casic.smarttube.extensions.initImmersionBar +import com.casic.smarttube.model.MapDeviceModel +import com.casic.smarttube.utils.RouteOnMap +import com.casic.smarttube.vm.DeviceViewModel +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog + +class GroupDeviceMapActivity : KotlinBaseActivity(), + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, + AMap.OnInfoWindowClickListener, AMap.OnMapClickListener { + + private val context = this + private val geocoderSearch by lazy { GeocodeSearch(this) } + private lateinit var aMap: AMap + private lateinit var deviceViewModel: DeviceViewModel + private var clickedMarker: Marker? = null + + /** + * 自定义Marker弹出框 + * */ + private var infoView: View? = null + + /** + * 所有设备列表信息集合 + * */ + private var deviceModels: MutableList = ArrayList() + + override fun initViewBinding(): ActivityGroupDeviceMapBinding { + return ActivityGroupDeviceMapBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + } + + override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + //地图初始化 + initMap(savedInstanceState) + + //默认显示所有设备 + deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] + deviceViewModel.mapDeviceModel.observe(this) { + if (it.code == 200) { + val allMarkerOptions = ArrayList() + val latitudeList = ArrayList() + val longitudeList = ArrayList() + it.data.forEach { device -> + val lat = device.latGaode.toString() + val lng = device.lngGaode.toString() + if (lat.isNotBlank() && lng.isNotBlank()) { + //返回true代表当前位置在大陆、港澳地区,反之不在 + val latitude = lat.toDouble() + val longitude = lng.toDouble() + if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { + //缓存所有设备详情,点击Marker时候需要 + deviceModels.add(device) + //分别缓存经、纬度 + latitudeList.add(latitude) + longitudeList.add(longitude) + //将所有设备信息转化缓存为Marker点 + allMarkerOptions.add( + MarkerOptions().position(LatLng(latitude, longitude)) + .title(device.devcode).snippet(device.modelName) + ) + } + } + } + + allMarkerOptions.forEach { marker -> + aMap.addMarker(marker) + } + + val latLng = LatLng(latitudeList[0], longitudeList[0]) + val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) + val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) + aMap.animateCamera(cameraUpdate, 1500, null) + } + } + deviceViewModel.getMapDeviceList() + } + + override fun initEvent() { + + } + + private fun initMap(savedInstanceState: Bundle?) { + binding.mapView.onCreate(savedInstanceState) + aMap = binding.mapView.map + aMap.mapType = AMap.MAP_TYPE_NORMAL + val uiSettings = aMap.uiSettings + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 + + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker 点击事件监听 + aMap.addOnMarkerClickListener(this) + // 点击marker弹出自定义popup + aMap.setInfoWindowAdapter(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + //地图点击事件,用于隐藏infoWindow + aMap.setOnMapClickListener(this) + } + + override fun onCameraChange(cameraPosition: CameraPosition?) { + + } + + //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker + override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { + + } + + override fun onMarkerClick(marker: Marker?): Boolean { + marker?.apply { + clickedMarker = this + if (isInfoWindowShown) { + hideInfoWindow() + } else { + showInfoWindow() + } + } + return true + } + + override fun onMapClick(p0: LatLng?) { + clickedMarker?.apply { + if (isInfoWindowShown) { + hideInfoWindow() + } + } + } + + override fun getInfoWindow(marker: Marker?): View? { + if (infoView == null) { + infoView = LayoutInflater.from(this).inflate(R.layout.popu_map_info, null) + } + marker?.apply { + renderWindow(this, infoView!!) + } + return infoView + } + + private fun renderWindow(marker: Marker, view: View) { + //反射得到popup里面的控件对象 + val deviceCodeView = view.findViewById(R.id.deviceCodeView) + val deviceModelView = view.findViewById(R.id.deviceModelView) + val deviceValueView = view.findViewById(R.id.deviceValueView) + val updateTimeView = view.findViewById(R.id.updateTimeView) + val locationView = view.findViewById(R.id.locationView) + + //绑定数据 + val clicked = marker.position + deviceModels.forEach { device -> + if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { + deviceCodeView.text = String.format("设备编号: ${device.devcode}") + deviceModelView.text = String.format("设备模型: ${device.modelName}") + //获取设备最新浓度信息 + deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) + deviceViewModel.lastDataModel.observe(this) { + if (it.code == 200) { + deviceValueView.text = String.format("最新浓度: ${it.data.strength}") + updateTimeView.text = String.format("更新时间: ${it.data.uptime}") + } else { + deviceValueView.text = String.format("最新浓度: 未知") + updateTimeView.text = String.format("更新时间: 未知") + } + } + if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { + locationView.text = "经纬度异常,无法查看具体位置" + } else { + val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { + if (rCode == 1000) { + val address = result?.regeocodeAddress?.formatAddress + val temp = StringBuilder() + if (address!!.length > 16) { + temp.append(address.substring(0, 14)).append("\r\n") + .append(address.substring(16)) + } else { + temp.append(address) + } + locationView.text = String.format("详细位置: $temp") + } + } + + override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + + } + }) + } + } + } + } + + /** + * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 + * */ + override fun getInfoContents(p0: Marker?): View? = null + + override fun onInfoWindowClick(marker: Marker?) { + marker?.apply { + AlertControlDialog.Builder().setContext(context).setTitle("操作提示") + .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + val lat = position.latitude.toString() + val lng = position.longitude.toString() + if (lat.isBlank() || lng.isBlank()) { + "窨井经纬度异常,无法开启导航".show(context) + return + } + RouteOnMap.startNavigation(context, snippet, position) + } + + override fun onCancelClick() { + + } + }).build().show() + } + } + + /***以下是地图生命周期管理************************************************************************/ + + override fun onResume() { + super.onResume() + binding.mapView.onResume() + } + + override fun onPause() { + super.onPause() + binding.mapView.onPause() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + binding.mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + super.onDestroy() + binding.mapView.onDestroy() + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 529403a..8908a3e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,7 +55,7 @@ - + +) : FragmentPagerAdapter(manager) { + + override fun getItem(position: Int): Fragment = pages[position] + + override fun getCount(): Int = pages.size + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + //注释掉父类方法,一直不销毁Fragment + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt deleted file mode 100644 index ab6743f..0000000 --- a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt +++ /dev/null @@ -1,387 +0,0 @@ -package com.casic.smarttube.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.CoordinateConverter -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.Marker -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.FragmentHomeBinding -import com.casic.smarttube.model.MapDeviceModel -import com.casic.smarttube.model.ProjectGroupModel -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.view.AddDeviceActivity -import com.casic.smarttube.vm.DeviceViewModel -import com.casic.smarttube.vm.ProjectGroupViewModel -import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter -import com.pengxh.kt.lite.adapter.ViewHolder -import com.pengxh.kt.lite.base.KotlinBaseFragment -import com.pengxh.kt.lite.extensions.navigatePageTo -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView -import com.pengxh.kt.lite.widget.dialog.AlertControlDialog - - -class HomePageFragment : KotlinBaseFragment(), AMap.OnCameraChangeListener, - AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener, - AMap.OnMapClickListener { - - private val kTag = "HomePageFragment" - private val geocoderSearch by lazy { GeocodeSearch(requireContext()) } - private lateinit var aMap: AMap - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var groupViewModel: ProjectGroupViewModel - private lateinit var groupListAdapter: NormalRecyclerAdapter - private var clickedMarker: Marker? = null - - /** - * 自定义Marker弹出框 - * */ - private var infoView: View? = null - - /** - * 所有设备列表信息集合 - * */ - private var deviceModels: MutableList = ArrayList() - - override fun initViewBinding( - inflater: LayoutInflater, container: ViewGroup? - ): FragmentHomeBinding { - return FragmentHomeBinding.inflate(inflater, container, false) - } - - override fun setupTopBarLayout() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - - } - - override fun onRightClick() { - requireContext().navigatePageTo() - } - }) - } - - override fun observeRequestState() { - groupViewModel.loadState.observe(this) { state -> - when (state) { - LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - //地图初始化 - initMap(savedInstanceState) - - //默认显示所有设备 - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - deviceViewModel.mapDeviceModel.observe(this) { - if (it.code == 200) { - val allMarkerOptions = ArrayList() - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //缓存所有设备详情,点击Marker时候需要 - deviceModels.add(device) - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - //将所有设备信息转化缓存为Marker点 - allMarkerOptions.add( - MarkerOptions().position(LatLng(latitude, longitude)) - .title(device.devcode).snippet(device.modelName) - ) - } - } - } - - allMarkerOptions.forEach { marker -> - aMap.addMarker(marker) - } - - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate, 1500, null) - } - } - deviceViewModel.getMapDeviceList() - - groupViewModel = ViewModelProvider(this)[ProjectGroupViewModel::class.java] - groupViewModel.groupModel.observe(this) { - if (it.code == 200) { - bindRecyclerView(it) - } - } - - groupViewModel.groupDeviceModel.observe(this) { - if (it.code == 200) { - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - } - } - } - //计算所有点的中心点位置 - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate) - } - } - } - - private fun bindRecyclerView(it: ProjectGroupModel) { - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - binding.homeRecyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - // 根据groupId查询组下设备 - groupViewModel.getDeviceListByGroup(item.groupId) - } - }) - } - - override fun initEvent() { - - } - - private fun initMap(savedInstanceState: Bundle?) { - binding.mapView.onCreate(savedInstanceState) - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 - - // 地图缩放监听 - aMap.addOnCameraChangeListener(this) - // marker 点击事件监听 - aMap.addOnMarkerClickListener(this) - // 点击marker弹出自定义popup - aMap.setInfoWindowAdapter(this) - //信息窗点击事件 - aMap.addOnInfoWindowClickListener(this) - //地图点击事件,用于隐藏infoWindow - aMap.setOnMapClickListener(this) - } - - override fun onCameraChange(cameraPosition: CameraPosition?) { - - } - - //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker - override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { - - } - - override fun onMarkerClick(marker: Marker?): Boolean { - marker?.apply { - clickedMarker = this - if (isInfoWindowShown) { - hideInfoWindow() - } else { - showInfoWindow() - } - } - return true - } - - override fun onMapClick(p0: LatLng?) { - clickedMarker?.apply { - if (isInfoWindowShown) { - hideInfoWindow() - } - } - } - - override fun getInfoWindow(marker: Marker?): View? { - if (infoView == null) { - infoView = LayoutInflater.from(requireContext()).inflate( - R.layout.popu_map_info, null - ) - } - marker?.apply { - renderWindow(this, infoView!!) - } - return infoView - } - - private fun renderWindow(marker: Marker, view: View) { - //反射得到popup里面的控件对象 - val deviceCodeView = view.findViewById(R.id.deviceCodeView) - val deviceModelView = view.findViewById(R.id.deviceModelView) - val deviceValueView = view.findViewById(R.id.deviceValueView) - val updateTimeView = view.findViewById(R.id.updateTimeView) - val locationView = view.findViewById(R.id.locationView) - - //绑定数据 - val clicked = marker.position - deviceModels.forEach { device -> - if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { - deviceCodeView.text = String.format("设备编号: ${device.devcode}") - deviceModelView.text = String.format("设备模型: ${device.modelName}") - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(requireActivity()) { - if (it.code == 200) { - deviceValueView.text = String.format("最新浓度: ${it.data.strength}") - updateTimeView.text = String.format("更新时间: ${it.data.uptime}") - } else { - deviceValueView.text = String.format("最新浓度: 未知") - updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - locationView.text = "经纬度异常,无法查看具体位置" - } else { - val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - val address = result?.regeocodeAddress?.formatAddress - val temp = StringBuilder() - if (address!!.length > 16) { - temp.append(address.substring(0, 14)).append("\r\n") - .append(address.substring(16)) - } else { - temp.append(address) - } - locationView.text = String.format("详细位置: $temp") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - } - - /** - * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 - * */ - override fun getInfoContents(p0: Marker?): View? = null - - override fun onInfoWindowClick(marker: Marker?) { - marker?.apply { - AlertControlDialog.Builder().setContext(requireContext()).setTitle("操作提示") - .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - val lat = position.latitude.toString() - val lng = position.longitude.toString() - if (lat.isBlank() || lng.isBlank()) { - "窨井经纬度异常,无法开启导航".show(requireContext()) - return - } - RouteOnMap.startNavigation(requireContext(), snippet, position) - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - - /***以下是地图生命周期管理************************************************************************/ - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - groupViewModel.getProGroupList() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } - - override fun onDestroy() { - super.onDestroy() - binding.mapView.onDestroy() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt index 1d0aa3d..dd09cf5 100644 --- a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt +++ b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt @@ -15,12 +15,16 @@ import com.casic.smarttube.databinding.FragmentOverviewBinding import com.casic.smarttube.model.ProjectGroupModel import com.casic.smarttube.view.GroupDeviceActivity +import com.casic.smarttube.view.GroupDeviceMapActivity import com.casic.smarttube.vm.ProjectGroupViewModel import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseFragment import com.pengxh.kt.lite.divider.RecyclerViewItemDivider import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.EmptyView import com.pengxh.kt.lite.widget.TitleBarView import com.pengxh.kt.lite.widget.dialog.AlertInputDialog @@ -32,6 +36,7 @@ private lateinit var groupViewModel: ProjectGroupViewModel private lateinit var groupListAdapter: NormalRecyclerAdapter private var clickedPosition = 0 + private var isRefresh = false override fun initViewBinding( inflater: LayoutInflater, container: ViewGroup? @@ -40,7 +45,15 @@ } override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + } + + override fun onRightClick() { + requireContext().navigatePageTo() + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { @@ -55,66 +68,93 @@ groupListAdapter.notifyItemChanged(clickedPosition) } } - groupViewModel.getGroupList() + } + + override fun onResume() { + super.onResume() + groupViewModel.getProGroupList() } private fun bindRecyclerView(it: ProjectGroupModel) { val dataRows = it.data - if (dataRows.size == 0) { - binding.emptyView.visibility = View.VISIBLE - binding.recyclerView.visibility = View.GONE - } else { - binding.emptyView.visibility = View.GONE - binding.recyclerView.visibility = View.VISIBLE + when { + isRefresh -> { + binding.refreshView.finishRefresh() + isRefresh = false + groupListAdapter.refresh(dataRows) + } - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_over_view_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - .setOnClickListener(R.id.editGroupNameView) { - clickedPosition = position - editGroupName(item) - } - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) + else -> { + if (dataRows.size == 0) { + binding.emptyView.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE + } else { + binding.emptyView.visibility = View.GONE + binding.recyclerView.visibility = View.VISIBLE + + groupListAdapter = object : NormalRecyclerAdapter( + R.layout.item_group_over_view_rv_l, it.data + ) { + override fun convertView( + viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel + ) { + viewHolder.setText(R.id.groupNameView, item.groupId) + .setText(R.id.totalDeviceNumView, item.totalDevice) + .setText(R.id.inUseDeviceNumView, item.alive) + .setText(R.id.notUseDeviceNumView, item.unalive) + .setOnClickListener(R.id.editGroupNameView) { + clickedPosition = position + editGroupName(item) } - } + if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { + viewHolder.setText( + R.id.groupLocationView, + "经纬度异常,无法查看具体位置" + ) + } else { + val point = + LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched( + result: RegeocodeResult?, + rCode: Int + ) { + if (rCode == 1000) { + viewHolder.setText( + R.id.groupLocationView, + String.format("${result?.regeocodeAddress?.formatAddress}") + ) + } + } - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + override fun onGeocodeSearched( + result: GeocodeResult?, + rCode: Int + ) { + } + }) } - }) + } } + binding.recyclerView.addItemDecoration( + RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) + ) + binding.recyclerView.adapter = groupListAdapter + groupListAdapter.setOnItemClickedListener(object : + NormalRecyclerAdapter.OnItemClickedListener { + override fun onItemClicked( + position: Int, + item: ProjectGroupModel.DataModel + ) { + requireContext().navigatePageTo(item.groupId) + } + }) } } - binding.recyclerView.addItemDecoration( - RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) - ) - binding.recyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - requireContext().navigatePageTo(item.groupId) - } - }) } } @@ -139,18 +179,31 @@ } override fun observeRequestState() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - + groupViewModel.loadState.observe(this) { + if (isRefresh) { + return@observe } + when (it) { + LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中,请稍后...") - override fun onRightClick() { - groupViewModel.getProGroupList() + LoadState.Success -> { + LoadingDialog.dismiss() + } + + LoadState.Fail -> { + LoadingDialog.dismiss() + "数据加载失败,请重试".show(requireContext()) + } } - }) + } } override fun initEvent() { + binding.refreshView.setOnRefreshListener { + isRefresh = true + groupViewModel.getProGroupList() + } + binding.emptyView.setOnClickListener(object : EmptyView.OnClickListener { override fun onReloadButtonClicked() { groupViewModel.getProGroupList() diff --git a/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt new file mode 100644 index 0000000..c33c40e --- /dev/null +++ b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt @@ -0,0 +1,288 @@ +package com.casic.smarttube.view + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.lifecycle.ViewModelProvider +import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.CameraUpdateFactory +import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.CameraPosition +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.Marker +import com.amap.api.maps.model.MarkerOptions +import com.amap.api.services.core.LatLonPoint +import com.amap.api.services.geocoder.GeocodeResult +import com.amap.api.services.geocoder.GeocodeSearch +import com.amap.api.services.geocoder.RegeocodeQuery +import com.amap.api.services.geocoder.RegeocodeResult +import com.casic.smarttube.R +import com.casic.smarttube.databinding.ActivityGroupDeviceMapBinding +import com.casic.smarttube.extensions.initImmersionBar +import com.casic.smarttube.model.MapDeviceModel +import com.casic.smarttube.utils.RouteOnMap +import com.casic.smarttube.vm.DeviceViewModel +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog + +class GroupDeviceMapActivity : KotlinBaseActivity(), + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, + AMap.OnInfoWindowClickListener, AMap.OnMapClickListener { + + private val context = this + private val geocoderSearch by lazy { GeocodeSearch(this) } + private lateinit var aMap: AMap + private lateinit var deviceViewModel: DeviceViewModel + private var clickedMarker: Marker? = null + + /** + * 自定义Marker弹出框 + * */ + private var infoView: View? = null + + /** + * 所有设备列表信息集合 + * */ + private var deviceModels: MutableList = ArrayList() + + override fun initViewBinding(): ActivityGroupDeviceMapBinding { + return ActivityGroupDeviceMapBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + } + + override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + //地图初始化 + initMap(savedInstanceState) + + //默认显示所有设备 + deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] + deviceViewModel.mapDeviceModel.observe(this) { + if (it.code == 200) { + val allMarkerOptions = ArrayList() + val latitudeList = ArrayList() + val longitudeList = ArrayList() + it.data.forEach { device -> + val lat = device.latGaode.toString() + val lng = device.lngGaode.toString() + if (lat.isNotBlank() && lng.isNotBlank()) { + //返回true代表当前位置在大陆、港澳地区,反之不在 + val latitude = lat.toDouble() + val longitude = lng.toDouble() + if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { + //缓存所有设备详情,点击Marker时候需要 + deviceModels.add(device) + //分别缓存经、纬度 + latitudeList.add(latitude) + longitudeList.add(longitude) + //将所有设备信息转化缓存为Marker点 + allMarkerOptions.add( + MarkerOptions().position(LatLng(latitude, longitude)) + .title(device.devcode).snippet(device.modelName) + ) + } + } + } + + allMarkerOptions.forEach { marker -> + aMap.addMarker(marker) + } + + val latLng = LatLng(latitudeList[0], longitudeList[0]) + val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) + val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) + aMap.animateCamera(cameraUpdate, 1500, null) + } + } + deviceViewModel.getMapDeviceList() + } + + override fun initEvent() { + + } + + private fun initMap(savedInstanceState: Bundle?) { + binding.mapView.onCreate(savedInstanceState) + aMap = binding.mapView.map + aMap.mapType = AMap.MAP_TYPE_NORMAL + val uiSettings = aMap.uiSettings + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 + + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker 点击事件监听 + aMap.addOnMarkerClickListener(this) + // 点击marker弹出自定义popup + aMap.setInfoWindowAdapter(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + //地图点击事件,用于隐藏infoWindow + aMap.setOnMapClickListener(this) + } + + override fun onCameraChange(cameraPosition: CameraPosition?) { + + } + + //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker + override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { + + } + + override fun onMarkerClick(marker: Marker?): Boolean { + marker?.apply { + clickedMarker = this + if (isInfoWindowShown) { + hideInfoWindow() + } else { + showInfoWindow() + } + } + return true + } + + override fun onMapClick(p0: LatLng?) { + clickedMarker?.apply { + if (isInfoWindowShown) { + hideInfoWindow() + } + } + } + + override fun getInfoWindow(marker: Marker?): View? { + if (infoView == null) { + infoView = LayoutInflater.from(this).inflate(R.layout.popu_map_info, null) + } + marker?.apply { + renderWindow(this, infoView!!) + } + return infoView + } + + private fun renderWindow(marker: Marker, view: View) { + //反射得到popup里面的控件对象 + val deviceCodeView = view.findViewById(R.id.deviceCodeView) + val deviceModelView = view.findViewById(R.id.deviceModelView) + val deviceValueView = view.findViewById(R.id.deviceValueView) + val updateTimeView = view.findViewById(R.id.updateTimeView) + val locationView = view.findViewById(R.id.locationView) + + //绑定数据 + val clicked = marker.position + deviceModels.forEach { device -> + if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { + deviceCodeView.text = String.format("设备编号: ${device.devcode}") + deviceModelView.text = String.format("设备模型: ${device.modelName}") + //获取设备最新浓度信息 + deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) + deviceViewModel.lastDataModel.observe(this) { + if (it.code == 200) { + deviceValueView.text = String.format("最新浓度: ${it.data.strength}") + updateTimeView.text = String.format("更新时间: ${it.data.uptime}") + } else { + deviceValueView.text = String.format("最新浓度: 未知") + updateTimeView.text = String.format("更新时间: 未知") + } + } + if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { + locationView.text = "经纬度异常,无法查看具体位置" + } else { + val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { + if (rCode == 1000) { + val address = result?.regeocodeAddress?.formatAddress + val temp = StringBuilder() + if (address!!.length > 16) { + temp.append(address.substring(0, 14)).append("\r\n") + .append(address.substring(16)) + } else { + temp.append(address) + } + locationView.text = String.format("详细位置: $temp") + } + } + + override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + + } + }) + } + } + } + } + + /** + * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 + * */ + override fun getInfoContents(p0: Marker?): View? = null + + override fun onInfoWindowClick(marker: Marker?) { + marker?.apply { + AlertControlDialog.Builder().setContext(context).setTitle("操作提示") + .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + val lat = position.latitude.toString() + val lng = position.longitude.toString() + if (lat.isBlank() || lng.isBlank()) { + "窨井经纬度异常,无法开启导航".show(context) + return + } + RouteOnMap.startNavigation(context, snippet, position) + } + + override fun onCancelClick() { + + } + }).build().show() + } + } + + /***以下是地图生命周期管理************************************************************************/ + + override fun onResume() { + super.onResume() + binding.mapView.onResume() + } + + override fun onPause() { + super.onPause() + binding.mapView.onPause() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + binding.mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + super.onDestroy() + binding.mapView.onDestroy() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt index c7f06c9..b6b4e8a 100644 --- a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt +++ b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt @@ -3,29 +3,25 @@ import android.os.Bundle import android.view.KeyEvent import android.view.MenuItem -import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter import androidx.viewpager.widget.ViewPager import com.casic.smarttube.R +import com.casic.smarttube.adapter.TabPageViewAdapter import com.casic.smarttube.databinding.ActivityMainBinding import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.fragment.HomePageFragment import com.casic.smarttube.fragment.MinePageFragment import com.casic.smarttube.fragment.OverviewFragment -import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show class MainActivity : KotlinBaseActivity() { private var menuItem: MenuItem? = null - private var fragmentPages: MutableList = ArrayList() + private var fragmentPages: ArrayList = ArrayList() private var clickTime: Long = 0 init { - fragmentPages.add(HomePageFragment()) fragmentPages.add(OverviewFragment()) fragmentPages.add(MinePageFragment()) } @@ -35,30 +31,13 @@ } override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) } override fun initOnCreate(savedInstanceState: Bundle?) { //保留icon原图颜色 binding.bottomNavigation.itemIconTintList = null - binding.bottomNavigation.setOnItemSelectedListener { menuItem -> - when (menuItem.itemId) { - R.id.nav_home -> { - binding.mainViewPager.currentItem = 0 - } - - R.id.nav_overview -> { - binding.mainViewPager.currentItem = 1 - } - - R.id.nav_mine -> { - binding.mainViewPager.currentItem = 2 - } - } - false - } - binding.mainViewPager.adapter = ViewPagerAdapter(fragmentPages, supportFragmentManager) + binding.mainViewPager.adapter = TabPageViewAdapter(supportFragmentManager, fragmentPages) } override fun observeRequestState() { @@ -66,6 +45,18 @@ } override fun initEvent() { + binding.bottomNavigation.setOnItemSelectedListener { menuItem -> + when (menuItem.itemId) { + R.id.nav_overview -> { + binding.mainViewPager.currentItem = 0 + } + + R.id.nav_mine -> { + binding.mainViewPager.currentItem = 1 + } + } + false + } binding.mainViewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageScrollStateChanged(state: Int) { @@ -87,6 +78,10 @@ menuItem!!.isChecked = true } }) + + binding.addDeviceButton.setOnClickListener { + navigatePageTo() + } } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { @@ -100,18 +95,4 @@ } } else super.onKeyDown(keyCode, event) } - - inner class ViewPagerAdapter(list: MutableList, manager: FragmentManager) : - FragmentPagerAdapter(manager) { - - private var viewPages: List = list - - override fun getItem(position: Int): Fragment = viewPages[position] - - override fun getCount(): Int = viewPages.size - - override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { - - } - } } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 529403a..8908a3e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,7 +55,7 @@ - + +) : FragmentPagerAdapter(manager) { + + override fun getItem(position: Int): Fragment = pages[position] + + override fun getCount(): Int = pages.size + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + //注释掉父类方法,一直不销毁Fragment + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt deleted file mode 100644 index ab6743f..0000000 --- a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt +++ /dev/null @@ -1,387 +0,0 @@ -package com.casic.smarttube.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.CoordinateConverter -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.Marker -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.FragmentHomeBinding -import com.casic.smarttube.model.MapDeviceModel -import com.casic.smarttube.model.ProjectGroupModel -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.view.AddDeviceActivity -import com.casic.smarttube.vm.DeviceViewModel -import com.casic.smarttube.vm.ProjectGroupViewModel -import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter -import com.pengxh.kt.lite.adapter.ViewHolder -import com.pengxh.kt.lite.base.KotlinBaseFragment -import com.pengxh.kt.lite.extensions.navigatePageTo -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView -import com.pengxh.kt.lite.widget.dialog.AlertControlDialog - - -class HomePageFragment : KotlinBaseFragment(), AMap.OnCameraChangeListener, - AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener, - AMap.OnMapClickListener { - - private val kTag = "HomePageFragment" - private val geocoderSearch by lazy { GeocodeSearch(requireContext()) } - private lateinit var aMap: AMap - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var groupViewModel: ProjectGroupViewModel - private lateinit var groupListAdapter: NormalRecyclerAdapter - private var clickedMarker: Marker? = null - - /** - * 自定义Marker弹出框 - * */ - private var infoView: View? = null - - /** - * 所有设备列表信息集合 - * */ - private var deviceModels: MutableList = ArrayList() - - override fun initViewBinding( - inflater: LayoutInflater, container: ViewGroup? - ): FragmentHomeBinding { - return FragmentHomeBinding.inflate(inflater, container, false) - } - - override fun setupTopBarLayout() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - - } - - override fun onRightClick() { - requireContext().navigatePageTo() - } - }) - } - - override fun observeRequestState() { - groupViewModel.loadState.observe(this) { state -> - when (state) { - LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - //地图初始化 - initMap(savedInstanceState) - - //默认显示所有设备 - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - deviceViewModel.mapDeviceModel.observe(this) { - if (it.code == 200) { - val allMarkerOptions = ArrayList() - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //缓存所有设备详情,点击Marker时候需要 - deviceModels.add(device) - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - //将所有设备信息转化缓存为Marker点 - allMarkerOptions.add( - MarkerOptions().position(LatLng(latitude, longitude)) - .title(device.devcode).snippet(device.modelName) - ) - } - } - } - - allMarkerOptions.forEach { marker -> - aMap.addMarker(marker) - } - - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate, 1500, null) - } - } - deviceViewModel.getMapDeviceList() - - groupViewModel = ViewModelProvider(this)[ProjectGroupViewModel::class.java] - groupViewModel.groupModel.observe(this) { - if (it.code == 200) { - bindRecyclerView(it) - } - } - - groupViewModel.groupDeviceModel.observe(this) { - if (it.code == 200) { - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - } - } - } - //计算所有点的中心点位置 - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate) - } - } - } - - private fun bindRecyclerView(it: ProjectGroupModel) { - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - binding.homeRecyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - // 根据groupId查询组下设备 - groupViewModel.getDeviceListByGroup(item.groupId) - } - }) - } - - override fun initEvent() { - - } - - private fun initMap(savedInstanceState: Bundle?) { - binding.mapView.onCreate(savedInstanceState) - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 - - // 地图缩放监听 - aMap.addOnCameraChangeListener(this) - // marker 点击事件监听 - aMap.addOnMarkerClickListener(this) - // 点击marker弹出自定义popup - aMap.setInfoWindowAdapter(this) - //信息窗点击事件 - aMap.addOnInfoWindowClickListener(this) - //地图点击事件,用于隐藏infoWindow - aMap.setOnMapClickListener(this) - } - - override fun onCameraChange(cameraPosition: CameraPosition?) { - - } - - //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker - override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { - - } - - override fun onMarkerClick(marker: Marker?): Boolean { - marker?.apply { - clickedMarker = this - if (isInfoWindowShown) { - hideInfoWindow() - } else { - showInfoWindow() - } - } - return true - } - - override fun onMapClick(p0: LatLng?) { - clickedMarker?.apply { - if (isInfoWindowShown) { - hideInfoWindow() - } - } - } - - override fun getInfoWindow(marker: Marker?): View? { - if (infoView == null) { - infoView = LayoutInflater.from(requireContext()).inflate( - R.layout.popu_map_info, null - ) - } - marker?.apply { - renderWindow(this, infoView!!) - } - return infoView - } - - private fun renderWindow(marker: Marker, view: View) { - //反射得到popup里面的控件对象 - val deviceCodeView = view.findViewById(R.id.deviceCodeView) - val deviceModelView = view.findViewById(R.id.deviceModelView) - val deviceValueView = view.findViewById(R.id.deviceValueView) - val updateTimeView = view.findViewById(R.id.updateTimeView) - val locationView = view.findViewById(R.id.locationView) - - //绑定数据 - val clicked = marker.position - deviceModels.forEach { device -> - if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { - deviceCodeView.text = String.format("设备编号: ${device.devcode}") - deviceModelView.text = String.format("设备模型: ${device.modelName}") - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(requireActivity()) { - if (it.code == 200) { - deviceValueView.text = String.format("最新浓度: ${it.data.strength}") - updateTimeView.text = String.format("更新时间: ${it.data.uptime}") - } else { - deviceValueView.text = String.format("最新浓度: 未知") - updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - locationView.text = "经纬度异常,无法查看具体位置" - } else { - val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - val address = result?.regeocodeAddress?.formatAddress - val temp = StringBuilder() - if (address!!.length > 16) { - temp.append(address.substring(0, 14)).append("\r\n") - .append(address.substring(16)) - } else { - temp.append(address) - } - locationView.text = String.format("详细位置: $temp") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - } - - /** - * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 - * */ - override fun getInfoContents(p0: Marker?): View? = null - - override fun onInfoWindowClick(marker: Marker?) { - marker?.apply { - AlertControlDialog.Builder().setContext(requireContext()).setTitle("操作提示") - .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - val lat = position.latitude.toString() - val lng = position.longitude.toString() - if (lat.isBlank() || lng.isBlank()) { - "窨井经纬度异常,无法开启导航".show(requireContext()) - return - } - RouteOnMap.startNavigation(requireContext(), snippet, position) - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - - /***以下是地图生命周期管理************************************************************************/ - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - groupViewModel.getProGroupList() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } - - override fun onDestroy() { - super.onDestroy() - binding.mapView.onDestroy() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt index 1d0aa3d..dd09cf5 100644 --- a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt +++ b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt @@ -15,12 +15,16 @@ import com.casic.smarttube.databinding.FragmentOverviewBinding import com.casic.smarttube.model.ProjectGroupModel import com.casic.smarttube.view.GroupDeviceActivity +import com.casic.smarttube.view.GroupDeviceMapActivity import com.casic.smarttube.vm.ProjectGroupViewModel import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseFragment import com.pengxh.kt.lite.divider.RecyclerViewItemDivider import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.EmptyView import com.pengxh.kt.lite.widget.TitleBarView import com.pengxh.kt.lite.widget.dialog.AlertInputDialog @@ -32,6 +36,7 @@ private lateinit var groupViewModel: ProjectGroupViewModel private lateinit var groupListAdapter: NormalRecyclerAdapter private var clickedPosition = 0 + private var isRefresh = false override fun initViewBinding( inflater: LayoutInflater, container: ViewGroup? @@ -40,7 +45,15 @@ } override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + } + + override fun onRightClick() { + requireContext().navigatePageTo() + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { @@ -55,66 +68,93 @@ groupListAdapter.notifyItemChanged(clickedPosition) } } - groupViewModel.getGroupList() + } + + override fun onResume() { + super.onResume() + groupViewModel.getProGroupList() } private fun bindRecyclerView(it: ProjectGroupModel) { val dataRows = it.data - if (dataRows.size == 0) { - binding.emptyView.visibility = View.VISIBLE - binding.recyclerView.visibility = View.GONE - } else { - binding.emptyView.visibility = View.GONE - binding.recyclerView.visibility = View.VISIBLE + when { + isRefresh -> { + binding.refreshView.finishRefresh() + isRefresh = false + groupListAdapter.refresh(dataRows) + } - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_over_view_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - .setOnClickListener(R.id.editGroupNameView) { - clickedPosition = position - editGroupName(item) - } - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) + else -> { + if (dataRows.size == 0) { + binding.emptyView.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE + } else { + binding.emptyView.visibility = View.GONE + binding.recyclerView.visibility = View.VISIBLE + + groupListAdapter = object : NormalRecyclerAdapter( + R.layout.item_group_over_view_rv_l, it.data + ) { + override fun convertView( + viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel + ) { + viewHolder.setText(R.id.groupNameView, item.groupId) + .setText(R.id.totalDeviceNumView, item.totalDevice) + .setText(R.id.inUseDeviceNumView, item.alive) + .setText(R.id.notUseDeviceNumView, item.unalive) + .setOnClickListener(R.id.editGroupNameView) { + clickedPosition = position + editGroupName(item) } - } + if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { + viewHolder.setText( + R.id.groupLocationView, + "经纬度异常,无法查看具体位置" + ) + } else { + val point = + LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched( + result: RegeocodeResult?, + rCode: Int + ) { + if (rCode == 1000) { + viewHolder.setText( + R.id.groupLocationView, + String.format("${result?.regeocodeAddress?.formatAddress}") + ) + } + } - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + override fun onGeocodeSearched( + result: GeocodeResult?, + rCode: Int + ) { + } + }) } - }) + } } + binding.recyclerView.addItemDecoration( + RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) + ) + binding.recyclerView.adapter = groupListAdapter + groupListAdapter.setOnItemClickedListener(object : + NormalRecyclerAdapter.OnItemClickedListener { + override fun onItemClicked( + position: Int, + item: ProjectGroupModel.DataModel + ) { + requireContext().navigatePageTo(item.groupId) + } + }) } } - binding.recyclerView.addItemDecoration( - RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) - ) - binding.recyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - requireContext().navigatePageTo(item.groupId) - } - }) } } @@ -139,18 +179,31 @@ } override fun observeRequestState() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - + groupViewModel.loadState.observe(this) { + if (isRefresh) { + return@observe } + when (it) { + LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中,请稍后...") - override fun onRightClick() { - groupViewModel.getProGroupList() + LoadState.Success -> { + LoadingDialog.dismiss() + } + + LoadState.Fail -> { + LoadingDialog.dismiss() + "数据加载失败,请重试".show(requireContext()) + } } - }) + } } override fun initEvent() { + binding.refreshView.setOnRefreshListener { + isRefresh = true + groupViewModel.getProGroupList() + } + binding.emptyView.setOnClickListener(object : EmptyView.OnClickListener { override fun onReloadButtonClicked() { groupViewModel.getProGroupList() diff --git a/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt new file mode 100644 index 0000000..c33c40e --- /dev/null +++ b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt @@ -0,0 +1,288 @@ +package com.casic.smarttube.view + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.lifecycle.ViewModelProvider +import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.CameraUpdateFactory +import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.CameraPosition +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.Marker +import com.amap.api.maps.model.MarkerOptions +import com.amap.api.services.core.LatLonPoint +import com.amap.api.services.geocoder.GeocodeResult +import com.amap.api.services.geocoder.GeocodeSearch +import com.amap.api.services.geocoder.RegeocodeQuery +import com.amap.api.services.geocoder.RegeocodeResult +import com.casic.smarttube.R +import com.casic.smarttube.databinding.ActivityGroupDeviceMapBinding +import com.casic.smarttube.extensions.initImmersionBar +import com.casic.smarttube.model.MapDeviceModel +import com.casic.smarttube.utils.RouteOnMap +import com.casic.smarttube.vm.DeviceViewModel +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog + +class GroupDeviceMapActivity : KotlinBaseActivity(), + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, + AMap.OnInfoWindowClickListener, AMap.OnMapClickListener { + + private val context = this + private val geocoderSearch by lazy { GeocodeSearch(this) } + private lateinit var aMap: AMap + private lateinit var deviceViewModel: DeviceViewModel + private var clickedMarker: Marker? = null + + /** + * 自定义Marker弹出框 + * */ + private var infoView: View? = null + + /** + * 所有设备列表信息集合 + * */ + private var deviceModels: MutableList = ArrayList() + + override fun initViewBinding(): ActivityGroupDeviceMapBinding { + return ActivityGroupDeviceMapBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + } + + override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + //地图初始化 + initMap(savedInstanceState) + + //默认显示所有设备 + deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] + deviceViewModel.mapDeviceModel.observe(this) { + if (it.code == 200) { + val allMarkerOptions = ArrayList() + val latitudeList = ArrayList() + val longitudeList = ArrayList() + it.data.forEach { device -> + val lat = device.latGaode.toString() + val lng = device.lngGaode.toString() + if (lat.isNotBlank() && lng.isNotBlank()) { + //返回true代表当前位置在大陆、港澳地区,反之不在 + val latitude = lat.toDouble() + val longitude = lng.toDouble() + if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { + //缓存所有设备详情,点击Marker时候需要 + deviceModels.add(device) + //分别缓存经、纬度 + latitudeList.add(latitude) + longitudeList.add(longitude) + //将所有设备信息转化缓存为Marker点 + allMarkerOptions.add( + MarkerOptions().position(LatLng(latitude, longitude)) + .title(device.devcode).snippet(device.modelName) + ) + } + } + } + + allMarkerOptions.forEach { marker -> + aMap.addMarker(marker) + } + + val latLng = LatLng(latitudeList[0], longitudeList[0]) + val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) + val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) + aMap.animateCamera(cameraUpdate, 1500, null) + } + } + deviceViewModel.getMapDeviceList() + } + + override fun initEvent() { + + } + + private fun initMap(savedInstanceState: Bundle?) { + binding.mapView.onCreate(savedInstanceState) + aMap = binding.mapView.map + aMap.mapType = AMap.MAP_TYPE_NORMAL + val uiSettings = aMap.uiSettings + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 + + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker 点击事件监听 + aMap.addOnMarkerClickListener(this) + // 点击marker弹出自定义popup + aMap.setInfoWindowAdapter(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + //地图点击事件,用于隐藏infoWindow + aMap.setOnMapClickListener(this) + } + + override fun onCameraChange(cameraPosition: CameraPosition?) { + + } + + //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker + override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { + + } + + override fun onMarkerClick(marker: Marker?): Boolean { + marker?.apply { + clickedMarker = this + if (isInfoWindowShown) { + hideInfoWindow() + } else { + showInfoWindow() + } + } + return true + } + + override fun onMapClick(p0: LatLng?) { + clickedMarker?.apply { + if (isInfoWindowShown) { + hideInfoWindow() + } + } + } + + override fun getInfoWindow(marker: Marker?): View? { + if (infoView == null) { + infoView = LayoutInflater.from(this).inflate(R.layout.popu_map_info, null) + } + marker?.apply { + renderWindow(this, infoView!!) + } + return infoView + } + + private fun renderWindow(marker: Marker, view: View) { + //反射得到popup里面的控件对象 + val deviceCodeView = view.findViewById(R.id.deviceCodeView) + val deviceModelView = view.findViewById(R.id.deviceModelView) + val deviceValueView = view.findViewById(R.id.deviceValueView) + val updateTimeView = view.findViewById(R.id.updateTimeView) + val locationView = view.findViewById(R.id.locationView) + + //绑定数据 + val clicked = marker.position + deviceModels.forEach { device -> + if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { + deviceCodeView.text = String.format("设备编号: ${device.devcode}") + deviceModelView.text = String.format("设备模型: ${device.modelName}") + //获取设备最新浓度信息 + deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) + deviceViewModel.lastDataModel.observe(this) { + if (it.code == 200) { + deviceValueView.text = String.format("最新浓度: ${it.data.strength}") + updateTimeView.text = String.format("更新时间: ${it.data.uptime}") + } else { + deviceValueView.text = String.format("最新浓度: 未知") + updateTimeView.text = String.format("更新时间: 未知") + } + } + if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { + locationView.text = "经纬度异常,无法查看具体位置" + } else { + val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { + if (rCode == 1000) { + val address = result?.regeocodeAddress?.formatAddress + val temp = StringBuilder() + if (address!!.length > 16) { + temp.append(address.substring(0, 14)).append("\r\n") + .append(address.substring(16)) + } else { + temp.append(address) + } + locationView.text = String.format("详细位置: $temp") + } + } + + override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + + } + }) + } + } + } + } + + /** + * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 + * */ + override fun getInfoContents(p0: Marker?): View? = null + + override fun onInfoWindowClick(marker: Marker?) { + marker?.apply { + AlertControlDialog.Builder().setContext(context).setTitle("操作提示") + .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + val lat = position.latitude.toString() + val lng = position.longitude.toString() + if (lat.isBlank() || lng.isBlank()) { + "窨井经纬度异常,无法开启导航".show(context) + return + } + RouteOnMap.startNavigation(context, snippet, position) + } + + override fun onCancelClick() { + + } + }).build().show() + } + } + + /***以下是地图生命周期管理************************************************************************/ + + override fun onResume() { + super.onResume() + binding.mapView.onResume() + } + + override fun onPause() { + super.onPause() + binding.mapView.onPause() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + binding.mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + super.onDestroy() + binding.mapView.onDestroy() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt index c7f06c9..b6b4e8a 100644 --- a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt +++ b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt @@ -3,29 +3,25 @@ import android.os.Bundle import android.view.KeyEvent import android.view.MenuItem -import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter import androidx.viewpager.widget.ViewPager import com.casic.smarttube.R +import com.casic.smarttube.adapter.TabPageViewAdapter import com.casic.smarttube.databinding.ActivityMainBinding import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.fragment.HomePageFragment import com.casic.smarttube.fragment.MinePageFragment import com.casic.smarttube.fragment.OverviewFragment -import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show class MainActivity : KotlinBaseActivity() { private var menuItem: MenuItem? = null - private var fragmentPages: MutableList = ArrayList() + private var fragmentPages: ArrayList = ArrayList() private var clickTime: Long = 0 init { - fragmentPages.add(HomePageFragment()) fragmentPages.add(OverviewFragment()) fragmentPages.add(MinePageFragment()) } @@ -35,30 +31,13 @@ } override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) } override fun initOnCreate(savedInstanceState: Bundle?) { //保留icon原图颜色 binding.bottomNavigation.itemIconTintList = null - binding.bottomNavigation.setOnItemSelectedListener { menuItem -> - when (menuItem.itemId) { - R.id.nav_home -> { - binding.mainViewPager.currentItem = 0 - } - - R.id.nav_overview -> { - binding.mainViewPager.currentItem = 1 - } - - R.id.nav_mine -> { - binding.mainViewPager.currentItem = 2 - } - } - false - } - binding.mainViewPager.adapter = ViewPagerAdapter(fragmentPages, supportFragmentManager) + binding.mainViewPager.adapter = TabPageViewAdapter(supportFragmentManager, fragmentPages) } override fun observeRequestState() { @@ -66,6 +45,18 @@ } override fun initEvent() { + binding.bottomNavigation.setOnItemSelectedListener { menuItem -> + when (menuItem.itemId) { + R.id.nav_overview -> { + binding.mainViewPager.currentItem = 0 + } + + R.id.nav_mine -> { + binding.mainViewPager.currentItem = 1 + } + } + false + } binding.mainViewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageScrollStateChanged(state: Int) { @@ -87,6 +78,10 @@ menuItem!!.isChecked = true } }) + + binding.addDeviceButton.setOnClickListener { + navigatePageTo() + } } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { @@ -100,18 +95,4 @@ } } else super.onKeyDown(keyCode, event) } - - inner class ViewPagerAdapter(list: MutableList, manager: FragmentManager) : - FragmentPagerAdapter(manager) { - - private var viewPages: List = list - - override fun getItem(position: Int): Fragment = viewPages[position] - - override fun getCount(): Int = viewPages.size - - override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { - - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt b/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt deleted file mode 100644 index b5be93b..0000000 --- a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt +++ /dev/null @@ -1,174 +0,0 @@ -package com.casic.smarttube.view - -import android.os.Bundle -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.model.BitmapDescriptorFactory -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.ActivityMapDeviceBriefBinding -import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.vm.DeviceViewModel -import com.gyf.immersionbar.ImmersionBar -import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.utils.LiteKitConstant -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView - -class MapDeviceBriefActivity : KotlinBaseActivity() { - - private val kTag = "MapDeviceBriefActivity" - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var aMap: AMap - private lateinit var params: ArrayList - private val geocoderSearch by lazy { GeocodeSearch(this) } - - - override fun initViewBinding(): ActivityMapDeviceBriefBinding { - return ActivityMapDeviceBriefBinding.inflate(layoutInflater) - } - - override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - finish() - } - - override fun onRightClick() { - - } - }) - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图旋转 - - this.params = intent.getStringArrayListExtra(LiteKitConstant.INTENT_PARAM_KEY)!! - - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - } - - override fun observeRequestState() { - deviceViewModel.loadState.observe(this) { - when (it) { - LoadState.Loading -> LoadingDialog.show(this, "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initEvent() { - deviceViewModel.obtainDeviceDetail(params[0], params[1]) - deviceViewModel.deviceDetailModel.observe(this) { - if (it.code == 200) { - val device = it.data - - binding.deviceCodeView.text = String.format("设备编号: ${device.devcode}") - binding.deviceModelView.text = String.format("设备模型: ${params[2]}") - - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(this) { v -> - if (v.code == 200) { - binding.deviceValueView.text = String.format("最新浓度: ${v.data.strength}") - binding.updateTimeView.text = String.format("更新时间: ${v.data.uptime}") - } else { - binding.deviceValueView.text = String.format("最新浓度: 未知") - binding.updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - binding.locationView.text = "经纬度异常,无法查看具体位置" - } else { - val queryParam = RegeocodeQuery( - LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()), - 200f, - GeocodeSearch.AMAP - ) - val latLng = LatLng(device.latGaode.toDouble(), device.lngGaode.toDouble()) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - binding.locationView.text = - String.format("详细位置: ${result?.regeocodeAddress?.formatAddress}") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - - val cameraPosition = CameraPosition(latLng, 18f, 0f, 0f) - val newCameraPosition = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(newCameraPosition, 1500, object : AMap.CancelableCallback { - override fun onFinish() { - //添加Marker - val markerOptions = MarkerOptions().position(latLng) - .icon(BitmapDescriptorFactory.fromResource(R.mipmap.well_location)) - .draggable(false) - aMap.addMarker(markerOptions) - } - - override fun onCancel() { - - } - }) - aMap.setOnMarkerClickListener { - RouteOnMap.startNavigation( - this@MapDeviceBriefActivity, "", latLng - ) - true - } - } - } - } - } - - /**地图相关*********/ - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding.mapView.onCreate(savedInstanceState) - } - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onDestroy() { - binding.mapView.onDestroy() - super.onDestroy() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } -} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 529403a..8908a3e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,7 +55,7 @@ - + +) : FragmentPagerAdapter(manager) { + + override fun getItem(position: Int): Fragment = pages[position] + + override fun getCount(): Int = pages.size + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + //注释掉父类方法,一直不销毁Fragment + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt deleted file mode 100644 index ab6743f..0000000 --- a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt +++ /dev/null @@ -1,387 +0,0 @@ -package com.casic.smarttube.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.CoordinateConverter -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.Marker -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.FragmentHomeBinding -import com.casic.smarttube.model.MapDeviceModel -import com.casic.smarttube.model.ProjectGroupModel -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.view.AddDeviceActivity -import com.casic.smarttube.vm.DeviceViewModel -import com.casic.smarttube.vm.ProjectGroupViewModel -import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter -import com.pengxh.kt.lite.adapter.ViewHolder -import com.pengxh.kt.lite.base.KotlinBaseFragment -import com.pengxh.kt.lite.extensions.navigatePageTo -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView -import com.pengxh.kt.lite.widget.dialog.AlertControlDialog - - -class HomePageFragment : KotlinBaseFragment(), AMap.OnCameraChangeListener, - AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener, - AMap.OnMapClickListener { - - private val kTag = "HomePageFragment" - private val geocoderSearch by lazy { GeocodeSearch(requireContext()) } - private lateinit var aMap: AMap - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var groupViewModel: ProjectGroupViewModel - private lateinit var groupListAdapter: NormalRecyclerAdapter - private var clickedMarker: Marker? = null - - /** - * 自定义Marker弹出框 - * */ - private var infoView: View? = null - - /** - * 所有设备列表信息集合 - * */ - private var deviceModels: MutableList = ArrayList() - - override fun initViewBinding( - inflater: LayoutInflater, container: ViewGroup? - ): FragmentHomeBinding { - return FragmentHomeBinding.inflate(inflater, container, false) - } - - override fun setupTopBarLayout() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - - } - - override fun onRightClick() { - requireContext().navigatePageTo() - } - }) - } - - override fun observeRequestState() { - groupViewModel.loadState.observe(this) { state -> - when (state) { - LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - //地图初始化 - initMap(savedInstanceState) - - //默认显示所有设备 - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - deviceViewModel.mapDeviceModel.observe(this) { - if (it.code == 200) { - val allMarkerOptions = ArrayList() - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //缓存所有设备详情,点击Marker时候需要 - deviceModels.add(device) - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - //将所有设备信息转化缓存为Marker点 - allMarkerOptions.add( - MarkerOptions().position(LatLng(latitude, longitude)) - .title(device.devcode).snippet(device.modelName) - ) - } - } - } - - allMarkerOptions.forEach { marker -> - aMap.addMarker(marker) - } - - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate, 1500, null) - } - } - deviceViewModel.getMapDeviceList() - - groupViewModel = ViewModelProvider(this)[ProjectGroupViewModel::class.java] - groupViewModel.groupModel.observe(this) { - if (it.code == 200) { - bindRecyclerView(it) - } - } - - groupViewModel.groupDeviceModel.observe(this) { - if (it.code == 200) { - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - } - } - } - //计算所有点的中心点位置 - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate) - } - } - } - - private fun bindRecyclerView(it: ProjectGroupModel) { - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - binding.homeRecyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - // 根据groupId查询组下设备 - groupViewModel.getDeviceListByGroup(item.groupId) - } - }) - } - - override fun initEvent() { - - } - - private fun initMap(savedInstanceState: Bundle?) { - binding.mapView.onCreate(savedInstanceState) - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 - - // 地图缩放监听 - aMap.addOnCameraChangeListener(this) - // marker 点击事件监听 - aMap.addOnMarkerClickListener(this) - // 点击marker弹出自定义popup - aMap.setInfoWindowAdapter(this) - //信息窗点击事件 - aMap.addOnInfoWindowClickListener(this) - //地图点击事件,用于隐藏infoWindow - aMap.setOnMapClickListener(this) - } - - override fun onCameraChange(cameraPosition: CameraPosition?) { - - } - - //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker - override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { - - } - - override fun onMarkerClick(marker: Marker?): Boolean { - marker?.apply { - clickedMarker = this - if (isInfoWindowShown) { - hideInfoWindow() - } else { - showInfoWindow() - } - } - return true - } - - override fun onMapClick(p0: LatLng?) { - clickedMarker?.apply { - if (isInfoWindowShown) { - hideInfoWindow() - } - } - } - - override fun getInfoWindow(marker: Marker?): View? { - if (infoView == null) { - infoView = LayoutInflater.from(requireContext()).inflate( - R.layout.popu_map_info, null - ) - } - marker?.apply { - renderWindow(this, infoView!!) - } - return infoView - } - - private fun renderWindow(marker: Marker, view: View) { - //反射得到popup里面的控件对象 - val deviceCodeView = view.findViewById(R.id.deviceCodeView) - val deviceModelView = view.findViewById(R.id.deviceModelView) - val deviceValueView = view.findViewById(R.id.deviceValueView) - val updateTimeView = view.findViewById(R.id.updateTimeView) - val locationView = view.findViewById(R.id.locationView) - - //绑定数据 - val clicked = marker.position - deviceModels.forEach { device -> - if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { - deviceCodeView.text = String.format("设备编号: ${device.devcode}") - deviceModelView.text = String.format("设备模型: ${device.modelName}") - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(requireActivity()) { - if (it.code == 200) { - deviceValueView.text = String.format("最新浓度: ${it.data.strength}") - updateTimeView.text = String.format("更新时间: ${it.data.uptime}") - } else { - deviceValueView.text = String.format("最新浓度: 未知") - updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - locationView.text = "经纬度异常,无法查看具体位置" - } else { - val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - val address = result?.regeocodeAddress?.formatAddress - val temp = StringBuilder() - if (address!!.length > 16) { - temp.append(address.substring(0, 14)).append("\r\n") - .append(address.substring(16)) - } else { - temp.append(address) - } - locationView.text = String.format("详细位置: $temp") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - } - - /** - * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 - * */ - override fun getInfoContents(p0: Marker?): View? = null - - override fun onInfoWindowClick(marker: Marker?) { - marker?.apply { - AlertControlDialog.Builder().setContext(requireContext()).setTitle("操作提示") - .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - val lat = position.latitude.toString() - val lng = position.longitude.toString() - if (lat.isBlank() || lng.isBlank()) { - "窨井经纬度异常,无法开启导航".show(requireContext()) - return - } - RouteOnMap.startNavigation(requireContext(), snippet, position) - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - - /***以下是地图生命周期管理************************************************************************/ - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - groupViewModel.getProGroupList() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } - - override fun onDestroy() { - super.onDestroy() - binding.mapView.onDestroy() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt index 1d0aa3d..dd09cf5 100644 --- a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt +++ b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt @@ -15,12 +15,16 @@ import com.casic.smarttube.databinding.FragmentOverviewBinding import com.casic.smarttube.model.ProjectGroupModel import com.casic.smarttube.view.GroupDeviceActivity +import com.casic.smarttube.view.GroupDeviceMapActivity import com.casic.smarttube.vm.ProjectGroupViewModel import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseFragment import com.pengxh.kt.lite.divider.RecyclerViewItemDivider import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.EmptyView import com.pengxh.kt.lite.widget.TitleBarView import com.pengxh.kt.lite.widget.dialog.AlertInputDialog @@ -32,6 +36,7 @@ private lateinit var groupViewModel: ProjectGroupViewModel private lateinit var groupListAdapter: NormalRecyclerAdapter private var clickedPosition = 0 + private var isRefresh = false override fun initViewBinding( inflater: LayoutInflater, container: ViewGroup? @@ -40,7 +45,15 @@ } override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + } + + override fun onRightClick() { + requireContext().navigatePageTo() + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { @@ -55,66 +68,93 @@ groupListAdapter.notifyItemChanged(clickedPosition) } } - groupViewModel.getGroupList() + } + + override fun onResume() { + super.onResume() + groupViewModel.getProGroupList() } private fun bindRecyclerView(it: ProjectGroupModel) { val dataRows = it.data - if (dataRows.size == 0) { - binding.emptyView.visibility = View.VISIBLE - binding.recyclerView.visibility = View.GONE - } else { - binding.emptyView.visibility = View.GONE - binding.recyclerView.visibility = View.VISIBLE + when { + isRefresh -> { + binding.refreshView.finishRefresh() + isRefresh = false + groupListAdapter.refresh(dataRows) + } - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_over_view_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - .setOnClickListener(R.id.editGroupNameView) { - clickedPosition = position - editGroupName(item) - } - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) + else -> { + if (dataRows.size == 0) { + binding.emptyView.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE + } else { + binding.emptyView.visibility = View.GONE + binding.recyclerView.visibility = View.VISIBLE + + groupListAdapter = object : NormalRecyclerAdapter( + R.layout.item_group_over_view_rv_l, it.data + ) { + override fun convertView( + viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel + ) { + viewHolder.setText(R.id.groupNameView, item.groupId) + .setText(R.id.totalDeviceNumView, item.totalDevice) + .setText(R.id.inUseDeviceNumView, item.alive) + .setText(R.id.notUseDeviceNumView, item.unalive) + .setOnClickListener(R.id.editGroupNameView) { + clickedPosition = position + editGroupName(item) } - } + if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { + viewHolder.setText( + R.id.groupLocationView, + "经纬度异常,无法查看具体位置" + ) + } else { + val point = + LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched( + result: RegeocodeResult?, + rCode: Int + ) { + if (rCode == 1000) { + viewHolder.setText( + R.id.groupLocationView, + String.format("${result?.regeocodeAddress?.formatAddress}") + ) + } + } - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + override fun onGeocodeSearched( + result: GeocodeResult?, + rCode: Int + ) { + } + }) } - }) + } } + binding.recyclerView.addItemDecoration( + RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) + ) + binding.recyclerView.adapter = groupListAdapter + groupListAdapter.setOnItemClickedListener(object : + NormalRecyclerAdapter.OnItemClickedListener { + override fun onItemClicked( + position: Int, + item: ProjectGroupModel.DataModel + ) { + requireContext().navigatePageTo(item.groupId) + } + }) } } - binding.recyclerView.addItemDecoration( - RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) - ) - binding.recyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - requireContext().navigatePageTo(item.groupId) - } - }) } } @@ -139,18 +179,31 @@ } override fun observeRequestState() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - + groupViewModel.loadState.observe(this) { + if (isRefresh) { + return@observe } + when (it) { + LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中,请稍后...") - override fun onRightClick() { - groupViewModel.getProGroupList() + LoadState.Success -> { + LoadingDialog.dismiss() + } + + LoadState.Fail -> { + LoadingDialog.dismiss() + "数据加载失败,请重试".show(requireContext()) + } } - }) + } } override fun initEvent() { + binding.refreshView.setOnRefreshListener { + isRefresh = true + groupViewModel.getProGroupList() + } + binding.emptyView.setOnClickListener(object : EmptyView.OnClickListener { override fun onReloadButtonClicked() { groupViewModel.getProGroupList() diff --git a/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt new file mode 100644 index 0000000..c33c40e --- /dev/null +++ b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt @@ -0,0 +1,288 @@ +package com.casic.smarttube.view + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.lifecycle.ViewModelProvider +import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.CameraUpdateFactory +import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.CameraPosition +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.Marker +import com.amap.api.maps.model.MarkerOptions +import com.amap.api.services.core.LatLonPoint +import com.amap.api.services.geocoder.GeocodeResult +import com.amap.api.services.geocoder.GeocodeSearch +import com.amap.api.services.geocoder.RegeocodeQuery +import com.amap.api.services.geocoder.RegeocodeResult +import com.casic.smarttube.R +import com.casic.smarttube.databinding.ActivityGroupDeviceMapBinding +import com.casic.smarttube.extensions.initImmersionBar +import com.casic.smarttube.model.MapDeviceModel +import com.casic.smarttube.utils.RouteOnMap +import com.casic.smarttube.vm.DeviceViewModel +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog + +class GroupDeviceMapActivity : KotlinBaseActivity(), + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, + AMap.OnInfoWindowClickListener, AMap.OnMapClickListener { + + private val context = this + private val geocoderSearch by lazy { GeocodeSearch(this) } + private lateinit var aMap: AMap + private lateinit var deviceViewModel: DeviceViewModel + private var clickedMarker: Marker? = null + + /** + * 自定义Marker弹出框 + * */ + private var infoView: View? = null + + /** + * 所有设备列表信息集合 + * */ + private var deviceModels: MutableList = ArrayList() + + override fun initViewBinding(): ActivityGroupDeviceMapBinding { + return ActivityGroupDeviceMapBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + } + + override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + //地图初始化 + initMap(savedInstanceState) + + //默认显示所有设备 + deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] + deviceViewModel.mapDeviceModel.observe(this) { + if (it.code == 200) { + val allMarkerOptions = ArrayList() + val latitudeList = ArrayList() + val longitudeList = ArrayList() + it.data.forEach { device -> + val lat = device.latGaode.toString() + val lng = device.lngGaode.toString() + if (lat.isNotBlank() && lng.isNotBlank()) { + //返回true代表当前位置在大陆、港澳地区,反之不在 + val latitude = lat.toDouble() + val longitude = lng.toDouble() + if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { + //缓存所有设备详情,点击Marker时候需要 + deviceModels.add(device) + //分别缓存经、纬度 + latitudeList.add(latitude) + longitudeList.add(longitude) + //将所有设备信息转化缓存为Marker点 + allMarkerOptions.add( + MarkerOptions().position(LatLng(latitude, longitude)) + .title(device.devcode).snippet(device.modelName) + ) + } + } + } + + allMarkerOptions.forEach { marker -> + aMap.addMarker(marker) + } + + val latLng = LatLng(latitudeList[0], longitudeList[0]) + val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) + val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) + aMap.animateCamera(cameraUpdate, 1500, null) + } + } + deviceViewModel.getMapDeviceList() + } + + override fun initEvent() { + + } + + private fun initMap(savedInstanceState: Bundle?) { + binding.mapView.onCreate(savedInstanceState) + aMap = binding.mapView.map + aMap.mapType = AMap.MAP_TYPE_NORMAL + val uiSettings = aMap.uiSettings + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 + + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker 点击事件监听 + aMap.addOnMarkerClickListener(this) + // 点击marker弹出自定义popup + aMap.setInfoWindowAdapter(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + //地图点击事件,用于隐藏infoWindow + aMap.setOnMapClickListener(this) + } + + override fun onCameraChange(cameraPosition: CameraPosition?) { + + } + + //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker + override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { + + } + + override fun onMarkerClick(marker: Marker?): Boolean { + marker?.apply { + clickedMarker = this + if (isInfoWindowShown) { + hideInfoWindow() + } else { + showInfoWindow() + } + } + return true + } + + override fun onMapClick(p0: LatLng?) { + clickedMarker?.apply { + if (isInfoWindowShown) { + hideInfoWindow() + } + } + } + + override fun getInfoWindow(marker: Marker?): View? { + if (infoView == null) { + infoView = LayoutInflater.from(this).inflate(R.layout.popu_map_info, null) + } + marker?.apply { + renderWindow(this, infoView!!) + } + return infoView + } + + private fun renderWindow(marker: Marker, view: View) { + //反射得到popup里面的控件对象 + val deviceCodeView = view.findViewById(R.id.deviceCodeView) + val deviceModelView = view.findViewById(R.id.deviceModelView) + val deviceValueView = view.findViewById(R.id.deviceValueView) + val updateTimeView = view.findViewById(R.id.updateTimeView) + val locationView = view.findViewById(R.id.locationView) + + //绑定数据 + val clicked = marker.position + deviceModels.forEach { device -> + if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { + deviceCodeView.text = String.format("设备编号: ${device.devcode}") + deviceModelView.text = String.format("设备模型: ${device.modelName}") + //获取设备最新浓度信息 + deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) + deviceViewModel.lastDataModel.observe(this) { + if (it.code == 200) { + deviceValueView.text = String.format("最新浓度: ${it.data.strength}") + updateTimeView.text = String.format("更新时间: ${it.data.uptime}") + } else { + deviceValueView.text = String.format("最新浓度: 未知") + updateTimeView.text = String.format("更新时间: 未知") + } + } + if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { + locationView.text = "经纬度异常,无法查看具体位置" + } else { + val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { + if (rCode == 1000) { + val address = result?.regeocodeAddress?.formatAddress + val temp = StringBuilder() + if (address!!.length > 16) { + temp.append(address.substring(0, 14)).append("\r\n") + .append(address.substring(16)) + } else { + temp.append(address) + } + locationView.text = String.format("详细位置: $temp") + } + } + + override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + + } + }) + } + } + } + } + + /** + * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 + * */ + override fun getInfoContents(p0: Marker?): View? = null + + override fun onInfoWindowClick(marker: Marker?) { + marker?.apply { + AlertControlDialog.Builder().setContext(context).setTitle("操作提示") + .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + val lat = position.latitude.toString() + val lng = position.longitude.toString() + if (lat.isBlank() || lng.isBlank()) { + "窨井经纬度异常,无法开启导航".show(context) + return + } + RouteOnMap.startNavigation(context, snippet, position) + } + + override fun onCancelClick() { + + } + }).build().show() + } + } + + /***以下是地图生命周期管理************************************************************************/ + + override fun onResume() { + super.onResume() + binding.mapView.onResume() + } + + override fun onPause() { + super.onPause() + binding.mapView.onPause() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + binding.mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + super.onDestroy() + binding.mapView.onDestroy() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt index c7f06c9..b6b4e8a 100644 --- a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt +++ b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt @@ -3,29 +3,25 @@ import android.os.Bundle import android.view.KeyEvent import android.view.MenuItem -import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter import androidx.viewpager.widget.ViewPager import com.casic.smarttube.R +import com.casic.smarttube.adapter.TabPageViewAdapter import com.casic.smarttube.databinding.ActivityMainBinding import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.fragment.HomePageFragment import com.casic.smarttube.fragment.MinePageFragment import com.casic.smarttube.fragment.OverviewFragment -import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show class MainActivity : KotlinBaseActivity() { private var menuItem: MenuItem? = null - private var fragmentPages: MutableList = ArrayList() + private var fragmentPages: ArrayList = ArrayList() private var clickTime: Long = 0 init { - fragmentPages.add(HomePageFragment()) fragmentPages.add(OverviewFragment()) fragmentPages.add(MinePageFragment()) } @@ -35,30 +31,13 @@ } override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) } override fun initOnCreate(savedInstanceState: Bundle?) { //保留icon原图颜色 binding.bottomNavigation.itemIconTintList = null - binding.bottomNavigation.setOnItemSelectedListener { menuItem -> - when (menuItem.itemId) { - R.id.nav_home -> { - binding.mainViewPager.currentItem = 0 - } - - R.id.nav_overview -> { - binding.mainViewPager.currentItem = 1 - } - - R.id.nav_mine -> { - binding.mainViewPager.currentItem = 2 - } - } - false - } - binding.mainViewPager.adapter = ViewPagerAdapter(fragmentPages, supportFragmentManager) + binding.mainViewPager.adapter = TabPageViewAdapter(supportFragmentManager, fragmentPages) } override fun observeRequestState() { @@ -66,6 +45,18 @@ } override fun initEvent() { + binding.bottomNavigation.setOnItemSelectedListener { menuItem -> + when (menuItem.itemId) { + R.id.nav_overview -> { + binding.mainViewPager.currentItem = 0 + } + + R.id.nav_mine -> { + binding.mainViewPager.currentItem = 1 + } + } + false + } binding.mainViewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageScrollStateChanged(state: Int) { @@ -87,6 +78,10 @@ menuItem!!.isChecked = true } }) + + binding.addDeviceButton.setOnClickListener { + navigatePageTo() + } } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { @@ -100,18 +95,4 @@ } } else super.onKeyDown(keyCode, event) } - - inner class ViewPagerAdapter(list: MutableList, manager: FragmentManager) : - FragmentPagerAdapter(manager) { - - private var viewPages: List = list - - override fun getItem(position: Int): Fragment = viewPages[position] - - override fun getCount(): Int = viewPages.size - - override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { - - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt b/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt deleted file mode 100644 index b5be93b..0000000 --- a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt +++ /dev/null @@ -1,174 +0,0 @@ -package com.casic.smarttube.view - -import android.os.Bundle -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.model.BitmapDescriptorFactory -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.ActivityMapDeviceBriefBinding -import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.vm.DeviceViewModel -import com.gyf.immersionbar.ImmersionBar -import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.utils.LiteKitConstant -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView - -class MapDeviceBriefActivity : KotlinBaseActivity() { - - private val kTag = "MapDeviceBriefActivity" - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var aMap: AMap - private lateinit var params: ArrayList - private val geocoderSearch by lazy { GeocodeSearch(this) } - - - override fun initViewBinding(): ActivityMapDeviceBriefBinding { - return ActivityMapDeviceBriefBinding.inflate(layoutInflater) - } - - override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - finish() - } - - override fun onRightClick() { - - } - }) - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图旋转 - - this.params = intent.getStringArrayListExtra(LiteKitConstant.INTENT_PARAM_KEY)!! - - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - } - - override fun observeRequestState() { - deviceViewModel.loadState.observe(this) { - when (it) { - LoadState.Loading -> LoadingDialog.show(this, "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initEvent() { - deviceViewModel.obtainDeviceDetail(params[0], params[1]) - deviceViewModel.deviceDetailModel.observe(this) { - if (it.code == 200) { - val device = it.data - - binding.deviceCodeView.text = String.format("设备编号: ${device.devcode}") - binding.deviceModelView.text = String.format("设备模型: ${params[2]}") - - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(this) { v -> - if (v.code == 200) { - binding.deviceValueView.text = String.format("最新浓度: ${v.data.strength}") - binding.updateTimeView.text = String.format("更新时间: ${v.data.uptime}") - } else { - binding.deviceValueView.text = String.format("最新浓度: 未知") - binding.updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - binding.locationView.text = "经纬度异常,无法查看具体位置" - } else { - val queryParam = RegeocodeQuery( - LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()), - 200f, - GeocodeSearch.AMAP - ) - val latLng = LatLng(device.latGaode.toDouble(), device.lngGaode.toDouble()) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - binding.locationView.text = - String.format("详细位置: ${result?.regeocodeAddress?.formatAddress}") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - - val cameraPosition = CameraPosition(latLng, 18f, 0f, 0f) - val newCameraPosition = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(newCameraPosition, 1500, object : AMap.CancelableCallback { - override fun onFinish() { - //添加Marker - val markerOptions = MarkerOptions().position(latLng) - .icon(BitmapDescriptorFactory.fromResource(R.mipmap.well_location)) - .draggable(false) - aMap.addMarker(markerOptions) - } - - override fun onCancel() { - - } - }) - aMap.setOnMarkerClickListener { - RouteOnMap.startNavigation( - this@MapDeviceBriefActivity, "", latLng - ) - true - } - } - } - } - } - - /**地图相关*********/ - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding.mapView.onCreate(savedInstanceState) - } - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onDestroy() { - binding.mapView.onDestroy() - super.onDestroy() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_group_device_map.xml b/app/src/main/res/layout/activity_group_device_map.xml new file mode 100644 index 0000000..078406e --- /dev/null +++ b/app/src/main/res/layout/activity_group_device_map.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 529403a..8908a3e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,7 +55,7 @@ - + +) : FragmentPagerAdapter(manager) { + + override fun getItem(position: Int): Fragment = pages[position] + + override fun getCount(): Int = pages.size + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + //注释掉父类方法,一直不销毁Fragment + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt deleted file mode 100644 index ab6743f..0000000 --- a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt +++ /dev/null @@ -1,387 +0,0 @@ -package com.casic.smarttube.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.CoordinateConverter -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.Marker -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.FragmentHomeBinding -import com.casic.smarttube.model.MapDeviceModel -import com.casic.smarttube.model.ProjectGroupModel -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.view.AddDeviceActivity -import com.casic.smarttube.vm.DeviceViewModel -import com.casic.smarttube.vm.ProjectGroupViewModel -import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter -import com.pengxh.kt.lite.adapter.ViewHolder -import com.pengxh.kt.lite.base.KotlinBaseFragment -import com.pengxh.kt.lite.extensions.navigatePageTo -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView -import com.pengxh.kt.lite.widget.dialog.AlertControlDialog - - -class HomePageFragment : KotlinBaseFragment(), AMap.OnCameraChangeListener, - AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener, - AMap.OnMapClickListener { - - private val kTag = "HomePageFragment" - private val geocoderSearch by lazy { GeocodeSearch(requireContext()) } - private lateinit var aMap: AMap - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var groupViewModel: ProjectGroupViewModel - private lateinit var groupListAdapter: NormalRecyclerAdapter - private var clickedMarker: Marker? = null - - /** - * 自定义Marker弹出框 - * */ - private var infoView: View? = null - - /** - * 所有设备列表信息集合 - * */ - private var deviceModels: MutableList = ArrayList() - - override fun initViewBinding( - inflater: LayoutInflater, container: ViewGroup? - ): FragmentHomeBinding { - return FragmentHomeBinding.inflate(inflater, container, false) - } - - override fun setupTopBarLayout() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - - } - - override fun onRightClick() { - requireContext().navigatePageTo() - } - }) - } - - override fun observeRequestState() { - groupViewModel.loadState.observe(this) { state -> - when (state) { - LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - //地图初始化 - initMap(savedInstanceState) - - //默认显示所有设备 - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - deviceViewModel.mapDeviceModel.observe(this) { - if (it.code == 200) { - val allMarkerOptions = ArrayList() - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //缓存所有设备详情,点击Marker时候需要 - deviceModels.add(device) - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - //将所有设备信息转化缓存为Marker点 - allMarkerOptions.add( - MarkerOptions().position(LatLng(latitude, longitude)) - .title(device.devcode).snippet(device.modelName) - ) - } - } - } - - allMarkerOptions.forEach { marker -> - aMap.addMarker(marker) - } - - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate, 1500, null) - } - } - deviceViewModel.getMapDeviceList() - - groupViewModel = ViewModelProvider(this)[ProjectGroupViewModel::class.java] - groupViewModel.groupModel.observe(this) { - if (it.code == 200) { - bindRecyclerView(it) - } - } - - groupViewModel.groupDeviceModel.observe(this) { - if (it.code == 200) { - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - } - } - } - //计算所有点的中心点位置 - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate) - } - } - } - - private fun bindRecyclerView(it: ProjectGroupModel) { - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - binding.homeRecyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - // 根据groupId查询组下设备 - groupViewModel.getDeviceListByGroup(item.groupId) - } - }) - } - - override fun initEvent() { - - } - - private fun initMap(savedInstanceState: Bundle?) { - binding.mapView.onCreate(savedInstanceState) - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 - - // 地图缩放监听 - aMap.addOnCameraChangeListener(this) - // marker 点击事件监听 - aMap.addOnMarkerClickListener(this) - // 点击marker弹出自定义popup - aMap.setInfoWindowAdapter(this) - //信息窗点击事件 - aMap.addOnInfoWindowClickListener(this) - //地图点击事件,用于隐藏infoWindow - aMap.setOnMapClickListener(this) - } - - override fun onCameraChange(cameraPosition: CameraPosition?) { - - } - - //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker - override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { - - } - - override fun onMarkerClick(marker: Marker?): Boolean { - marker?.apply { - clickedMarker = this - if (isInfoWindowShown) { - hideInfoWindow() - } else { - showInfoWindow() - } - } - return true - } - - override fun onMapClick(p0: LatLng?) { - clickedMarker?.apply { - if (isInfoWindowShown) { - hideInfoWindow() - } - } - } - - override fun getInfoWindow(marker: Marker?): View? { - if (infoView == null) { - infoView = LayoutInflater.from(requireContext()).inflate( - R.layout.popu_map_info, null - ) - } - marker?.apply { - renderWindow(this, infoView!!) - } - return infoView - } - - private fun renderWindow(marker: Marker, view: View) { - //反射得到popup里面的控件对象 - val deviceCodeView = view.findViewById(R.id.deviceCodeView) - val deviceModelView = view.findViewById(R.id.deviceModelView) - val deviceValueView = view.findViewById(R.id.deviceValueView) - val updateTimeView = view.findViewById(R.id.updateTimeView) - val locationView = view.findViewById(R.id.locationView) - - //绑定数据 - val clicked = marker.position - deviceModels.forEach { device -> - if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { - deviceCodeView.text = String.format("设备编号: ${device.devcode}") - deviceModelView.text = String.format("设备模型: ${device.modelName}") - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(requireActivity()) { - if (it.code == 200) { - deviceValueView.text = String.format("最新浓度: ${it.data.strength}") - updateTimeView.text = String.format("更新时间: ${it.data.uptime}") - } else { - deviceValueView.text = String.format("最新浓度: 未知") - updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - locationView.text = "经纬度异常,无法查看具体位置" - } else { - val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - val address = result?.regeocodeAddress?.formatAddress - val temp = StringBuilder() - if (address!!.length > 16) { - temp.append(address.substring(0, 14)).append("\r\n") - .append(address.substring(16)) - } else { - temp.append(address) - } - locationView.text = String.format("详细位置: $temp") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - } - - /** - * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 - * */ - override fun getInfoContents(p0: Marker?): View? = null - - override fun onInfoWindowClick(marker: Marker?) { - marker?.apply { - AlertControlDialog.Builder().setContext(requireContext()).setTitle("操作提示") - .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - val lat = position.latitude.toString() - val lng = position.longitude.toString() - if (lat.isBlank() || lng.isBlank()) { - "窨井经纬度异常,无法开启导航".show(requireContext()) - return - } - RouteOnMap.startNavigation(requireContext(), snippet, position) - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - - /***以下是地图生命周期管理************************************************************************/ - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - groupViewModel.getProGroupList() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } - - override fun onDestroy() { - super.onDestroy() - binding.mapView.onDestroy() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt index 1d0aa3d..dd09cf5 100644 --- a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt +++ b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt @@ -15,12 +15,16 @@ import com.casic.smarttube.databinding.FragmentOverviewBinding import com.casic.smarttube.model.ProjectGroupModel import com.casic.smarttube.view.GroupDeviceActivity +import com.casic.smarttube.view.GroupDeviceMapActivity import com.casic.smarttube.vm.ProjectGroupViewModel import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseFragment import com.pengxh.kt.lite.divider.RecyclerViewItemDivider import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.EmptyView import com.pengxh.kt.lite.widget.TitleBarView import com.pengxh.kt.lite.widget.dialog.AlertInputDialog @@ -32,6 +36,7 @@ private lateinit var groupViewModel: ProjectGroupViewModel private lateinit var groupListAdapter: NormalRecyclerAdapter private var clickedPosition = 0 + private var isRefresh = false override fun initViewBinding( inflater: LayoutInflater, container: ViewGroup? @@ -40,7 +45,15 @@ } override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + } + + override fun onRightClick() { + requireContext().navigatePageTo() + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { @@ -55,66 +68,93 @@ groupListAdapter.notifyItemChanged(clickedPosition) } } - groupViewModel.getGroupList() + } + + override fun onResume() { + super.onResume() + groupViewModel.getProGroupList() } private fun bindRecyclerView(it: ProjectGroupModel) { val dataRows = it.data - if (dataRows.size == 0) { - binding.emptyView.visibility = View.VISIBLE - binding.recyclerView.visibility = View.GONE - } else { - binding.emptyView.visibility = View.GONE - binding.recyclerView.visibility = View.VISIBLE + when { + isRefresh -> { + binding.refreshView.finishRefresh() + isRefresh = false + groupListAdapter.refresh(dataRows) + } - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_over_view_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - .setOnClickListener(R.id.editGroupNameView) { - clickedPosition = position - editGroupName(item) - } - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) + else -> { + if (dataRows.size == 0) { + binding.emptyView.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE + } else { + binding.emptyView.visibility = View.GONE + binding.recyclerView.visibility = View.VISIBLE + + groupListAdapter = object : NormalRecyclerAdapter( + R.layout.item_group_over_view_rv_l, it.data + ) { + override fun convertView( + viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel + ) { + viewHolder.setText(R.id.groupNameView, item.groupId) + .setText(R.id.totalDeviceNumView, item.totalDevice) + .setText(R.id.inUseDeviceNumView, item.alive) + .setText(R.id.notUseDeviceNumView, item.unalive) + .setOnClickListener(R.id.editGroupNameView) { + clickedPosition = position + editGroupName(item) } - } + if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { + viewHolder.setText( + R.id.groupLocationView, + "经纬度异常,无法查看具体位置" + ) + } else { + val point = + LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched( + result: RegeocodeResult?, + rCode: Int + ) { + if (rCode == 1000) { + viewHolder.setText( + R.id.groupLocationView, + String.format("${result?.regeocodeAddress?.formatAddress}") + ) + } + } - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + override fun onGeocodeSearched( + result: GeocodeResult?, + rCode: Int + ) { + } + }) } - }) + } } + binding.recyclerView.addItemDecoration( + RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) + ) + binding.recyclerView.adapter = groupListAdapter + groupListAdapter.setOnItemClickedListener(object : + NormalRecyclerAdapter.OnItemClickedListener { + override fun onItemClicked( + position: Int, + item: ProjectGroupModel.DataModel + ) { + requireContext().navigatePageTo(item.groupId) + } + }) } } - binding.recyclerView.addItemDecoration( - RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) - ) - binding.recyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - requireContext().navigatePageTo(item.groupId) - } - }) } } @@ -139,18 +179,31 @@ } override fun observeRequestState() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - + groupViewModel.loadState.observe(this) { + if (isRefresh) { + return@observe } + when (it) { + LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中,请稍后...") - override fun onRightClick() { - groupViewModel.getProGroupList() + LoadState.Success -> { + LoadingDialog.dismiss() + } + + LoadState.Fail -> { + LoadingDialog.dismiss() + "数据加载失败,请重试".show(requireContext()) + } } - }) + } } override fun initEvent() { + binding.refreshView.setOnRefreshListener { + isRefresh = true + groupViewModel.getProGroupList() + } + binding.emptyView.setOnClickListener(object : EmptyView.OnClickListener { override fun onReloadButtonClicked() { groupViewModel.getProGroupList() diff --git a/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt new file mode 100644 index 0000000..c33c40e --- /dev/null +++ b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt @@ -0,0 +1,288 @@ +package com.casic.smarttube.view + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.lifecycle.ViewModelProvider +import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.CameraUpdateFactory +import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.CameraPosition +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.Marker +import com.amap.api.maps.model.MarkerOptions +import com.amap.api.services.core.LatLonPoint +import com.amap.api.services.geocoder.GeocodeResult +import com.amap.api.services.geocoder.GeocodeSearch +import com.amap.api.services.geocoder.RegeocodeQuery +import com.amap.api.services.geocoder.RegeocodeResult +import com.casic.smarttube.R +import com.casic.smarttube.databinding.ActivityGroupDeviceMapBinding +import com.casic.smarttube.extensions.initImmersionBar +import com.casic.smarttube.model.MapDeviceModel +import com.casic.smarttube.utils.RouteOnMap +import com.casic.smarttube.vm.DeviceViewModel +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog + +class GroupDeviceMapActivity : KotlinBaseActivity(), + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, + AMap.OnInfoWindowClickListener, AMap.OnMapClickListener { + + private val context = this + private val geocoderSearch by lazy { GeocodeSearch(this) } + private lateinit var aMap: AMap + private lateinit var deviceViewModel: DeviceViewModel + private var clickedMarker: Marker? = null + + /** + * 自定义Marker弹出框 + * */ + private var infoView: View? = null + + /** + * 所有设备列表信息集合 + * */ + private var deviceModels: MutableList = ArrayList() + + override fun initViewBinding(): ActivityGroupDeviceMapBinding { + return ActivityGroupDeviceMapBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + } + + override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + //地图初始化 + initMap(savedInstanceState) + + //默认显示所有设备 + deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] + deviceViewModel.mapDeviceModel.observe(this) { + if (it.code == 200) { + val allMarkerOptions = ArrayList() + val latitudeList = ArrayList() + val longitudeList = ArrayList() + it.data.forEach { device -> + val lat = device.latGaode.toString() + val lng = device.lngGaode.toString() + if (lat.isNotBlank() && lng.isNotBlank()) { + //返回true代表当前位置在大陆、港澳地区,反之不在 + val latitude = lat.toDouble() + val longitude = lng.toDouble() + if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { + //缓存所有设备详情,点击Marker时候需要 + deviceModels.add(device) + //分别缓存经、纬度 + latitudeList.add(latitude) + longitudeList.add(longitude) + //将所有设备信息转化缓存为Marker点 + allMarkerOptions.add( + MarkerOptions().position(LatLng(latitude, longitude)) + .title(device.devcode).snippet(device.modelName) + ) + } + } + } + + allMarkerOptions.forEach { marker -> + aMap.addMarker(marker) + } + + val latLng = LatLng(latitudeList[0], longitudeList[0]) + val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) + val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) + aMap.animateCamera(cameraUpdate, 1500, null) + } + } + deviceViewModel.getMapDeviceList() + } + + override fun initEvent() { + + } + + private fun initMap(savedInstanceState: Bundle?) { + binding.mapView.onCreate(savedInstanceState) + aMap = binding.mapView.map + aMap.mapType = AMap.MAP_TYPE_NORMAL + val uiSettings = aMap.uiSettings + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 + + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker 点击事件监听 + aMap.addOnMarkerClickListener(this) + // 点击marker弹出自定义popup + aMap.setInfoWindowAdapter(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + //地图点击事件,用于隐藏infoWindow + aMap.setOnMapClickListener(this) + } + + override fun onCameraChange(cameraPosition: CameraPosition?) { + + } + + //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker + override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { + + } + + override fun onMarkerClick(marker: Marker?): Boolean { + marker?.apply { + clickedMarker = this + if (isInfoWindowShown) { + hideInfoWindow() + } else { + showInfoWindow() + } + } + return true + } + + override fun onMapClick(p0: LatLng?) { + clickedMarker?.apply { + if (isInfoWindowShown) { + hideInfoWindow() + } + } + } + + override fun getInfoWindow(marker: Marker?): View? { + if (infoView == null) { + infoView = LayoutInflater.from(this).inflate(R.layout.popu_map_info, null) + } + marker?.apply { + renderWindow(this, infoView!!) + } + return infoView + } + + private fun renderWindow(marker: Marker, view: View) { + //反射得到popup里面的控件对象 + val deviceCodeView = view.findViewById(R.id.deviceCodeView) + val deviceModelView = view.findViewById(R.id.deviceModelView) + val deviceValueView = view.findViewById(R.id.deviceValueView) + val updateTimeView = view.findViewById(R.id.updateTimeView) + val locationView = view.findViewById(R.id.locationView) + + //绑定数据 + val clicked = marker.position + deviceModels.forEach { device -> + if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { + deviceCodeView.text = String.format("设备编号: ${device.devcode}") + deviceModelView.text = String.format("设备模型: ${device.modelName}") + //获取设备最新浓度信息 + deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) + deviceViewModel.lastDataModel.observe(this) { + if (it.code == 200) { + deviceValueView.text = String.format("最新浓度: ${it.data.strength}") + updateTimeView.text = String.format("更新时间: ${it.data.uptime}") + } else { + deviceValueView.text = String.format("最新浓度: 未知") + updateTimeView.text = String.format("更新时间: 未知") + } + } + if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { + locationView.text = "经纬度异常,无法查看具体位置" + } else { + val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { + if (rCode == 1000) { + val address = result?.regeocodeAddress?.formatAddress + val temp = StringBuilder() + if (address!!.length > 16) { + temp.append(address.substring(0, 14)).append("\r\n") + .append(address.substring(16)) + } else { + temp.append(address) + } + locationView.text = String.format("详细位置: $temp") + } + } + + override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + + } + }) + } + } + } + } + + /** + * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 + * */ + override fun getInfoContents(p0: Marker?): View? = null + + override fun onInfoWindowClick(marker: Marker?) { + marker?.apply { + AlertControlDialog.Builder().setContext(context).setTitle("操作提示") + .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + val lat = position.latitude.toString() + val lng = position.longitude.toString() + if (lat.isBlank() || lng.isBlank()) { + "窨井经纬度异常,无法开启导航".show(context) + return + } + RouteOnMap.startNavigation(context, snippet, position) + } + + override fun onCancelClick() { + + } + }).build().show() + } + } + + /***以下是地图生命周期管理************************************************************************/ + + override fun onResume() { + super.onResume() + binding.mapView.onResume() + } + + override fun onPause() { + super.onPause() + binding.mapView.onPause() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + binding.mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + super.onDestroy() + binding.mapView.onDestroy() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt index c7f06c9..b6b4e8a 100644 --- a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt +++ b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt @@ -3,29 +3,25 @@ import android.os.Bundle import android.view.KeyEvent import android.view.MenuItem -import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter import androidx.viewpager.widget.ViewPager import com.casic.smarttube.R +import com.casic.smarttube.adapter.TabPageViewAdapter import com.casic.smarttube.databinding.ActivityMainBinding import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.fragment.HomePageFragment import com.casic.smarttube.fragment.MinePageFragment import com.casic.smarttube.fragment.OverviewFragment -import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show class MainActivity : KotlinBaseActivity() { private var menuItem: MenuItem? = null - private var fragmentPages: MutableList = ArrayList() + private var fragmentPages: ArrayList = ArrayList() private var clickTime: Long = 0 init { - fragmentPages.add(HomePageFragment()) fragmentPages.add(OverviewFragment()) fragmentPages.add(MinePageFragment()) } @@ -35,30 +31,13 @@ } override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) } override fun initOnCreate(savedInstanceState: Bundle?) { //保留icon原图颜色 binding.bottomNavigation.itemIconTintList = null - binding.bottomNavigation.setOnItemSelectedListener { menuItem -> - when (menuItem.itemId) { - R.id.nav_home -> { - binding.mainViewPager.currentItem = 0 - } - - R.id.nav_overview -> { - binding.mainViewPager.currentItem = 1 - } - - R.id.nav_mine -> { - binding.mainViewPager.currentItem = 2 - } - } - false - } - binding.mainViewPager.adapter = ViewPagerAdapter(fragmentPages, supportFragmentManager) + binding.mainViewPager.adapter = TabPageViewAdapter(supportFragmentManager, fragmentPages) } override fun observeRequestState() { @@ -66,6 +45,18 @@ } override fun initEvent() { + binding.bottomNavigation.setOnItemSelectedListener { menuItem -> + when (menuItem.itemId) { + R.id.nav_overview -> { + binding.mainViewPager.currentItem = 0 + } + + R.id.nav_mine -> { + binding.mainViewPager.currentItem = 1 + } + } + false + } binding.mainViewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageScrollStateChanged(state: Int) { @@ -87,6 +78,10 @@ menuItem!!.isChecked = true } }) + + binding.addDeviceButton.setOnClickListener { + navigatePageTo() + } } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { @@ -100,18 +95,4 @@ } } else super.onKeyDown(keyCode, event) } - - inner class ViewPagerAdapter(list: MutableList, manager: FragmentManager) : - FragmentPagerAdapter(manager) { - - private var viewPages: List = list - - override fun getItem(position: Int): Fragment = viewPages[position] - - override fun getCount(): Int = viewPages.size - - override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { - - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt b/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt deleted file mode 100644 index b5be93b..0000000 --- a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt +++ /dev/null @@ -1,174 +0,0 @@ -package com.casic.smarttube.view - -import android.os.Bundle -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.model.BitmapDescriptorFactory -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.ActivityMapDeviceBriefBinding -import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.vm.DeviceViewModel -import com.gyf.immersionbar.ImmersionBar -import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.utils.LiteKitConstant -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView - -class MapDeviceBriefActivity : KotlinBaseActivity() { - - private val kTag = "MapDeviceBriefActivity" - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var aMap: AMap - private lateinit var params: ArrayList - private val geocoderSearch by lazy { GeocodeSearch(this) } - - - override fun initViewBinding(): ActivityMapDeviceBriefBinding { - return ActivityMapDeviceBriefBinding.inflate(layoutInflater) - } - - override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - finish() - } - - override fun onRightClick() { - - } - }) - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图旋转 - - this.params = intent.getStringArrayListExtra(LiteKitConstant.INTENT_PARAM_KEY)!! - - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - } - - override fun observeRequestState() { - deviceViewModel.loadState.observe(this) { - when (it) { - LoadState.Loading -> LoadingDialog.show(this, "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initEvent() { - deviceViewModel.obtainDeviceDetail(params[0], params[1]) - deviceViewModel.deviceDetailModel.observe(this) { - if (it.code == 200) { - val device = it.data - - binding.deviceCodeView.text = String.format("设备编号: ${device.devcode}") - binding.deviceModelView.text = String.format("设备模型: ${params[2]}") - - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(this) { v -> - if (v.code == 200) { - binding.deviceValueView.text = String.format("最新浓度: ${v.data.strength}") - binding.updateTimeView.text = String.format("更新时间: ${v.data.uptime}") - } else { - binding.deviceValueView.text = String.format("最新浓度: 未知") - binding.updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - binding.locationView.text = "经纬度异常,无法查看具体位置" - } else { - val queryParam = RegeocodeQuery( - LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()), - 200f, - GeocodeSearch.AMAP - ) - val latLng = LatLng(device.latGaode.toDouble(), device.lngGaode.toDouble()) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - binding.locationView.text = - String.format("详细位置: ${result?.regeocodeAddress?.formatAddress}") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - - val cameraPosition = CameraPosition(latLng, 18f, 0f, 0f) - val newCameraPosition = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(newCameraPosition, 1500, object : AMap.CancelableCallback { - override fun onFinish() { - //添加Marker - val markerOptions = MarkerOptions().position(latLng) - .icon(BitmapDescriptorFactory.fromResource(R.mipmap.well_location)) - .draggable(false) - aMap.addMarker(markerOptions) - } - - override fun onCancel() { - - } - }) - aMap.setOnMarkerClickListener { - RouteOnMap.startNavigation( - this@MapDeviceBriefActivity, "", latLng - ) - true - } - } - } - } - } - - /**地图相关*********/ - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding.mapView.onCreate(savedInstanceState) - } - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onDestroy() { - binding.mapView.onDestroy() - super.onDestroy() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_group_device_map.xml b/app/src/main/res/layout/activity_group_device_map.xml new file mode 100644 index 0000000..078406e --- /dev/null +++ b/app/src/main/res/layout/activity_group_device_map.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index bb4ff3c..ffe86f1 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,26 +1,40 @@ - + android:background="@color/mainBackColor"> - + android:layout_height="match_parent" + android:orientation="vertical"> - - + + + + + - \ No newline at end of file + android:layout_gravity="center|bottom" + android:backgroundTint="@color/white" + android:contentDescription="@string/app_name" + android:src="@android:drawable/ic_input_add" + app:borderWidth="0dp" + app:elevation="@dimen/dp_5" /> + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 529403a..8908a3e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,7 +55,7 @@ - + +) : FragmentPagerAdapter(manager) { + + override fun getItem(position: Int): Fragment = pages[position] + + override fun getCount(): Int = pages.size + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + //注释掉父类方法,一直不销毁Fragment + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt deleted file mode 100644 index ab6743f..0000000 --- a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt +++ /dev/null @@ -1,387 +0,0 @@ -package com.casic.smarttube.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.CoordinateConverter -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.Marker -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.FragmentHomeBinding -import com.casic.smarttube.model.MapDeviceModel -import com.casic.smarttube.model.ProjectGroupModel -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.view.AddDeviceActivity -import com.casic.smarttube.vm.DeviceViewModel -import com.casic.smarttube.vm.ProjectGroupViewModel -import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter -import com.pengxh.kt.lite.adapter.ViewHolder -import com.pengxh.kt.lite.base.KotlinBaseFragment -import com.pengxh.kt.lite.extensions.navigatePageTo -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView -import com.pengxh.kt.lite.widget.dialog.AlertControlDialog - - -class HomePageFragment : KotlinBaseFragment(), AMap.OnCameraChangeListener, - AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener, - AMap.OnMapClickListener { - - private val kTag = "HomePageFragment" - private val geocoderSearch by lazy { GeocodeSearch(requireContext()) } - private lateinit var aMap: AMap - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var groupViewModel: ProjectGroupViewModel - private lateinit var groupListAdapter: NormalRecyclerAdapter - private var clickedMarker: Marker? = null - - /** - * 自定义Marker弹出框 - * */ - private var infoView: View? = null - - /** - * 所有设备列表信息集合 - * */ - private var deviceModels: MutableList = ArrayList() - - override fun initViewBinding( - inflater: LayoutInflater, container: ViewGroup? - ): FragmentHomeBinding { - return FragmentHomeBinding.inflate(inflater, container, false) - } - - override fun setupTopBarLayout() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - - } - - override fun onRightClick() { - requireContext().navigatePageTo() - } - }) - } - - override fun observeRequestState() { - groupViewModel.loadState.observe(this) { state -> - when (state) { - LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - //地图初始化 - initMap(savedInstanceState) - - //默认显示所有设备 - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - deviceViewModel.mapDeviceModel.observe(this) { - if (it.code == 200) { - val allMarkerOptions = ArrayList() - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //缓存所有设备详情,点击Marker时候需要 - deviceModels.add(device) - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - //将所有设备信息转化缓存为Marker点 - allMarkerOptions.add( - MarkerOptions().position(LatLng(latitude, longitude)) - .title(device.devcode).snippet(device.modelName) - ) - } - } - } - - allMarkerOptions.forEach { marker -> - aMap.addMarker(marker) - } - - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate, 1500, null) - } - } - deviceViewModel.getMapDeviceList() - - groupViewModel = ViewModelProvider(this)[ProjectGroupViewModel::class.java] - groupViewModel.groupModel.observe(this) { - if (it.code == 200) { - bindRecyclerView(it) - } - } - - groupViewModel.groupDeviceModel.observe(this) { - if (it.code == 200) { - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - } - } - } - //计算所有点的中心点位置 - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate) - } - } - } - - private fun bindRecyclerView(it: ProjectGroupModel) { - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - binding.homeRecyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - // 根据groupId查询组下设备 - groupViewModel.getDeviceListByGroup(item.groupId) - } - }) - } - - override fun initEvent() { - - } - - private fun initMap(savedInstanceState: Bundle?) { - binding.mapView.onCreate(savedInstanceState) - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 - - // 地图缩放监听 - aMap.addOnCameraChangeListener(this) - // marker 点击事件监听 - aMap.addOnMarkerClickListener(this) - // 点击marker弹出自定义popup - aMap.setInfoWindowAdapter(this) - //信息窗点击事件 - aMap.addOnInfoWindowClickListener(this) - //地图点击事件,用于隐藏infoWindow - aMap.setOnMapClickListener(this) - } - - override fun onCameraChange(cameraPosition: CameraPosition?) { - - } - - //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker - override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { - - } - - override fun onMarkerClick(marker: Marker?): Boolean { - marker?.apply { - clickedMarker = this - if (isInfoWindowShown) { - hideInfoWindow() - } else { - showInfoWindow() - } - } - return true - } - - override fun onMapClick(p0: LatLng?) { - clickedMarker?.apply { - if (isInfoWindowShown) { - hideInfoWindow() - } - } - } - - override fun getInfoWindow(marker: Marker?): View? { - if (infoView == null) { - infoView = LayoutInflater.from(requireContext()).inflate( - R.layout.popu_map_info, null - ) - } - marker?.apply { - renderWindow(this, infoView!!) - } - return infoView - } - - private fun renderWindow(marker: Marker, view: View) { - //反射得到popup里面的控件对象 - val deviceCodeView = view.findViewById(R.id.deviceCodeView) - val deviceModelView = view.findViewById(R.id.deviceModelView) - val deviceValueView = view.findViewById(R.id.deviceValueView) - val updateTimeView = view.findViewById(R.id.updateTimeView) - val locationView = view.findViewById(R.id.locationView) - - //绑定数据 - val clicked = marker.position - deviceModels.forEach { device -> - if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { - deviceCodeView.text = String.format("设备编号: ${device.devcode}") - deviceModelView.text = String.format("设备模型: ${device.modelName}") - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(requireActivity()) { - if (it.code == 200) { - deviceValueView.text = String.format("最新浓度: ${it.data.strength}") - updateTimeView.text = String.format("更新时间: ${it.data.uptime}") - } else { - deviceValueView.text = String.format("最新浓度: 未知") - updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - locationView.text = "经纬度异常,无法查看具体位置" - } else { - val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - val address = result?.regeocodeAddress?.formatAddress - val temp = StringBuilder() - if (address!!.length > 16) { - temp.append(address.substring(0, 14)).append("\r\n") - .append(address.substring(16)) - } else { - temp.append(address) - } - locationView.text = String.format("详细位置: $temp") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - } - - /** - * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 - * */ - override fun getInfoContents(p0: Marker?): View? = null - - override fun onInfoWindowClick(marker: Marker?) { - marker?.apply { - AlertControlDialog.Builder().setContext(requireContext()).setTitle("操作提示") - .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - val lat = position.latitude.toString() - val lng = position.longitude.toString() - if (lat.isBlank() || lng.isBlank()) { - "窨井经纬度异常,无法开启导航".show(requireContext()) - return - } - RouteOnMap.startNavigation(requireContext(), snippet, position) - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - - /***以下是地图生命周期管理************************************************************************/ - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - groupViewModel.getProGroupList() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } - - override fun onDestroy() { - super.onDestroy() - binding.mapView.onDestroy() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt index 1d0aa3d..dd09cf5 100644 --- a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt +++ b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt @@ -15,12 +15,16 @@ import com.casic.smarttube.databinding.FragmentOverviewBinding import com.casic.smarttube.model.ProjectGroupModel import com.casic.smarttube.view.GroupDeviceActivity +import com.casic.smarttube.view.GroupDeviceMapActivity import com.casic.smarttube.vm.ProjectGroupViewModel import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseFragment import com.pengxh.kt.lite.divider.RecyclerViewItemDivider import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.EmptyView import com.pengxh.kt.lite.widget.TitleBarView import com.pengxh.kt.lite.widget.dialog.AlertInputDialog @@ -32,6 +36,7 @@ private lateinit var groupViewModel: ProjectGroupViewModel private lateinit var groupListAdapter: NormalRecyclerAdapter private var clickedPosition = 0 + private var isRefresh = false override fun initViewBinding( inflater: LayoutInflater, container: ViewGroup? @@ -40,7 +45,15 @@ } override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + } + + override fun onRightClick() { + requireContext().navigatePageTo() + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { @@ -55,66 +68,93 @@ groupListAdapter.notifyItemChanged(clickedPosition) } } - groupViewModel.getGroupList() + } + + override fun onResume() { + super.onResume() + groupViewModel.getProGroupList() } private fun bindRecyclerView(it: ProjectGroupModel) { val dataRows = it.data - if (dataRows.size == 0) { - binding.emptyView.visibility = View.VISIBLE - binding.recyclerView.visibility = View.GONE - } else { - binding.emptyView.visibility = View.GONE - binding.recyclerView.visibility = View.VISIBLE + when { + isRefresh -> { + binding.refreshView.finishRefresh() + isRefresh = false + groupListAdapter.refresh(dataRows) + } - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_over_view_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - .setOnClickListener(R.id.editGroupNameView) { - clickedPosition = position - editGroupName(item) - } - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) + else -> { + if (dataRows.size == 0) { + binding.emptyView.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE + } else { + binding.emptyView.visibility = View.GONE + binding.recyclerView.visibility = View.VISIBLE + + groupListAdapter = object : NormalRecyclerAdapter( + R.layout.item_group_over_view_rv_l, it.data + ) { + override fun convertView( + viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel + ) { + viewHolder.setText(R.id.groupNameView, item.groupId) + .setText(R.id.totalDeviceNumView, item.totalDevice) + .setText(R.id.inUseDeviceNumView, item.alive) + .setText(R.id.notUseDeviceNumView, item.unalive) + .setOnClickListener(R.id.editGroupNameView) { + clickedPosition = position + editGroupName(item) } - } + if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { + viewHolder.setText( + R.id.groupLocationView, + "经纬度异常,无法查看具体位置" + ) + } else { + val point = + LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched( + result: RegeocodeResult?, + rCode: Int + ) { + if (rCode == 1000) { + viewHolder.setText( + R.id.groupLocationView, + String.format("${result?.regeocodeAddress?.formatAddress}") + ) + } + } - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + override fun onGeocodeSearched( + result: GeocodeResult?, + rCode: Int + ) { + } + }) } - }) + } } + binding.recyclerView.addItemDecoration( + RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) + ) + binding.recyclerView.adapter = groupListAdapter + groupListAdapter.setOnItemClickedListener(object : + NormalRecyclerAdapter.OnItemClickedListener { + override fun onItemClicked( + position: Int, + item: ProjectGroupModel.DataModel + ) { + requireContext().navigatePageTo(item.groupId) + } + }) } } - binding.recyclerView.addItemDecoration( - RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) - ) - binding.recyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - requireContext().navigatePageTo(item.groupId) - } - }) } } @@ -139,18 +179,31 @@ } override fun observeRequestState() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - + groupViewModel.loadState.observe(this) { + if (isRefresh) { + return@observe } + when (it) { + LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中,请稍后...") - override fun onRightClick() { - groupViewModel.getProGroupList() + LoadState.Success -> { + LoadingDialog.dismiss() + } + + LoadState.Fail -> { + LoadingDialog.dismiss() + "数据加载失败,请重试".show(requireContext()) + } } - }) + } } override fun initEvent() { + binding.refreshView.setOnRefreshListener { + isRefresh = true + groupViewModel.getProGroupList() + } + binding.emptyView.setOnClickListener(object : EmptyView.OnClickListener { override fun onReloadButtonClicked() { groupViewModel.getProGroupList() diff --git a/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt new file mode 100644 index 0000000..c33c40e --- /dev/null +++ b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt @@ -0,0 +1,288 @@ +package com.casic.smarttube.view + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.lifecycle.ViewModelProvider +import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.CameraUpdateFactory +import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.CameraPosition +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.Marker +import com.amap.api.maps.model.MarkerOptions +import com.amap.api.services.core.LatLonPoint +import com.amap.api.services.geocoder.GeocodeResult +import com.amap.api.services.geocoder.GeocodeSearch +import com.amap.api.services.geocoder.RegeocodeQuery +import com.amap.api.services.geocoder.RegeocodeResult +import com.casic.smarttube.R +import com.casic.smarttube.databinding.ActivityGroupDeviceMapBinding +import com.casic.smarttube.extensions.initImmersionBar +import com.casic.smarttube.model.MapDeviceModel +import com.casic.smarttube.utils.RouteOnMap +import com.casic.smarttube.vm.DeviceViewModel +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog + +class GroupDeviceMapActivity : KotlinBaseActivity(), + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, + AMap.OnInfoWindowClickListener, AMap.OnMapClickListener { + + private val context = this + private val geocoderSearch by lazy { GeocodeSearch(this) } + private lateinit var aMap: AMap + private lateinit var deviceViewModel: DeviceViewModel + private var clickedMarker: Marker? = null + + /** + * 自定义Marker弹出框 + * */ + private var infoView: View? = null + + /** + * 所有设备列表信息集合 + * */ + private var deviceModels: MutableList = ArrayList() + + override fun initViewBinding(): ActivityGroupDeviceMapBinding { + return ActivityGroupDeviceMapBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + } + + override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + //地图初始化 + initMap(savedInstanceState) + + //默认显示所有设备 + deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] + deviceViewModel.mapDeviceModel.observe(this) { + if (it.code == 200) { + val allMarkerOptions = ArrayList() + val latitudeList = ArrayList() + val longitudeList = ArrayList() + it.data.forEach { device -> + val lat = device.latGaode.toString() + val lng = device.lngGaode.toString() + if (lat.isNotBlank() && lng.isNotBlank()) { + //返回true代表当前位置在大陆、港澳地区,反之不在 + val latitude = lat.toDouble() + val longitude = lng.toDouble() + if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { + //缓存所有设备详情,点击Marker时候需要 + deviceModels.add(device) + //分别缓存经、纬度 + latitudeList.add(latitude) + longitudeList.add(longitude) + //将所有设备信息转化缓存为Marker点 + allMarkerOptions.add( + MarkerOptions().position(LatLng(latitude, longitude)) + .title(device.devcode).snippet(device.modelName) + ) + } + } + } + + allMarkerOptions.forEach { marker -> + aMap.addMarker(marker) + } + + val latLng = LatLng(latitudeList[0], longitudeList[0]) + val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) + val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) + aMap.animateCamera(cameraUpdate, 1500, null) + } + } + deviceViewModel.getMapDeviceList() + } + + override fun initEvent() { + + } + + private fun initMap(savedInstanceState: Bundle?) { + binding.mapView.onCreate(savedInstanceState) + aMap = binding.mapView.map + aMap.mapType = AMap.MAP_TYPE_NORMAL + val uiSettings = aMap.uiSettings + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 + + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker 点击事件监听 + aMap.addOnMarkerClickListener(this) + // 点击marker弹出自定义popup + aMap.setInfoWindowAdapter(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + //地图点击事件,用于隐藏infoWindow + aMap.setOnMapClickListener(this) + } + + override fun onCameraChange(cameraPosition: CameraPosition?) { + + } + + //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker + override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { + + } + + override fun onMarkerClick(marker: Marker?): Boolean { + marker?.apply { + clickedMarker = this + if (isInfoWindowShown) { + hideInfoWindow() + } else { + showInfoWindow() + } + } + return true + } + + override fun onMapClick(p0: LatLng?) { + clickedMarker?.apply { + if (isInfoWindowShown) { + hideInfoWindow() + } + } + } + + override fun getInfoWindow(marker: Marker?): View? { + if (infoView == null) { + infoView = LayoutInflater.from(this).inflate(R.layout.popu_map_info, null) + } + marker?.apply { + renderWindow(this, infoView!!) + } + return infoView + } + + private fun renderWindow(marker: Marker, view: View) { + //反射得到popup里面的控件对象 + val deviceCodeView = view.findViewById(R.id.deviceCodeView) + val deviceModelView = view.findViewById(R.id.deviceModelView) + val deviceValueView = view.findViewById(R.id.deviceValueView) + val updateTimeView = view.findViewById(R.id.updateTimeView) + val locationView = view.findViewById(R.id.locationView) + + //绑定数据 + val clicked = marker.position + deviceModels.forEach { device -> + if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { + deviceCodeView.text = String.format("设备编号: ${device.devcode}") + deviceModelView.text = String.format("设备模型: ${device.modelName}") + //获取设备最新浓度信息 + deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) + deviceViewModel.lastDataModel.observe(this) { + if (it.code == 200) { + deviceValueView.text = String.format("最新浓度: ${it.data.strength}") + updateTimeView.text = String.format("更新时间: ${it.data.uptime}") + } else { + deviceValueView.text = String.format("最新浓度: 未知") + updateTimeView.text = String.format("更新时间: 未知") + } + } + if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { + locationView.text = "经纬度异常,无法查看具体位置" + } else { + val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { + if (rCode == 1000) { + val address = result?.regeocodeAddress?.formatAddress + val temp = StringBuilder() + if (address!!.length > 16) { + temp.append(address.substring(0, 14)).append("\r\n") + .append(address.substring(16)) + } else { + temp.append(address) + } + locationView.text = String.format("详细位置: $temp") + } + } + + override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + + } + }) + } + } + } + } + + /** + * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 + * */ + override fun getInfoContents(p0: Marker?): View? = null + + override fun onInfoWindowClick(marker: Marker?) { + marker?.apply { + AlertControlDialog.Builder().setContext(context).setTitle("操作提示") + .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + val lat = position.latitude.toString() + val lng = position.longitude.toString() + if (lat.isBlank() || lng.isBlank()) { + "窨井经纬度异常,无法开启导航".show(context) + return + } + RouteOnMap.startNavigation(context, snippet, position) + } + + override fun onCancelClick() { + + } + }).build().show() + } + } + + /***以下是地图生命周期管理************************************************************************/ + + override fun onResume() { + super.onResume() + binding.mapView.onResume() + } + + override fun onPause() { + super.onPause() + binding.mapView.onPause() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + binding.mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + super.onDestroy() + binding.mapView.onDestroy() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt index c7f06c9..b6b4e8a 100644 --- a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt +++ b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt @@ -3,29 +3,25 @@ import android.os.Bundle import android.view.KeyEvent import android.view.MenuItem -import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter import androidx.viewpager.widget.ViewPager import com.casic.smarttube.R +import com.casic.smarttube.adapter.TabPageViewAdapter import com.casic.smarttube.databinding.ActivityMainBinding import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.fragment.HomePageFragment import com.casic.smarttube.fragment.MinePageFragment import com.casic.smarttube.fragment.OverviewFragment -import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show class MainActivity : KotlinBaseActivity() { private var menuItem: MenuItem? = null - private var fragmentPages: MutableList = ArrayList() + private var fragmentPages: ArrayList = ArrayList() private var clickTime: Long = 0 init { - fragmentPages.add(HomePageFragment()) fragmentPages.add(OverviewFragment()) fragmentPages.add(MinePageFragment()) } @@ -35,30 +31,13 @@ } override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) } override fun initOnCreate(savedInstanceState: Bundle?) { //保留icon原图颜色 binding.bottomNavigation.itemIconTintList = null - binding.bottomNavigation.setOnItemSelectedListener { menuItem -> - when (menuItem.itemId) { - R.id.nav_home -> { - binding.mainViewPager.currentItem = 0 - } - - R.id.nav_overview -> { - binding.mainViewPager.currentItem = 1 - } - - R.id.nav_mine -> { - binding.mainViewPager.currentItem = 2 - } - } - false - } - binding.mainViewPager.adapter = ViewPagerAdapter(fragmentPages, supportFragmentManager) + binding.mainViewPager.adapter = TabPageViewAdapter(supportFragmentManager, fragmentPages) } override fun observeRequestState() { @@ -66,6 +45,18 @@ } override fun initEvent() { + binding.bottomNavigation.setOnItemSelectedListener { menuItem -> + when (menuItem.itemId) { + R.id.nav_overview -> { + binding.mainViewPager.currentItem = 0 + } + + R.id.nav_mine -> { + binding.mainViewPager.currentItem = 1 + } + } + false + } binding.mainViewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageScrollStateChanged(state: Int) { @@ -87,6 +78,10 @@ menuItem!!.isChecked = true } }) + + binding.addDeviceButton.setOnClickListener { + navigatePageTo() + } } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { @@ -100,18 +95,4 @@ } } else super.onKeyDown(keyCode, event) } - - inner class ViewPagerAdapter(list: MutableList, manager: FragmentManager) : - FragmentPagerAdapter(manager) { - - private var viewPages: List = list - - override fun getItem(position: Int): Fragment = viewPages[position] - - override fun getCount(): Int = viewPages.size - - override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { - - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt b/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt deleted file mode 100644 index b5be93b..0000000 --- a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt +++ /dev/null @@ -1,174 +0,0 @@ -package com.casic.smarttube.view - -import android.os.Bundle -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.model.BitmapDescriptorFactory -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.ActivityMapDeviceBriefBinding -import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.vm.DeviceViewModel -import com.gyf.immersionbar.ImmersionBar -import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.utils.LiteKitConstant -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView - -class MapDeviceBriefActivity : KotlinBaseActivity() { - - private val kTag = "MapDeviceBriefActivity" - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var aMap: AMap - private lateinit var params: ArrayList - private val geocoderSearch by lazy { GeocodeSearch(this) } - - - override fun initViewBinding(): ActivityMapDeviceBriefBinding { - return ActivityMapDeviceBriefBinding.inflate(layoutInflater) - } - - override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - finish() - } - - override fun onRightClick() { - - } - }) - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图旋转 - - this.params = intent.getStringArrayListExtra(LiteKitConstant.INTENT_PARAM_KEY)!! - - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - } - - override fun observeRequestState() { - deviceViewModel.loadState.observe(this) { - when (it) { - LoadState.Loading -> LoadingDialog.show(this, "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initEvent() { - deviceViewModel.obtainDeviceDetail(params[0], params[1]) - deviceViewModel.deviceDetailModel.observe(this) { - if (it.code == 200) { - val device = it.data - - binding.deviceCodeView.text = String.format("设备编号: ${device.devcode}") - binding.deviceModelView.text = String.format("设备模型: ${params[2]}") - - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(this) { v -> - if (v.code == 200) { - binding.deviceValueView.text = String.format("最新浓度: ${v.data.strength}") - binding.updateTimeView.text = String.format("更新时间: ${v.data.uptime}") - } else { - binding.deviceValueView.text = String.format("最新浓度: 未知") - binding.updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - binding.locationView.text = "经纬度异常,无法查看具体位置" - } else { - val queryParam = RegeocodeQuery( - LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()), - 200f, - GeocodeSearch.AMAP - ) - val latLng = LatLng(device.latGaode.toDouble(), device.lngGaode.toDouble()) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - binding.locationView.text = - String.format("详细位置: ${result?.regeocodeAddress?.formatAddress}") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - - val cameraPosition = CameraPosition(latLng, 18f, 0f, 0f) - val newCameraPosition = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(newCameraPosition, 1500, object : AMap.CancelableCallback { - override fun onFinish() { - //添加Marker - val markerOptions = MarkerOptions().position(latLng) - .icon(BitmapDescriptorFactory.fromResource(R.mipmap.well_location)) - .draggable(false) - aMap.addMarker(markerOptions) - } - - override fun onCancel() { - - } - }) - aMap.setOnMarkerClickListener { - RouteOnMap.startNavigation( - this@MapDeviceBriefActivity, "", latLng - ) - true - } - } - } - } - } - - /**地图相关*********/ - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding.mapView.onCreate(savedInstanceState) - } - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onDestroy() { - binding.mapView.onDestroy() - super.onDestroy() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_group_device_map.xml b/app/src/main/res/layout/activity_group_device_map.xml new file mode 100644 index 0000000..078406e --- /dev/null +++ b/app/src/main/res/layout/activity_group_device_map.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index bb4ff3c..ffe86f1 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,26 +1,40 @@ - + android:background="@color/mainBackColor"> - + android:layout_height="match_parent" + android:orientation="vertical"> - - + + + + + - \ No newline at end of file + android:layout_gravity="center|bottom" + android:backgroundTint="@color/white" + android:contentDescription="@string/app_name" + android:src="@android:drawable/ic_input_add" + app:borderWidth="0dp" + app:elevation="@dimen/dp_5" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_map_device_brief.xml b/app/src/main/res/layout/activity_map_device_brief.xml deleted file mode 100644 index dc425d4..0000000 --- a/app/src/main/res/layout/activity_map_device_brief.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 529403a..8908a3e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,7 +55,7 @@ - + +) : FragmentPagerAdapter(manager) { + + override fun getItem(position: Int): Fragment = pages[position] + + override fun getCount(): Int = pages.size + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + //注释掉父类方法,一直不销毁Fragment + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt deleted file mode 100644 index ab6743f..0000000 --- a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt +++ /dev/null @@ -1,387 +0,0 @@ -package com.casic.smarttube.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.CoordinateConverter -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.Marker -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.FragmentHomeBinding -import com.casic.smarttube.model.MapDeviceModel -import com.casic.smarttube.model.ProjectGroupModel -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.view.AddDeviceActivity -import com.casic.smarttube.vm.DeviceViewModel -import com.casic.smarttube.vm.ProjectGroupViewModel -import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter -import com.pengxh.kt.lite.adapter.ViewHolder -import com.pengxh.kt.lite.base.KotlinBaseFragment -import com.pengxh.kt.lite.extensions.navigatePageTo -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView -import com.pengxh.kt.lite.widget.dialog.AlertControlDialog - - -class HomePageFragment : KotlinBaseFragment(), AMap.OnCameraChangeListener, - AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener, - AMap.OnMapClickListener { - - private val kTag = "HomePageFragment" - private val geocoderSearch by lazy { GeocodeSearch(requireContext()) } - private lateinit var aMap: AMap - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var groupViewModel: ProjectGroupViewModel - private lateinit var groupListAdapter: NormalRecyclerAdapter - private var clickedMarker: Marker? = null - - /** - * 自定义Marker弹出框 - * */ - private var infoView: View? = null - - /** - * 所有设备列表信息集合 - * */ - private var deviceModels: MutableList = ArrayList() - - override fun initViewBinding( - inflater: LayoutInflater, container: ViewGroup? - ): FragmentHomeBinding { - return FragmentHomeBinding.inflate(inflater, container, false) - } - - override fun setupTopBarLayout() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - - } - - override fun onRightClick() { - requireContext().navigatePageTo() - } - }) - } - - override fun observeRequestState() { - groupViewModel.loadState.observe(this) { state -> - when (state) { - LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - //地图初始化 - initMap(savedInstanceState) - - //默认显示所有设备 - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - deviceViewModel.mapDeviceModel.observe(this) { - if (it.code == 200) { - val allMarkerOptions = ArrayList() - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //缓存所有设备详情,点击Marker时候需要 - deviceModels.add(device) - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - //将所有设备信息转化缓存为Marker点 - allMarkerOptions.add( - MarkerOptions().position(LatLng(latitude, longitude)) - .title(device.devcode).snippet(device.modelName) - ) - } - } - } - - allMarkerOptions.forEach { marker -> - aMap.addMarker(marker) - } - - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate, 1500, null) - } - } - deviceViewModel.getMapDeviceList() - - groupViewModel = ViewModelProvider(this)[ProjectGroupViewModel::class.java] - groupViewModel.groupModel.observe(this) { - if (it.code == 200) { - bindRecyclerView(it) - } - } - - groupViewModel.groupDeviceModel.observe(this) { - if (it.code == 200) { - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - } - } - } - //计算所有点的中心点位置 - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate) - } - } - } - - private fun bindRecyclerView(it: ProjectGroupModel) { - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - binding.homeRecyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - // 根据groupId查询组下设备 - groupViewModel.getDeviceListByGroup(item.groupId) - } - }) - } - - override fun initEvent() { - - } - - private fun initMap(savedInstanceState: Bundle?) { - binding.mapView.onCreate(savedInstanceState) - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 - - // 地图缩放监听 - aMap.addOnCameraChangeListener(this) - // marker 点击事件监听 - aMap.addOnMarkerClickListener(this) - // 点击marker弹出自定义popup - aMap.setInfoWindowAdapter(this) - //信息窗点击事件 - aMap.addOnInfoWindowClickListener(this) - //地图点击事件,用于隐藏infoWindow - aMap.setOnMapClickListener(this) - } - - override fun onCameraChange(cameraPosition: CameraPosition?) { - - } - - //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker - override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { - - } - - override fun onMarkerClick(marker: Marker?): Boolean { - marker?.apply { - clickedMarker = this - if (isInfoWindowShown) { - hideInfoWindow() - } else { - showInfoWindow() - } - } - return true - } - - override fun onMapClick(p0: LatLng?) { - clickedMarker?.apply { - if (isInfoWindowShown) { - hideInfoWindow() - } - } - } - - override fun getInfoWindow(marker: Marker?): View? { - if (infoView == null) { - infoView = LayoutInflater.from(requireContext()).inflate( - R.layout.popu_map_info, null - ) - } - marker?.apply { - renderWindow(this, infoView!!) - } - return infoView - } - - private fun renderWindow(marker: Marker, view: View) { - //反射得到popup里面的控件对象 - val deviceCodeView = view.findViewById(R.id.deviceCodeView) - val deviceModelView = view.findViewById(R.id.deviceModelView) - val deviceValueView = view.findViewById(R.id.deviceValueView) - val updateTimeView = view.findViewById(R.id.updateTimeView) - val locationView = view.findViewById(R.id.locationView) - - //绑定数据 - val clicked = marker.position - deviceModels.forEach { device -> - if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { - deviceCodeView.text = String.format("设备编号: ${device.devcode}") - deviceModelView.text = String.format("设备模型: ${device.modelName}") - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(requireActivity()) { - if (it.code == 200) { - deviceValueView.text = String.format("最新浓度: ${it.data.strength}") - updateTimeView.text = String.format("更新时间: ${it.data.uptime}") - } else { - deviceValueView.text = String.format("最新浓度: 未知") - updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - locationView.text = "经纬度异常,无法查看具体位置" - } else { - val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - val address = result?.regeocodeAddress?.formatAddress - val temp = StringBuilder() - if (address!!.length > 16) { - temp.append(address.substring(0, 14)).append("\r\n") - .append(address.substring(16)) - } else { - temp.append(address) - } - locationView.text = String.format("详细位置: $temp") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - } - - /** - * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 - * */ - override fun getInfoContents(p0: Marker?): View? = null - - override fun onInfoWindowClick(marker: Marker?) { - marker?.apply { - AlertControlDialog.Builder().setContext(requireContext()).setTitle("操作提示") - .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - val lat = position.latitude.toString() - val lng = position.longitude.toString() - if (lat.isBlank() || lng.isBlank()) { - "窨井经纬度异常,无法开启导航".show(requireContext()) - return - } - RouteOnMap.startNavigation(requireContext(), snippet, position) - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - - /***以下是地图生命周期管理************************************************************************/ - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - groupViewModel.getProGroupList() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } - - override fun onDestroy() { - super.onDestroy() - binding.mapView.onDestroy() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt index 1d0aa3d..dd09cf5 100644 --- a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt +++ b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt @@ -15,12 +15,16 @@ import com.casic.smarttube.databinding.FragmentOverviewBinding import com.casic.smarttube.model.ProjectGroupModel import com.casic.smarttube.view.GroupDeviceActivity +import com.casic.smarttube.view.GroupDeviceMapActivity import com.casic.smarttube.vm.ProjectGroupViewModel import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseFragment import com.pengxh.kt.lite.divider.RecyclerViewItemDivider import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.EmptyView import com.pengxh.kt.lite.widget.TitleBarView import com.pengxh.kt.lite.widget.dialog.AlertInputDialog @@ -32,6 +36,7 @@ private lateinit var groupViewModel: ProjectGroupViewModel private lateinit var groupListAdapter: NormalRecyclerAdapter private var clickedPosition = 0 + private var isRefresh = false override fun initViewBinding( inflater: LayoutInflater, container: ViewGroup? @@ -40,7 +45,15 @@ } override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + } + + override fun onRightClick() { + requireContext().navigatePageTo() + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { @@ -55,66 +68,93 @@ groupListAdapter.notifyItemChanged(clickedPosition) } } - groupViewModel.getGroupList() + } + + override fun onResume() { + super.onResume() + groupViewModel.getProGroupList() } private fun bindRecyclerView(it: ProjectGroupModel) { val dataRows = it.data - if (dataRows.size == 0) { - binding.emptyView.visibility = View.VISIBLE - binding.recyclerView.visibility = View.GONE - } else { - binding.emptyView.visibility = View.GONE - binding.recyclerView.visibility = View.VISIBLE + when { + isRefresh -> { + binding.refreshView.finishRefresh() + isRefresh = false + groupListAdapter.refresh(dataRows) + } - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_over_view_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - .setOnClickListener(R.id.editGroupNameView) { - clickedPosition = position - editGroupName(item) - } - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) + else -> { + if (dataRows.size == 0) { + binding.emptyView.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE + } else { + binding.emptyView.visibility = View.GONE + binding.recyclerView.visibility = View.VISIBLE + + groupListAdapter = object : NormalRecyclerAdapter( + R.layout.item_group_over_view_rv_l, it.data + ) { + override fun convertView( + viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel + ) { + viewHolder.setText(R.id.groupNameView, item.groupId) + .setText(R.id.totalDeviceNumView, item.totalDevice) + .setText(R.id.inUseDeviceNumView, item.alive) + .setText(R.id.notUseDeviceNumView, item.unalive) + .setOnClickListener(R.id.editGroupNameView) { + clickedPosition = position + editGroupName(item) } - } + if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { + viewHolder.setText( + R.id.groupLocationView, + "经纬度异常,无法查看具体位置" + ) + } else { + val point = + LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched( + result: RegeocodeResult?, + rCode: Int + ) { + if (rCode == 1000) { + viewHolder.setText( + R.id.groupLocationView, + String.format("${result?.regeocodeAddress?.formatAddress}") + ) + } + } - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + override fun onGeocodeSearched( + result: GeocodeResult?, + rCode: Int + ) { + } + }) } - }) + } } + binding.recyclerView.addItemDecoration( + RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) + ) + binding.recyclerView.adapter = groupListAdapter + groupListAdapter.setOnItemClickedListener(object : + NormalRecyclerAdapter.OnItemClickedListener { + override fun onItemClicked( + position: Int, + item: ProjectGroupModel.DataModel + ) { + requireContext().navigatePageTo(item.groupId) + } + }) } } - binding.recyclerView.addItemDecoration( - RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) - ) - binding.recyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - requireContext().navigatePageTo(item.groupId) - } - }) } } @@ -139,18 +179,31 @@ } override fun observeRequestState() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - + groupViewModel.loadState.observe(this) { + if (isRefresh) { + return@observe } + when (it) { + LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中,请稍后...") - override fun onRightClick() { - groupViewModel.getProGroupList() + LoadState.Success -> { + LoadingDialog.dismiss() + } + + LoadState.Fail -> { + LoadingDialog.dismiss() + "数据加载失败,请重试".show(requireContext()) + } } - }) + } } override fun initEvent() { + binding.refreshView.setOnRefreshListener { + isRefresh = true + groupViewModel.getProGroupList() + } + binding.emptyView.setOnClickListener(object : EmptyView.OnClickListener { override fun onReloadButtonClicked() { groupViewModel.getProGroupList() diff --git a/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt new file mode 100644 index 0000000..c33c40e --- /dev/null +++ b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt @@ -0,0 +1,288 @@ +package com.casic.smarttube.view + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.lifecycle.ViewModelProvider +import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.CameraUpdateFactory +import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.CameraPosition +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.Marker +import com.amap.api.maps.model.MarkerOptions +import com.amap.api.services.core.LatLonPoint +import com.amap.api.services.geocoder.GeocodeResult +import com.amap.api.services.geocoder.GeocodeSearch +import com.amap.api.services.geocoder.RegeocodeQuery +import com.amap.api.services.geocoder.RegeocodeResult +import com.casic.smarttube.R +import com.casic.smarttube.databinding.ActivityGroupDeviceMapBinding +import com.casic.smarttube.extensions.initImmersionBar +import com.casic.smarttube.model.MapDeviceModel +import com.casic.smarttube.utils.RouteOnMap +import com.casic.smarttube.vm.DeviceViewModel +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog + +class GroupDeviceMapActivity : KotlinBaseActivity(), + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, + AMap.OnInfoWindowClickListener, AMap.OnMapClickListener { + + private val context = this + private val geocoderSearch by lazy { GeocodeSearch(this) } + private lateinit var aMap: AMap + private lateinit var deviceViewModel: DeviceViewModel + private var clickedMarker: Marker? = null + + /** + * 自定义Marker弹出框 + * */ + private var infoView: View? = null + + /** + * 所有设备列表信息集合 + * */ + private var deviceModels: MutableList = ArrayList() + + override fun initViewBinding(): ActivityGroupDeviceMapBinding { + return ActivityGroupDeviceMapBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + } + + override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + //地图初始化 + initMap(savedInstanceState) + + //默认显示所有设备 + deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] + deviceViewModel.mapDeviceModel.observe(this) { + if (it.code == 200) { + val allMarkerOptions = ArrayList() + val latitudeList = ArrayList() + val longitudeList = ArrayList() + it.data.forEach { device -> + val lat = device.latGaode.toString() + val lng = device.lngGaode.toString() + if (lat.isNotBlank() && lng.isNotBlank()) { + //返回true代表当前位置在大陆、港澳地区,反之不在 + val latitude = lat.toDouble() + val longitude = lng.toDouble() + if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { + //缓存所有设备详情,点击Marker时候需要 + deviceModels.add(device) + //分别缓存经、纬度 + latitudeList.add(latitude) + longitudeList.add(longitude) + //将所有设备信息转化缓存为Marker点 + allMarkerOptions.add( + MarkerOptions().position(LatLng(latitude, longitude)) + .title(device.devcode).snippet(device.modelName) + ) + } + } + } + + allMarkerOptions.forEach { marker -> + aMap.addMarker(marker) + } + + val latLng = LatLng(latitudeList[0], longitudeList[0]) + val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) + val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) + aMap.animateCamera(cameraUpdate, 1500, null) + } + } + deviceViewModel.getMapDeviceList() + } + + override fun initEvent() { + + } + + private fun initMap(savedInstanceState: Bundle?) { + binding.mapView.onCreate(savedInstanceState) + aMap = binding.mapView.map + aMap.mapType = AMap.MAP_TYPE_NORMAL + val uiSettings = aMap.uiSettings + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 + + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker 点击事件监听 + aMap.addOnMarkerClickListener(this) + // 点击marker弹出自定义popup + aMap.setInfoWindowAdapter(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + //地图点击事件,用于隐藏infoWindow + aMap.setOnMapClickListener(this) + } + + override fun onCameraChange(cameraPosition: CameraPosition?) { + + } + + //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker + override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { + + } + + override fun onMarkerClick(marker: Marker?): Boolean { + marker?.apply { + clickedMarker = this + if (isInfoWindowShown) { + hideInfoWindow() + } else { + showInfoWindow() + } + } + return true + } + + override fun onMapClick(p0: LatLng?) { + clickedMarker?.apply { + if (isInfoWindowShown) { + hideInfoWindow() + } + } + } + + override fun getInfoWindow(marker: Marker?): View? { + if (infoView == null) { + infoView = LayoutInflater.from(this).inflate(R.layout.popu_map_info, null) + } + marker?.apply { + renderWindow(this, infoView!!) + } + return infoView + } + + private fun renderWindow(marker: Marker, view: View) { + //反射得到popup里面的控件对象 + val deviceCodeView = view.findViewById(R.id.deviceCodeView) + val deviceModelView = view.findViewById(R.id.deviceModelView) + val deviceValueView = view.findViewById(R.id.deviceValueView) + val updateTimeView = view.findViewById(R.id.updateTimeView) + val locationView = view.findViewById(R.id.locationView) + + //绑定数据 + val clicked = marker.position + deviceModels.forEach { device -> + if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { + deviceCodeView.text = String.format("设备编号: ${device.devcode}") + deviceModelView.text = String.format("设备模型: ${device.modelName}") + //获取设备最新浓度信息 + deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) + deviceViewModel.lastDataModel.observe(this) { + if (it.code == 200) { + deviceValueView.text = String.format("最新浓度: ${it.data.strength}") + updateTimeView.text = String.format("更新时间: ${it.data.uptime}") + } else { + deviceValueView.text = String.format("最新浓度: 未知") + updateTimeView.text = String.format("更新时间: 未知") + } + } + if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { + locationView.text = "经纬度异常,无法查看具体位置" + } else { + val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { + if (rCode == 1000) { + val address = result?.regeocodeAddress?.formatAddress + val temp = StringBuilder() + if (address!!.length > 16) { + temp.append(address.substring(0, 14)).append("\r\n") + .append(address.substring(16)) + } else { + temp.append(address) + } + locationView.text = String.format("详细位置: $temp") + } + } + + override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + + } + }) + } + } + } + } + + /** + * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 + * */ + override fun getInfoContents(p0: Marker?): View? = null + + override fun onInfoWindowClick(marker: Marker?) { + marker?.apply { + AlertControlDialog.Builder().setContext(context).setTitle("操作提示") + .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + val lat = position.latitude.toString() + val lng = position.longitude.toString() + if (lat.isBlank() || lng.isBlank()) { + "窨井经纬度异常,无法开启导航".show(context) + return + } + RouteOnMap.startNavigation(context, snippet, position) + } + + override fun onCancelClick() { + + } + }).build().show() + } + } + + /***以下是地图生命周期管理************************************************************************/ + + override fun onResume() { + super.onResume() + binding.mapView.onResume() + } + + override fun onPause() { + super.onPause() + binding.mapView.onPause() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + binding.mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + super.onDestroy() + binding.mapView.onDestroy() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt index c7f06c9..b6b4e8a 100644 --- a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt +++ b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt @@ -3,29 +3,25 @@ import android.os.Bundle import android.view.KeyEvent import android.view.MenuItem -import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter import androidx.viewpager.widget.ViewPager import com.casic.smarttube.R +import com.casic.smarttube.adapter.TabPageViewAdapter import com.casic.smarttube.databinding.ActivityMainBinding import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.fragment.HomePageFragment import com.casic.smarttube.fragment.MinePageFragment import com.casic.smarttube.fragment.OverviewFragment -import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show class MainActivity : KotlinBaseActivity() { private var menuItem: MenuItem? = null - private var fragmentPages: MutableList = ArrayList() + private var fragmentPages: ArrayList = ArrayList() private var clickTime: Long = 0 init { - fragmentPages.add(HomePageFragment()) fragmentPages.add(OverviewFragment()) fragmentPages.add(MinePageFragment()) } @@ -35,30 +31,13 @@ } override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) } override fun initOnCreate(savedInstanceState: Bundle?) { //保留icon原图颜色 binding.bottomNavigation.itemIconTintList = null - binding.bottomNavigation.setOnItemSelectedListener { menuItem -> - when (menuItem.itemId) { - R.id.nav_home -> { - binding.mainViewPager.currentItem = 0 - } - - R.id.nav_overview -> { - binding.mainViewPager.currentItem = 1 - } - - R.id.nav_mine -> { - binding.mainViewPager.currentItem = 2 - } - } - false - } - binding.mainViewPager.adapter = ViewPagerAdapter(fragmentPages, supportFragmentManager) + binding.mainViewPager.adapter = TabPageViewAdapter(supportFragmentManager, fragmentPages) } override fun observeRequestState() { @@ -66,6 +45,18 @@ } override fun initEvent() { + binding.bottomNavigation.setOnItemSelectedListener { menuItem -> + when (menuItem.itemId) { + R.id.nav_overview -> { + binding.mainViewPager.currentItem = 0 + } + + R.id.nav_mine -> { + binding.mainViewPager.currentItem = 1 + } + } + false + } binding.mainViewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageScrollStateChanged(state: Int) { @@ -87,6 +78,10 @@ menuItem!!.isChecked = true } }) + + binding.addDeviceButton.setOnClickListener { + navigatePageTo() + } } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { @@ -100,18 +95,4 @@ } } else super.onKeyDown(keyCode, event) } - - inner class ViewPagerAdapter(list: MutableList, manager: FragmentManager) : - FragmentPagerAdapter(manager) { - - private var viewPages: List = list - - override fun getItem(position: Int): Fragment = viewPages[position] - - override fun getCount(): Int = viewPages.size - - override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { - - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt b/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt deleted file mode 100644 index b5be93b..0000000 --- a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt +++ /dev/null @@ -1,174 +0,0 @@ -package com.casic.smarttube.view - -import android.os.Bundle -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.model.BitmapDescriptorFactory -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.ActivityMapDeviceBriefBinding -import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.vm.DeviceViewModel -import com.gyf.immersionbar.ImmersionBar -import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.utils.LiteKitConstant -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView - -class MapDeviceBriefActivity : KotlinBaseActivity() { - - private val kTag = "MapDeviceBriefActivity" - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var aMap: AMap - private lateinit var params: ArrayList - private val geocoderSearch by lazy { GeocodeSearch(this) } - - - override fun initViewBinding(): ActivityMapDeviceBriefBinding { - return ActivityMapDeviceBriefBinding.inflate(layoutInflater) - } - - override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - finish() - } - - override fun onRightClick() { - - } - }) - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图旋转 - - this.params = intent.getStringArrayListExtra(LiteKitConstant.INTENT_PARAM_KEY)!! - - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - } - - override fun observeRequestState() { - deviceViewModel.loadState.observe(this) { - when (it) { - LoadState.Loading -> LoadingDialog.show(this, "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initEvent() { - deviceViewModel.obtainDeviceDetail(params[0], params[1]) - deviceViewModel.deviceDetailModel.observe(this) { - if (it.code == 200) { - val device = it.data - - binding.deviceCodeView.text = String.format("设备编号: ${device.devcode}") - binding.deviceModelView.text = String.format("设备模型: ${params[2]}") - - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(this) { v -> - if (v.code == 200) { - binding.deviceValueView.text = String.format("最新浓度: ${v.data.strength}") - binding.updateTimeView.text = String.format("更新时间: ${v.data.uptime}") - } else { - binding.deviceValueView.text = String.format("最新浓度: 未知") - binding.updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - binding.locationView.text = "经纬度异常,无法查看具体位置" - } else { - val queryParam = RegeocodeQuery( - LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()), - 200f, - GeocodeSearch.AMAP - ) - val latLng = LatLng(device.latGaode.toDouble(), device.lngGaode.toDouble()) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - binding.locationView.text = - String.format("详细位置: ${result?.regeocodeAddress?.formatAddress}") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - - val cameraPosition = CameraPosition(latLng, 18f, 0f, 0f) - val newCameraPosition = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(newCameraPosition, 1500, object : AMap.CancelableCallback { - override fun onFinish() { - //添加Marker - val markerOptions = MarkerOptions().position(latLng) - .icon(BitmapDescriptorFactory.fromResource(R.mipmap.well_location)) - .draggable(false) - aMap.addMarker(markerOptions) - } - - override fun onCancel() { - - } - }) - aMap.setOnMarkerClickListener { - RouteOnMap.startNavigation( - this@MapDeviceBriefActivity, "", latLng - ) - true - } - } - } - } - } - - /**地图相关*********/ - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding.mapView.onCreate(savedInstanceState) - } - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onDestroy() { - binding.mapView.onDestroy() - super.onDestroy() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_group_device_map.xml b/app/src/main/res/layout/activity_group_device_map.xml new file mode 100644 index 0000000..078406e --- /dev/null +++ b/app/src/main/res/layout/activity_group_device_map.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index bb4ff3c..ffe86f1 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,26 +1,40 @@ - + android:background="@color/mainBackColor"> - + android:layout_height="match_parent" + android:orientation="vertical"> - - + + + + + - \ No newline at end of file + android:layout_gravity="center|bottom" + android:backgroundTint="@color/white" + android:contentDescription="@string/app_name" + android:src="@android:drawable/ic_input_add" + app:borderWidth="0dp" + app:elevation="@dimen/dp_5" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_map_device_brief.xml b/app/src/main/res/layout/activity_map_device_brief.xml deleted file mode 100644 index dc425d4..0000000 --- a/app/src/main/res/layout/activity_map_device_brief.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml deleted file mode 100644 index 9616185..0000000 --- a/app/src/main/res/layout/fragment_home.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 529403a..8908a3e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,7 +55,7 @@ - + +) : FragmentPagerAdapter(manager) { + + override fun getItem(position: Int): Fragment = pages[position] + + override fun getCount(): Int = pages.size + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + //注释掉父类方法,一直不销毁Fragment + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt deleted file mode 100644 index ab6743f..0000000 --- a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt +++ /dev/null @@ -1,387 +0,0 @@ -package com.casic.smarttube.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.CoordinateConverter -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.Marker -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.FragmentHomeBinding -import com.casic.smarttube.model.MapDeviceModel -import com.casic.smarttube.model.ProjectGroupModel -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.view.AddDeviceActivity -import com.casic.smarttube.vm.DeviceViewModel -import com.casic.smarttube.vm.ProjectGroupViewModel -import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter -import com.pengxh.kt.lite.adapter.ViewHolder -import com.pengxh.kt.lite.base.KotlinBaseFragment -import com.pengxh.kt.lite.extensions.navigatePageTo -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView -import com.pengxh.kt.lite.widget.dialog.AlertControlDialog - - -class HomePageFragment : KotlinBaseFragment(), AMap.OnCameraChangeListener, - AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener, - AMap.OnMapClickListener { - - private val kTag = "HomePageFragment" - private val geocoderSearch by lazy { GeocodeSearch(requireContext()) } - private lateinit var aMap: AMap - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var groupViewModel: ProjectGroupViewModel - private lateinit var groupListAdapter: NormalRecyclerAdapter - private var clickedMarker: Marker? = null - - /** - * 自定义Marker弹出框 - * */ - private var infoView: View? = null - - /** - * 所有设备列表信息集合 - * */ - private var deviceModels: MutableList = ArrayList() - - override fun initViewBinding( - inflater: LayoutInflater, container: ViewGroup? - ): FragmentHomeBinding { - return FragmentHomeBinding.inflate(inflater, container, false) - } - - override fun setupTopBarLayout() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - - } - - override fun onRightClick() { - requireContext().navigatePageTo() - } - }) - } - - override fun observeRequestState() { - groupViewModel.loadState.observe(this) { state -> - when (state) { - LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - //地图初始化 - initMap(savedInstanceState) - - //默认显示所有设备 - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - deviceViewModel.mapDeviceModel.observe(this) { - if (it.code == 200) { - val allMarkerOptions = ArrayList() - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //缓存所有设备详情,点击Marker时候需要 - deviceModels.add(device) - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - //将所有设备信息转化缓存为Marker点 - allMarkerOptions.add( - MarkerOptions().position(LatLng(latitude, longitude)) - .title(device.devcode).snippet(device.modelName) - ) - } - } - } - - allMarkerOptions.forEach { marker -> - aMap.addMarker(marker) - } - - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate, 1500, null) - } - } - deviceViewModel.getMapDeviceList() - - groupViewModel = ViewModelProvider(this)[ProjectGroupViewModel::class.java] - groupViewModel.groupModel.observe(this) { - if (it.code == 200) { - bindRecyclerView(it) - } - } - - groupViewModel.groupDeviceModel.observe(this) { - if (it.code == 200) { - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - } - } - } - //计算所有点的中心点位置 - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate) - } - } - } - - private fun bindRecyclerView(it: ProjectGroupModel) { - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - binding.homeRecyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - // 根据groupId查询组下设备 - groupViewModel.getDeviceListByGroup(item.groupId) - } - }) - } - - override fun initEvent() { - - } - - private fun initMap(savedInstanceState: Bundle?) { - binding.mapView.onCreate(savedInstanceState) - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 - - // 地图缩放监听 - aMap.addOnCameraChangeListener(this) - // marker 点击事件监听 - aMap.addOnMarkerClickListener(this) - // 点击marker弹出自定义popup - aMap.setInfoWindowAdapter(this) - //信息窗点击事件 - aMap.addOnInfoWindowClickListener(this) - //地图点击事件,用于隐藏infoWindow - aMap.setOnMapClickListener(this) - } - - override fun onCameraChange(cameraPosition: CameraPosition?) { - - } - - //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker - override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { - - } - - override fun onMarkerClick(marker: Marker?): Boolean { - marker?.apply { - clickedMarker = this - if (isInfoWindowShown) { - hideInfoWindow() - } else { - showInfoWindow() - } - } - return true - } - - override fun onMapClick(p0: LatLng?) { - clickedMarker?.apply { - if (isInfoWindowShown) { - hideInfoWindow() - } - } - } - - override fun getInfoWindow(marker: Marker?): View? { - if (infoView == null) { - infoView = LayoutInflater.from(requireContext()).inflate( - R.layout.popu_map_info, null - ) - } - marker?.apply { - renderWindow(this, infoView!!) - } - return infoView - } - - private fun renderWindow(marker: Marker, view: View) { - //反射得到popup里面的控件对象 - val deviceCodeView = view.findViewById(R.id.deviceCodeView) - val deviceModelView = view.findViewById(R.id.deviceModelView) - val deviceValueView = view.findViewById(R.id.deviceValueView) - val updateTimeView = view.findViewById(R.id.updateTimeView) - val locationView = view.findViewById(R.id.locationView) - - //绑定数据 - val clicked = marker.position - deviceModels.forEach { device -> - if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { - deviceCodeView.text = String.format("设备编号: ${device.devcode}") - deviceModelView.text = String.format("设备模型: ${device.modelName}") - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(requireActivity()) { - if (it.code == 200) { - deviceValueView.text = String.format("最新浓度: ${it.data.strength}") - updateTimeView.text = String.format("更新时间: ${it.data.uptime}") - } else { - deviceValueView.text = String.format("最新浓度: 未知") - updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - locationView.text = "经纬度异常,无法查看具体位置" - } else { - val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - val address = result?.regeocodeAddress?.formatAddress - val temp = StringBuilder() - if (address!!.length > 16) { - temp.append(address.substring(0, 14)).append("\r\n") - .append(address.substring(16)) - } else { - temp.append(address) - } - locationView.text = String.format("详细位置: $temp") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - } - - /** - * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 - * */ - override fun getInfoContents(p0: Marker?): View? = null - - override fun onInfoWindowClick(marker: Marker?) { - marker?.apply { - AlertControlDialog.Builder().setContext(requireContext()).setTitle("操作提示") - .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - val lat = position.latitude.toString() - val lng = position.longitude.toString() - if (lat.isBlank() || lng.isBlank()) { - "窨井经纬度异常,无法开启导航".show(requireContext()) - return - } - RouteOnMap.startNavigation(requireContext(), snippet, position) - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - - /***以下是地图生命周期管理************************************************************************/ - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - groupViewModel.getProGroupList() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } - - override fun onDestroy() { - super.onDestroy() - binding.mapView.onDestroy() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt index 1d0aa3d..dd09cf5 100644 --- a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt +++ b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt @@ -15,12 +15,16 @@ import com.casic.smarttube.databinding.FragmentOverviewBinding import com.casic.smarttube.model.ProjectGroupModel import com.casic.smarttube.view.GroupDeviceActivity +import com.casic.smarttube.view.GroupDeviceMapActivity import com.casic.smarttube.vm.ProjectGroupViewModel import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseFragment import com.pengxh.kt.lite.divider.RecyclerViewItemDivider import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.EmptyView import com.pengxh.kt.lite.widget.TitleBarView import com.pengxh.kt.lite.widget.dialog.AlertInputDialog @@ -32,6 +36,7 @@ private lateinit var groupViewModel: ProjectGroupViewModel private lateinit var groupListAdapter: NormalRecyclerAdapter private var clickedPosition = 0 + private var isRefresh = false override fun initViewBinding( inflater: LayoutInflater, container: ViewGroup? @@ -40,7 +45,15 @@ } override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + } + + override fun onRightClick() { + requireContext().navigatePageTo() + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { @@ -55,66 +68,93 @@ groupListAdapter.notifyItemChanged(clickedPosition) } } - groupViewModel.getGroupList() + } + + override fun onResume() { + super.onResume() + groupViewModel.getProGroupList() } private fun bindRecyclerView(it: ProjectGroupModel) { val dataRows = it.data - if (dataRows.size == 0) { - binding.emptyView.visibility = View.VISIBLE - binding.recyclerView.visibility = View.GONE - } else { - binding.emptyView.visibility = View.GONE - binding.recyclerView.visibility = View.VISIBLE + when { + isRefresh -> { + binding.refreshView.finishRefresh() + isRefresh = false + groupListAdapter.refresh(dataRows) + } - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_over_view_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - .setOnClickListener(R.id.editGroupNameView) { - clickedPosition = position - editGroupName(item) - } - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) + else -> { + if (dataRows.size == 0) { + binding.emptyView.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE + } else { + binding.emptyView.visibility = View.GONE + binding.recyclerView.visibility = View.VISIBLE + + groupListAdapter = object : NormalRecyclerAdapter( + R.layout.item_group_over_view_rv_l, it.data + ) { + override fun convertView( + viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel + ) { + viewHolder.setText(R.id.groupNameView, item.groupId) + .setText(R.id.totalDeviceNumView, item.totalDevice) + .setText(R.id.inUseDeviceNumView, item.alive) + .setText(R.id.notUseDeviceNumView, item.unalive) + .setOnClickListener(R.id.editGroupNameView) { + clickedPosition = position + editGroupName(item) } - } + if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { + viewHolder.setText( + R.id.groupLocationView, + "经纬度异常,无法查看具体位置" + ) + } else { + val point = + LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched( + result: RegeocodeResult?, + rCode: Int + ) { + if (rCode == 1000) { + viewHolder.setText( + R.id.groupLocationView, + String.format("${result?.regeocodeAddress?.formatAddress}") + ) + } + } - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + override fun onGeocodeSearched( + result: GeocodeResult?, + rCode: Int + ) { + } + }) } - }) + } } + binding.recyclerView.addItemDecoration( + RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) + ) + binding.recyclerView.adapter = groupListAdapter + groupListAdapter.setOnItemClickedListener(object : + NormalRecyclerAdapter.OnItemClickedListener { + override fun onItemClicked( + position: Int, + item: ProjectGroupModel.DataModel + ) { + requireContext().navigatePageTo(item.groupId) + } + }) } } - binding.recyclerView.addItemDecoration( - RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) - ) - binding.recyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - requireContext().navigatePageTo(item.groupId) - } - }) } } @@ -139,18 +179,31 @@ } override fun observeRequestState() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - + groupViewModel.loadState.observe(this) { + if (isRefresh) { + return@observe } + when (it) { + LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中,请稍后...") - override fun onRightClick() { - groupViewModel.getProGroupList() + LoadState.Success -> { + LoadingDialog.dismiss() + } + + LoadState.Fail -> { + LoadingDialog.dismiss() + "数据加载失败,请重试".show(requireContext()) + } } - }) + } } override fun initEvent() { + binding.refreshView.setOnRefreshListener { + isRefresh = true + groupViewModel.getProGroupList() + } + binding.emptyView.setOnClickListener(object : EmptyView.OnClickListener { override fun onReloadButtonClicked() { groupViewModel.getProGroupList() diff --git a/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt new file mode 100644 index 0000000..c33c40e --- /dev/null +++ b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt @@ -0,0 +1,288 @@ +package com.casic.smarttube.view + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.lifecycle.ViewModelProvider +import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.CameraUpdateFactory +import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.CameraPosition +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.Marker +import com.amap.api.maps.model.MarkerOptions +import com.amap.api.services.core.LatLonPoint +import com.amap.api.services.geocoder.GeocodeResult +import com.amap.api.services.geocoder.GeocodeSearch +import com.amap.api.services.geocoder.RegeocodeQuery +import com.amap.api.services.geocoder.RegeocodeResult +import com.casic.smarttube.R +import com.casic.smarttube.databinding.ActivityGroupDeviceMapBinding +import com.casic.smarttube.extensions.initImmersionBar +import com.casic.smarttube.model.MapDeviceModel +import com.casic.smarttube.utils.RouteOnMap +import com.casic.smarttube.vm.DeviceViewModel +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog + +class GroupDeviceMapActivity : KotlinBaseActivity(), + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, + AMap.OnInfoWindowClickListener, AMap.OnMapClickListener { + + private val context = this + private val geocoderSearch by lazy { GeocodeSearch(this) } + private lateinit var aMap: AMap + private lateinit var deviceViewModel: DeviceViewModel + private var clickedMarker: Marker? = null + + /** + * 自定义Marker弹出框 + * */ + private var infoView: View? = null + + /** + * 所有设备列表信息集合 + * */ + private var deviceModels: MutableList = ArrayList() + + override fun initViewBinding(): ActivityGroupDeviceMapBinding { + return ActivityGroupDeviceMapBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + } + + override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + //地图初始化 + initMap(savedInstanceState) + + //默认显示所有设备 + deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] + deviceViewModel.mapDeviceModel.observe(this) { + if (it.code == 200) { + val allMarkerOptions = ArrayList() + val latitudeList = ArrayList() + val longitudeList = ArrayList() + it.data.forEach { device -> + val lat = device.latGaode.toString() + val lng = device.lngGaode.toString() + if (lat.isNotBlank() && lng.isNotBlank()) { + //返回true代表当前位置在大陆、港澳地区,反之不在 + val latitude = lat.toDouble() + val longitude = lng.toDouble() + if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { + //缓存所有设备详情,点击Marker时候需要 + deviceModels.add(device) + //分别缓存经、纬度 + latitudeList.add(latitude) + longitudeList.add(longitude) + //将所有设备信息转化缓存为Marker点 + allMarkerOptions.add( + MarkerOptions().position(LatLng(latitude, longitude)) + .title(device.devcode).snippet(device.modelName) + ) + } + } + } + + allMarkerOptions.forEach { marker -> + aMap.addMarker(marker) + } + + val latLng = LatLng(latitudeList[0], longitudeList[0]) + val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) + val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) + aMap.animateCamera(cameraUpdate, 1500, null) + } + } + deviceViewModel.getMapDeviceList() + } + + override fun initEvent() { + + } + + private fun initMap(savedInstanceState: Bundle?) { + binding.mapView.onCreate(savedInstanceState) + aMap = binding.mapView.map + aMap.mapType = AMap.MAP_TYPE_NORMAL + val uiSettings = aMap.uiSettings + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 + + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker 点击事件监听 + aMap.addOnMarkerClickListener(this) + // 点击marker弹出自定义popup + aMap.setInfoWindowAdapter(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + //地图点击事件,用于隐藏infoWindow + aMap.setOnMapClickListener(this) + } + + override fun onCameraChange(cameraPosition: CameraPosition?) { + + } + + //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker + override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { + + } + + override fun onMarkerClick(marker: Marker?): Boolean { + marker?.apply { + clickedMarker = this + if (isInfoWindowShown) { + hideInfoWindow() + } else { + showInfoWindow() + } + } + return true + } + + override fun onMapClick(p0: LatLng?) { + clickedMarker?.apply { + if (isInfoWindowShown) { + hideInfoWindow() + } + } + } + + override fun getInfoWindow(marker: Marker?): View? { + if (infoView == null) { + infoView = LayoutInflater.from(this).inflate(R.layout.popu_map_info, null) + } + marker?.apply { + renderWindow(this, infoView!!) + } + return infoView + } + + private fun renderWindow(marker: Marker, view: View) { + //反射得到popup里面的控件对象 + val deviceCodeView = view.findViewById(R.id.deviceCodeView) + val deviceModelView = view.findViewById(R.id.deviceModelView) + val deviceValueView = view.findViewById(R.id.deviceValueView) + val updateTimeView = view.findViewById(R.id.updateTimeView) + val locationView = view.findViewById(R.id.locationView) + + //绑定数据 + val clicked = marker.position + deviceModels.forEach { device -> + if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { + deviceCodeView.text = String.format("设备编号: ${device.devcode}") + deviceModelView.text = String.format("设备模型: ${device.modelName}") + //获取设备最新浓度信息 + deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) + deviceViewModel.lastDataModel.observe(this) { + if (it.code == 200) { + deviceValueView.text = String.format("最新浓度: ${it.data.strength}") + updateTimeView.text = String.format("更新时间: ${it.data.uptime}") + } else { + deviceValueView.text = String.format("最新浓度: 未知") + updateTimeView.text = String.format("更新时间: 未知") + } + } + if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { + locationView.text = "经纬度异常,无法查看具体位置" + } else { + val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { + if (rCode == 1000) { + val address = result?.regeocodeAddress?.formatAddress + val temp = StringBuilder() + if (address!!.length > 16) { + temp.append(address.substring(0, 14)).append("\r\n") + .append(address.substring(16)) + } else { + temp.append(address) + } + locationView.text = String.format("详细位置: $temp") + } + } + + override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + + } + }) + } + } + } + } + + /** + * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 + * */ + override fun getInfoContents(p0: Marker?): View? = null + + override fun onInfoWindowClick(marker: Marker?) { + marker?.apply { + AlertControlDialog.Builder().setContext(context).setTitle("操作提示") + .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + val lat = position.latitude.toString() + val lng = position.longitude.toString() + if (lat.isBlank() || lng.isBlank()) { + "窨井经纬度异常,无法开启导航".show(context) + return + } + RouteOnMap.startNavigation(context, snippet, position) + } + + override fun onCancelClick() { + + } + }).build().show() + } + } + + /***以下是地图生命周期管理************************************************************************/ + + override fun onResume() { + super.onResume() + binding.mapView.onResume() + } + + override fun onPause() { + super.onPause() + binding.mapView.onPause() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + binding.mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + super.onDestroy() + binding.mapView.onDestroy() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt index c7f06c9..b6b4e8a 100644 --- a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt +++ b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt @@ -3,29 +3,25 @@ import android.os.Bundle import android.view.KeyEvent import android.view.MenuItem -import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter import androidx.viewpager.widget.ViewPager import com.casic.smarttube.R +import com.casic.smarttube.adapter.TabPageViewAdapter import com.casic.smarttube.databinding.ActivityMainBinding import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.fragment.HomePageFragment import com.casic.smarttube.fragment.MinePageFragment import com.casic.smarttube.fragment.OverviewFragment -import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show class MainActivity : KotlinBaseActivity() { private var menuItem: MenuItem? = null - private var fragmentPages: MutableList = ArrayList() + private var fragmentPages: ArrayList = ArrayList() private var clickTime: Long = 0 init { - fragmentPages.add(HomePageFragment()) fragmentPages.add(OverviewFragment()) fragmentPages.add(MinePageFragment()) } @@ -35,30 +31,13 @@ } override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) } override fun initOnCreate(savedInstanceState: Bundle?) { //保留icon原图颜色 binding.bottomNavigation.itemIconTintList = null - binding.bottomNavigation.setOnItemSelectedListener { menuItem -> - when (menuItem.itemId) { - R.id.nav_home -> { - binding.mainViewPager.currentItem = 0 - } - - R.id.nav_overview -> { - binding.mainViewPager.currentItem = 1 - } - - R.id.nav_mine -> { - binding.mainViewPager.currentItem = 2 - } - } - false - } - binding.mainViewPager.adapter = ViewPagerAdapter(fragmentPages, supportFragmentManager) + binding.mainViewPager.adapter = TabPageViewAdapter(supportFragmentManager, fragmentPages) } override fun observeRequestState() { @@ -66,6 +45,18 @@ } override fun initEvent() { + binding.bottomNavigation.setOnItemSelectedListener { menuItem -> + when (menuItem.itemId) { + R.id.nav_overview -> { + binding.mainViewPager.currentItem = 0 + } + + R.id.nav_mine -> { + binding.mainViewPager.currentItem = 1 + } + } + false + } binding.mainViewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageScrollStateChanged(state: Int) { @@ -87,6 +78,10 @@ menuItem!!.isChecked = true } }) + + binding.addDeviceButton.setOnClickListener { + navigatePageTo() + } } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { @@ -100,18 +95,4 @@ } } else super.onKeyDown(keyCode, event) } - - inner class ViewPagerAdapter(list: MutableList, manager: FragmentManager) : - FragmentPagerAdapter(manager) { - - private var viewPages: List = list - - override fun getItem(position: Int): Fragment = viewPages[position] - - override fun getCount(): Int = viewPages.size - - override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { - - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt b/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt deleted file mode 100644 index b5be93b..0000000 --- a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt +++ /dev/null @@ -1,174 +0,0 @@ -package com.casic.smarttube.view - -import android.os.Bundle -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.model.BitmapDescriptorFactory -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.ActivityMapDeviceBriefBinding -import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.vm.DeviceViewModel -import com.gyf.immersionbar.ImmersionBar -import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.utils.LiteKitConstant -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView - -class MapDeviceBriefActivity : KotlinBaseActivity() { - - private val kTag = "MapDeviceBriefActivity" - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var aMap: AMap - private lateinit var params: ArrayList - private val geocoderSearch by lazy { GeocodeSearch(this) } - - - override fun initViewBinding(): ActivityMapDeviceBriefBinding { - return ActivityMapDeviceBriefBinding.inflate(layoutInflater) - } - - override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - finish() - } - - override fun onRightClick() { - - } - }) - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图旋转 - - this.params = intent.getStringArrayListExtra(LiteKitConstant.INTENT_PARAM_KEY)!! - - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - } - - override fun observeRequestState() { - deviceViewModel.loadState.observe(this) { - when (it) { - LoadState.Loading -> LoadingDialog.show(this, "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initEvent() { - deviceViewModel.obtainDeviceDetail(params[0], params[1]) - deviceViewModel.deviceDetailModel.observe(this) { - if (it.code == 200) { - val device = it.data - - binding.deviceCodeView.text = String.format("设备编号: ${device.devcode}") - binding.deviceModelView.text = String.format("设备模型: ${params[2]}") - - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(this) { v -> - if (v.code == 200) { - binding.deviceValueView.text = String.format("最新浓度: ${v.data.strength}") - binding.updateTimeView.text = String.format("更新时间: ${v.data.uptime}") - } else { - binding.deviceValueView.text = String.format("最新浓度: 未知") - binding.updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - binding.locationView.text = "经纬度异常,无法查看具体位置" - } else { - val queryParam = RegeocodeQuery( - LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()), - 200f, - GeocodeSearch.AMAP - ) - val latLng = LatLng(device.latGaode.toDouble(), device.lngGaode.toDouble()) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - binding.locationView.text = - String.format("详细位置: ${result?.regeocodeAddress?.formatAddress}") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - - val cameraPosition = CameraPosition(latLng, 18f, 0f, 0f) - val newCameraPosition = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(newCameraPosition, 1500, object : AMap.CancelableCallback { - override fun onFinish() { - //添加Marker - val markerOptions = MarkerOptions().position(latLng) - .icon(BitmapDescriptorFactory.fromResource(R.mipmap.well_location)) - .draggable(false) - aMap.addMarker(markerOptions) - } - - override fun onCancel() { - - } - }) - aMap.setOnMarkerClickListener { - RouteOnMap.startNavigation( - this@MapDeviceBriefActivity, "", latLng - ) - true - } - } - } - } - } - - /**地图相关*********/ - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding.mapView.onCreate(savedInstanceState) - } - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onDestroy() { - binding.mapView.onDestroy() - super.onDestroy() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_group_device_map.xml b/app/src/main/res/layout/activity_group_device_map.xml new file mode 100644 index 0000000..078406e --- /dev/null +++ b/app/src/main/res/layout/activity_group_device_map.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index bb4ff3c..ffe86f1 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,26 +1,40 @@ - + android:background="@color/mainBackColor"> - + android:layout_height="match_parent" + android:orientation="vertical"> - - + + + + + - \ No newline at end of file + android:layout_gravity="center|bottom" + android:backgroundTint="@color/white" + android:contentDescription="@string/app_name" + android:src="@android:drawable/ic_input_add" + app:borderWidth="0dp" + app:elevation="@dimen/dp_5" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_map_device_brief.xml b/app/src/main/res/layout/activity_map_device_brief.xml deleted file mode 100644 index dc425d4..0000000 --- a/app/src/main/res/layout/activity_map_device_brief.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml deleted file mode 100644 index 9616185..0000000 --- a/app/src/main/res/layout/fragment_home.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_overview.xml b/app/src/main/res/layout/fragment_overview.xml index f5aff85..4070947 100644 --- a/app/src/main/res/layout/fragment_overview.xml +++ b/app/src/main/res/layout/fragment_overview.xml @@ -11,7 +11,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/mainThemeColor" - app:tbv_right_image="@drawable/ic_refresh_white" + app:tbv_right_image="@drawable/ic_change_map" app:tbv_show_left_image="false" app:tbv_show_right_image="true" app:tbv_smaller_title="true" @@ -27,10 +27,21 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - + android:layout_height="match_parent" + app:srlEnableLoadMore="false"> + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 529403a..8908a3e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,7 +55,7 @@ - + +) : FragmentPagerAdapter(manager) { + + override fun getItem(position: Int): Fragment = pages[position] + + override fun getCount(): Int = pages.size + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + //注释掉父类方法,一直不销毁Fragment + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt deleted file mode 100644 index ab6743f..0000000 --- a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt +++ /dev/null @@ -1,387 +0,0 @@ -package com.casic.smarttube.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.CoordinateConverter -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.Marker -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.FragmentHomeBinding -import com.casic.smarttube.model.MapDeviceModel -import com.casic.smarttube.model.ProjectGroupModel -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.view.AddDeviceActivity -import com.casic.smarttube.vm.DeviceViewModel -import com.casic.smarttube.vm.ProjectGroupViewModel -import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter -import com.pengxh.kt.lite.adapter.ViewHolder -import com.pengxh.kt.lite.base.KotlinBaseFragment -import com.pengxh.kt.lite.extensions.navigatePageTo -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView -import com.pengxh.kt.lite.widget.dialog.AlertControlDialog - - -class HomePageFragment : KotlinBaseFragment(), AMap.OnCameraChangeListener, - AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener, - AMap.OnMapClickListener { - - private val kTag = "HomePageFragment" - private val geocoderSearch by lazy { GeocodeSearch(requireContext()) } - private lateinit var aMap: AMap - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var groupViewModel: ProjectGroupViewModel - private lateinit var groupListAdapter: NormalRecyclerAdapter - private var clickedMarker: Marker? = null - - /** - * 自定义Marker弹出框 - * */ - private var infoView: View? = null - - /** - * 所有设备列表信息集合 - * */ - private var deviceModels: MutableList = ArrayList() - - override fun initViewBinding( - inflater: LayoutInflater, container: ViewGroup? - ): FragmentHomeBinding { - return FragmentHomeBinding.inflate(inflater, container, false) - } - - override fun setupTopBarLayout() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - - } - - override fun onRightClick() { - requireContext().navigatePageTo() - } - }) - } - - override fun observeRequestState() { - groupViewModel.loadState.observe(this) { state -> - when (state) { - LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - //地图初始化 - initMap(savedInstanceState) - - //默认显示所有设备 - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - deviceViewModel.mapDeviceModel.observe(this) { - if (it.code == 200) { - val allMarkerOptions = ArrayList() - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //缓存所有设备详情,点击Marker时候需要 - deviceModels.add(device) - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - //将所有设备信息转化缓存为Marker点 - allMarkerOptions.add( - MarkerOptions().position(LatLng(latitude, longitude)) - .title(device.devcode).snippet(device.modelName) - ) - } - } - } - - allMarkerOptions.forEach { marker -> - aMap.addMarker(marker) - } - - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate, 1500, null) - } - } - deviceViewModel.getMapDeviceList() - - groupViewModel = ViewModelProvider(this)[ProjectGroupViewModel::class.java] - groupViewModel.groupModel.observe(this) { - if (it.code == 200) { - bindRecyclerView(it) - } - } - - groupViewModel.groupDeviceModel.observe(this) { - if (it.code == 200) { - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - } - } - } - //计算所有点的中心点位置 - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate) - } - } - } - - private fun bindRecyclerView(it: ProjectGroupModel) { - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - binding.homeRecyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - // 根据groupId查询组下设备 - groupViewModel.getDeviceListByGroup(item.groupId) - } - }) - } - - override fun initEvent() { - - } - - private fun initMap(savedInstanceState: Bundle?) { - binding.mapView.onCreate(savedInstanceState) - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 - - // 地图缩放监听 - aMap.addOnCameraChangeListener(this) - // marker 点击事件监听 - aMap.addOnMarkerClickListener(this) - // 点击marker弹出自定义popup - aMap.setInfoWindowAdapter(this) - //信息窗点击事件 - aMap.addOnInfoWindowClickListener(this) - //地图点击事件,用于隐藏infoWindow - aMap.setOnMapClickListener(this) - } - - override fun onCameraChange(cameraPosition: CameraPosition?) { - - } - - //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker - override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { - - } - - override fun onMarkerClick(marker: Marker?): Boolean { - marker?.apply { - clickedMarker = this - if (isInfoWindowShown) { - hideInfoWindow() - } else { - showInfoWindow() - } - } - return true - } - - override fun onMapClick(p0: LatLng?) { - clickedMarker?.apply { - if (isInfoWindowShown) { - hideInfoWindow() - } - } - } - - override fun getInfoWindow(marker: Marker?): View? { - if (infoView == null) { - infoView = LayoutInflater.from(requireContext()).inflate( - R.layout.popu_map_info, null - ) - } - marker?.apply { - renderWindow(this, infoView!!) - } - return infoView - } - - private fun renderWindow(marker: Marker, view: View) { - //反射得到popup里面的控件对象 - val deviceCodeView = view.findViewById(R.id.deviceCodeView) - val deviceModelView = view.findViewById(R.id.deviceModelView) - val deviceValueView = view.findViewById(R.id.deviceValueView) - val updateTimeView = view.findViewById(R.id.updateTimeView) - val locationView = view.findViewById(R.id.locationView) - - //绑定数据 - val clicked = marker.position - deviceModels.forEach { device -> - if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { - deviceCodeView.text = String.format("设备编号: ${device.devcode}") - deviceModelView.text = String.format("设备模型: ${device.modelName}") - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(requireActivity()) { - if (it.code == 200) { - deviceValueView.text = String.format("最新浓度: ${it.data.strength}") - updateTimeView.text = String.format("更新时间: ${it.data.uptime}") - } else { - deviceValueView.text = String.format("最新浓度: 未知") - updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - locationView.text = "经纬度异常,无法查看具体位置" - } else { - val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - val address = result?.regeocodeAddress?.formatAddress - val temp = StringBuilder() - if (address!!.length > 16) { - temp.append(address.substring(0, 14)).append("\r\n") - .append(address.substring(16)) - } else { - temp.append(address) - } - locationView.text = String.format("详细位置: $temp") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - } - - /** - * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 - * */ - override fun getInfoContents(p0: Marker?): View? = null - - override fun onInfoWindowClick(marker: Marker?) { - marker?.apply { - AlertControlDialog.Builder().setContext(requireContext()).setTitle("操作提示") - .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - val lat = position.latitude.toString() - val lng = position.longitude.toString() - if (lat.isBlank() || lng.isBlank()) { - "窨井经纬度异常,无法开启导航".show(requireContext()) - return - } - RouteOnMap.startNavigation(requireContext(), snippet, position) - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - - /***以下是地图生命周期管理************************************************************************/ - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - groupViewModel.getProGroupList() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } - - override fun onDestroy() { - super.onDestroy() - binding.mapView.onDestroy() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt index 1d0aa3d..dd09cf5 100644 --- a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt +++ b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt @@ -15,12 +15,16 @@ import com.casic.smarttube.databinding.FragmentOverviewBinding import com.casic.smarttube.model.ProjectGroupModel import com.casic.smarttube.view.GroupDeviceActivity +import com.casic.smarttube.view.GroupDeviceMapActivity import com.casic.smarttube.vm.ProjectGroupViewModel import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseFragment import com.pengxh.kt.lite.divider.RecyclerViewItemDivider import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.EmptyView import com.pengxh.kt.lite.widget.TitleBarView import com.pengxh.kt.lite.widget.dialog.AlertInputDialog @@ -32,6 +36,7 @@ private lateinit var groupViewModel: ProjectGroupViewModel private lateinit var groupListAdapter: NormalRecyclerAdapter private var clickedPosition = 0 + private var isRefresh = false override fun initViewBinding( inflater: LayoutInflater, container: ViewGroup? @@ -40,7 +45,15 @@ } override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + } + + override fun onRightClick() { + requireContext().navigatePageTo() + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { @@ -55,66 +68,93 @@ groupListAdapter.notifyItemChanged(clickedPosition) } } - groupViewModel.getGroupList() + } + + override fun onResume() { + super.onResume() + groupViewModel.getProGroupList() } private fun bindRecyclerView(it: ProjectGroupModel) { val dataRows = it.data - if (dataRows.size == 0) { - binding.emptyView.visibility = View.VISIBLE - binding.recyclerView.visibility = View.GONE - } else { - binding.emptyView.visibility = View.GONE - binding.recyclerView.visibility = View.VISIBLE + when { + isRefresh -> { + binding.refreshView.finishRefresh() + isRefresh = false + groupListAdapter.refresh(dataRows) + } - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_over_view_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - .setOnClickListener(R.id.editGroupNameView) { - clickedPosition = position - editGroupName(item) - } - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) + else -> { + if (dataRows.size == 0) { + binding.emptyView.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE + } else { + binding.emptyView.visibility = View.GONE + binding.recyclerView.visibility = View.VISIBLE + + groupListAdapter = object : NormalRecyclerAdapter( + R.layout.item_group_over_view_rv_l, it.data + ) { + override fun convertView( + viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel + ) { + viewHolder.setText(R.id.groupNameView, item.groupId) + .setText(R.id.totalDeviceNumView, item.totalDevice) + .setText(R.id.inUseDeviceNumView, item.alive) + .setText(R.id.notUseDeviceNumView, item.unalive) + .setOnClickListener(R.id.editGroupNameView) { + clickedPosition = position + editGroupName(item) } - } + if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { + viewHolder.setText( + R.id.groupLocationView, + "经纬度异常,无法查看具体位置" + ) + } else { + val point = + LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched( + result: RegeocodeResult?, + rCode: Int + ) { + if (rCode == 1000) { + viewHolder.setText( + R.id.groupLocationView, + String.format("${result?.regeocodeAddress?.formatAddress}") + ) + } + } - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + override fun onGeocodeSearched( + result: GeocodeResult?, + rCode: Int + ) { + } + }) } - }) + } } + binding.recyclerView.addItemDecoration( + RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) + ) + binding.recyclerView.adapter = groupListAdapter + groupListAdapter.setOnItemClickedListener(object : + NormalRecyclerAdapter.OnItemClickedListener { + override fun onItemClicked( + position: Int, + item: ProjectGroupModel.DataModel + ) { + requireContext().navigatePageTo(item.groupId) + } + }) } } - binding.recyclerView.addItemDecoration( - RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) - ) - binding.recyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - requireContext().navigatePageTo(item.groupId) - } - }) } } @@ -139,18 +179,31 @@ } override fun observeRequestState() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - + groupViewModel.loadState.observe(this) { + if (isRefresh) { + return@observe } + when (it) { + LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中,请稍后...") - override fun onRightClick() { - groupViewModel.getProGroupList() + LoadState.Success -> { + LoadingDialog.dismiss() + } + + LoadState.Fail -> { + LoadingDialog.dismiss() + "数据加载失败,请重试".show(requireContext()) + } } - }) + } } override fun initEvent() { + binding.refreshView.setOnRefreshListener { + isRefresh = true + groupViewModel.getProGroupList() + } + binding.emptyView.setOnClickListener(object : EmptyView.OnClickListener { override fun onReloadButtonClicked() { groupViewModel.getProGroupList() diff --git a/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt new file mode 100644 index 0000000..c33c40e --- /dev/null +++ b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt @@ -0,0 +1,288 @@ +package com.casic.smarttube.view + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.lifecycle.ViewModelProvider +import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.CameraUpdateFactory +import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.CameraPosition +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.Marker +import com.amap.api.maps.model.MarkerOptions +import com.amap.api.services.core.LatLonPoint +import com.amap.api.services.geocoder.GeocodeResult +import com.amap.api.services.geocoder.GeocodeSearch +import com.amap.api.services.geocoder.RegeocodeQuery +import com.amap.api.services.geocoder.RegeocodeResult +import com.casic.smarttube.R +import com.casic.smarttube.databinding.ActivityGroupDeviceMapBinding +import com.casic.smarttube.extensions.initImmersionBar +import com.casic.smarttube.model.MapDeviceModel +import com.casic.smarttube.utils.RouteOnMap +import com.casic.smarttube.vm.DeviceViewModel +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog + +class GroupDeviceMapActivity : KotlinBaseActivity(), + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, + AMap.OnInfoWindowClickListener, AMap.OnMapClickListener { + + private val context = this + private val geocoderSearch by lazy { GeocodeSearch(this) } + private lateinit var aMap: AMap + private lateinit var deviceViewModel: DeviceViewModel + private var clickedMarker: Marker? = null + + /** + * 自定义Marker弹出框 + * */ + private var infoView: View? = null + + /** + * 所有设备列表信息集合 + * */ + private var deviceModels: MutableList = ArrayList() + + override fun initViewBinding(): ActivityGroupDeviceMapBinding { + return ActivityGroupDeviceMapBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + } + + override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + //地图初始化 + initMap(savedInstanceState) + + //默认显示所有设备 + deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] + deviceViewModel.mapDeviceModel.observe(this) { + if (it.code == 200) { + val allMarkerOptions = ArrayList() + val latitudeList = ArrayList() + val longitudeList = ArrayList() + it.data.forEach { device -> + val lat = device.latGaode.toString() + val lng = device.lngGaode.toString() + if (lat.isNotBlank() && lng.isNotBlank()) { + //返回true代表当前位置在大陆、港澳地区,反之不在 + val latitude = lat.toDouble() + val longitude = lng.toDouble() + if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { + //缓存所有设备详情,点击Marker时候需要 + deviceModels.add(device) + //分别缓存经、纬度 + latitudeList.add(latitude) + longitudeList.add(longitude) + //将所有设备信息转化缓存为Marker点 + allMarkerOptions.add( + MarkerOptions().position(LatLng(latitude, longitude)) + .title(device.devcode).snippet(device.modelName) + ) + } + } + } + + allMarkerOptions.forEach { marker -> + aMap.addMarker(marker) + } + + val latLng = LatLng(latitudeList[0], longitudeList[0]) + val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) + val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) + aMap.animateCamera(cameraUpdate, 1500, null) + } + } + deviceViewModel.getMapDeviceList() + } + + override fun initEvent() { + + } + + private fun initMap(savedInstanceState: Bundle?) { + binding.mapView.onCreate(savedInstanceState) + aMap = binding.mapView.map + aMap.mapType = AMap.MAP_TYPE_NORMAL + val uiSettings = aMap.uiSettings + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 + + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker 点击事件监听 + aMap.addOnMarkerClickListener(this) + // 点击marker弹出自定义popup + aMap.setInfoWindowAdapter(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + //地图点击事件,用于隐藏infoWindow + aMap.setOnMapClickListener(this) + } + + override fun onCameraChange(cameraPosition: CameraPosition?) { + + } + + //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker + override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { + + } + + override fun onMarkerClick(marker: Marker?): Boolean { + marker?.apply { + clickedMarker = this + if (isInfoWindowShown) { + hideInfoWindow() + } else { + showInfoWindow() + } + } + return true + } + + override fun onMapClick(p0: LatLng?) { + clickedMarker?.apply { + if (isInfoWindowShown) { + hideInfoWindow() + } + } + } + + override fun getInfoWindow(marker: Marker?): View? { + if (infoView == null) { + infoView = LayoutInflater.from(this).inflate(R.layout.popu_map_info, null) + } + marker?.apply { + renderWindow(this, infoView!!) + } + return infoView + } + + private fun renderWindow(marker: Marker, view: View) { + //反射得到popup里面的控件对象 + val deviceCodeView = view.findViewById(R.id.deviceCodeView) + val deviceModelView = view.findViewById(R.id.deviceModelView) + val deviceValueView = view.findViewById(R.id.deviceValueView) + val updateTimeView = view.findViewById(R.id.updateTimeView) + val locationView = view.findViewById(R.id.locationView) + + //绑定数据 + val clicked = marker.position + deviceModels.forEach { device -> + if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { + deviceCodeView.text = String.format("设备编号: ${device.devcode}") + deviceModelView.text = String.format("设备模型: ${device.modelName}") + //获取设备最新浓度信息 + deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) + deviceViewModel.lastDataModel.observe(this) { + if (it.code == 200) { + deviceValueView.text = String.format("最新浓度: ${it.data.strength}") + updateTimeView.text = String.format("更新时间: ${it.data.uptime}") + } else { + deviceValueView.text = String.format("最新浓度: 未知") + updateTimeView.text = String.format("更新时间: 未知") + } + } + if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { + locationView.text = "经纬度异常,无法查看具体位置" + } else { + val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { + if (rCode == 1000) { + val address = result?.regeocodeAddress?.formatAddress + val temp = StringBuilder() + if (address!!.length > 16) { + temp.append(address.substring(0, 14)).append("\r\n") + .append(address.substring(16)) + } else { + temp.append(address) + } + locationView.text = String.format("详细位置: $temp") + } + } + + override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + + } + }) + } + } + } + } + + /** + * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 + * */ + override fun getInfoContents(p0: Marker?): View? = null + + override fun onInfoWindowClick(marker: Marker?) { + marker?.apply { + AlertControlDialog.Builder().setContext(context).setTitle("操作提示") + .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + val lat = position.latitude.toString() + val lng = position.longitude.toString() + if (lat.isBlank() || lng.isBlank()) { + "窨井经纬度异常,无法开启导航".show(context) + return + } + RouteOnMap.startNavigation(context, snippet, position) + } + + override fun onCancelClick() { + + } + }).build().show() + } + } + + /***以下是地图生命周期管理************************************************************************/ + + override fun onResume() { + super.onResume() + binding.mapView.onResume() + } + + override fun onPause() { + super.onPause() + binding.mapView.onPause() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + binding.mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + super.onDestroy() + binding.mapView.onDestroy() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt index c7f06c9..b6b4e8a 100644 --- a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt +++ b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt @@ -3,29 +3,25 @@ import android.os.Bundle import android.view.KeyEvent import android.view.MenuItem -import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter import androidx.viewpager.widget.ViewPager import com.casic.smarttube.R +import com.casic.smarttube.adapter.TabPageViewAdapter import com.casic.smarttube.databinding.ActivityMainBinding import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.fragment.HomePageFragment import com.casic.smarttube.fragment.MinePageFragment import com.casic.smarttube.fragment.OverviewFragment -import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show class MainActivity : KotlinBaseActivity() { private var menuItem: MenuItem? = null - private var fragmentPages: MutableList = ArrayList() + private var fragmentPages: ArrayList = ArrayList() private var clickTime: Long = 0 init { - fragmentPages.add(HomePageFragment()) fragmentPages.add(OverviewFragment()) fragmentPages.add(MinePageFragment()) } @@ -35,30 +31,13 @@ } override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) } override fun initOnCreate(savedInstanceState: Bundle?) { //保留icon原图颜色 binding.bottomNavigation.itemIconTintList = null - binding.bottomNavigation.setOnItemSelectedListener { menuItem -> - when (menuItem.itemId) { - R.id.nav_home -> { - binding.mainViewPager.currentItem = 0 - } - - R.id.nav_overview -> { - binding.mainViewPager.currentItem = 1 - } - - R.id.nav_mine -> { - binding.mainViewPager.currentItem = 2 - } - } - false - } - binding.mainViewPager.adapter = ViewPagerAdapter(fragmentPages, supportFragmentManager) + binding.mainViewPager.adapter = TabPageViewAdapter(supportFragmentManager, fragmentPages) } override fun observeRequestState() { @@ -66,6 +45,18 @@ } override fun initEvent() { + binding.bottomNavigation.setOnItemSelectedListener { menuItem -> + when (menuItem.itemId) { + R.id.nav_overview -> { + binding.mainViewPager.currentItem = 0 + } + + R.id.nav_mine -> { + binding.mainViewPager.currentItem = 1 + } + } + false + } binding.mainViewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageScrollStateChanged(state: Int) { @@ -87,6 +78,10 @@ menuItem!!.isChecked = true } }) + + binding.addDeviceButton.setOnClickListener { + navigatePageTo() + } } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { @@ -100,18 +95,4 @@ } } else super.onKeyDown(keyCode, event) } - - inner class ViewPagerAdapter(list: MutableList, manager: FragmentManager) : - FragmentPagerAdapter(manager) { - - private var viewPages: List = list - - override fun getItem(position: Int): Fragment = viewPages[position] - - override fun getCount(): Int = viewPages.size - - override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { - - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt b/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt deleted file mode 100644 index b5be93b..0000000 --- a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt +++ /dev/null @@ -1,174 +0,0 @@ -package com.casic.smarttube.view - -import android.os.Bundle -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.model.BitmapDescriptorFactory -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.ActivityMapDeviceBriefBinding -import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.vm.DeviceViewModel -import com.gyf.immersionbar.ImmersionBar -import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.utils.LiteKitConstant -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView - -class MapDeviceBriefActivity : KotlinBaseActivity() { - - private val kTag = "MapDeviceBriefActivity" - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var aMap: AMap - private lateinit var params: ArrayList - private val geocoderSearch by lazy { GeocodeSearch(this) } - - - override fun initViewBinding(): ActivityMapDeviceBriefBinding { - return ActivityMapDeviceBriefBinding.inflate(layoutInflater) - } - - override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - finish() - } - - override fun onRightClick() { - - } - }) - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图旋转 - - this.params = intent.getStringArrayListExtra(LiteKitConstant.INTENT_PARAM_KEY)!! - - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - } - - override fun observeRequestState() { - deviceViewModel.loadState.observe(this) { - when (it) { - LoadState.Loading -> LoadingDialog.show(this, "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initEvent() { - deviceViewModel.obtainDeviceDetail(params[0], params[1]) - deviceViewModel.deviceDetailModel.observe(this) { - if (it.code == 200) { - val device = it.data - - binding.deviceCodeView.text = String.format("设备编号: ${device.devcode}") - binding.deviceModelView.text = String.format("设备模型: ${params[2]}") - - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(this) { v -> - if (v.code == 200) { - binding.deviceValueView.text = String.format("最新浓度: ${v.data.strength}") - binding.updateTimeView.text = String.format("更新时间: ${v.data.uptime}") - } else { - binding.deviceValueView.text = String.format("最新浓度: 未知") - binding.updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - binding.locationView.text = "经纬度异常,无法查看具体位置" - } else { - val queryParam = RegeocodeQuery( - LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()), - 200f, - GeocodeSearch.AMAP - ) - val latLng = LatLng(device.latGaode.toDouble(), device.lngGaode.toDouble()) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - binding.locationView.text = - String.format("详细位置: ${result?.regeocodeAddress?.formatAddress}") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - - val cameraPosition = CameraPosition(latLng, 18f, 0f, 0f) - val newCameraPosition = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(newCameraPosition, 1500, object : AMap.CancelableCallback { - override fun onFinish() { - //添加Marker - val markerOptions = MarkerOptions().position(latLng) - .icon(BitmapDescriptorFactory.fromResource(R.mipmap.well_location)) - .draggable(false) - aMap.addMarker(markerOptions) - } - - override fun onCancel() { - - } - }) - aMap.setOnMarkerClickListener { - RouteOnMap.startNavigation( - this@MapDeviceBriefActivity, "", latLng - ) - true - } - } - } - } - } - - /**地图相关*********/ - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding.mapView.onCreate(savedInstanceState) - } - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onDestroy() { - binding.mapView.onDestroy() - super.onDestroy() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_group_device_map.xml b/app/src/main/res/layout/activity_group_device_map.xml new file mode 100644 index 0000000..078406e --- /dev/null +++ b/app/src/main/res/layout/activity_group_device_map.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index bb4ff3c..ffe86f1 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,26 +1,40 @@ - + android:background="@color/mainBackColor"> - + android:layout_height="match_parent" + android:orientation="vertical"> - - + + + + + - \ No newline at end of file + android:layout_gravity="center|bottom" + android:backgroundTint="@color/white" + android:contentDescription="@string/app_name" + android:src="@android:drawable/ic_input_add" + app:borderWidth="0dp" + app:elevation="@dimen/dp_5" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_map_device_brief.xml b/app/src/main/res/layout/activity_map_device_brief.xml deleted file mode 100644 index dc425d4..0000000 --- a/app/src/main/res/layout/activity_map_device_brief.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml deleted file mode 100644 index 9616185..0000000 --- a/app/src/main/res/layout/fragment_home.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_overview.xml b/app/src/main/res/layout/fragment_overview.xml index f5aff85..4070947 100644 --- a/app/src/main/res/layout/fragment_overview.xml +++ b/app/src/main/res/layout/fragment_overview.xml @@ -11,7 +11,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/mainThemeColor" - app:tbv_right_image="@drawable/ic_refresh_white" + app:tbv_right_image="@drawable/ic_change_map" app:tbv_show_left_image="false" app:tbv_show_right_image="true" app:tbv_smaller_title="true" @@ -27,10 +27,21 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - + android:layout_height="match_parent" + app:srlEnableLoadMore="false"> + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml index 3b21717..de0db9e 100644 --- a/app/src/main/res/menu/bottom_nav_menu.xml +++ b/app/src/main/res/menu/bottom_nav_menu.xml @@ -4,14 +4,6 @@ xmlns:tools="http://schemas.android.com/tools"> - - - + +) : FragmentPagerAdapter(manager) { + + override fun getItem(position: Int): Fragment = pages[position] + + override fun getCount(): Int = pages.size + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + //注释掉父类方法,一直不销毁Fragment + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt deleted file mode 100644 index ab6743f..0000000 --- a/app/src/main/java/com/casic/smarttube/fragment/HomePageFragment.kt +++ /dev/null @@ -1,387 +0,0 @@ -package com.casic.smarttube.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.CoordinateConverter -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.Marker -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.FragmentHomeBinding -import com.casic.smarttube.model.MapDeviceModel -import com.casic.smarttube.model.ProjectGroupModel -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.view.AddDeviceActivity -import com.casic.smarttube.vm.DeviceViewModel -import com.casic.smarttube.vm.ProjectGroupViewModel -import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter -import com.pengxh.kt.lite.adapter.ViewHolder -import com.pengxh.kt.lite.base.KotlinBaseFragment -import com.pengxh.kt.lite.extensions.navigatePageTo -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView -import com.pengxh.kt.lite.widget.dialog.AlertControlDialog - - -class HomePageFragment : KotlinBaseFragment(), AMap.OnCameraChangeListener, - AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener, - AMap.OnMapClickListener { - - private val kTag = "HomePageFragment" - private val geocoderSearch by lazy { GeocodeSearch(requireContext()) } - private lateinit var aMap: AMap - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var groupViewModel: ProjectGroupViewModel - private lateinit var groupListAdapter: NormalRecyclerAdapter - private var clickedMarker: Marker? = null - - /** - * 自定义Marker弹出框 - * */ - private var infoView: View? = null - - /** - * 所有设备列表信息集合 - * */ - private var deviceModels: MutableList = ArrayList() - - override fun initViewBinding( - inflater: LayoutInflater, container: ViewGroup? - ): FragmentHomeBinding { - return FragmentHomeBinding.inflate(inflater, container, false) - } - - override fun setupTopBarLayout() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - - } - - override fun onRightClick() { - requireContext().navigatePageTo() - } - }) - } - - override fun observeRequestState() { - groupViewModel.loadState.observe(this) { state -> - when (state) { - LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - //地图初始化 - initMap(savedInstanceState) - - //默认显示所有设备 - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - deviceViewModel.mapDeviceModel.observe(this) { - if (it.code == 200) { - val allMarkerOptions = ArrayList() - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //缓存所有设备详情,点击Marker时候需要 - deviceModels.add(device) - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - //将所有设备信息转化缓存为Marker点 - allMarkerOptions.add( - MarkerOptions().position(LatLng(latitude, longitude)) - .title(device.devcode).snippet(device.modelName) - ) - } - } - } - - allMarkerOptions.forEach { marker -> - aMap.addMarker(marker) - } - - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate, 1500, null) - } - } - deviceViewModel.getMapDeviceList() - - groupViewModel = ViewModelProvider(this)[ProjectGroupViewModel::class.java] - groupViewModel.groupModel.observe(this) { - if (it.code == 200) { - bindRecyclerView(it) - } - } - - groupViewModel.groupDeviceModel.observe(this) { - if (it.code == 200) { - val latitudeList = ArrayList() - val longitudeList = ArrayList() - it.data.forEach { device -> - val lat = device.latGaode.toString() - val lng = device.lngGaode.toString() - if (lat.isNotBlank() && lng.isNotBlank()) { - //返回true代表当前位置在大陆、港澳地区,反之不在 - val latitude = lat.toDouble() - val longitude = lng.toDouble() - if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { - //分别缓存经、纬度 - latitudeList.add(latitude) - longitudeList.add(longitude) - } - } - } - //计算所有点的中心点位置 - val latLng = LatLng(latitudeList[0], longitudeList[0]) - val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) - val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(cameraUpdate) - } - } - } - - private fun bindRecyclerView(it: ProjectGroupModel) { - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - binding.homeRecyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - // 根据groupId查询组下设备 - groupViewModel.getDeviceListByGroup(item.groupId) - } - }) - } - - override fun initEvent() { - - } - - private fun initMap(savedInstanceState: Bundle?) { - binding.mapView.onCreate(savedInstanceState) - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 - - // 地图缩放监听 - aMap.addOnCameraChangeListener(this) - // marker 点击事件监听 - aMap.addOnMarkerClickListener(this) - // 点击marker弹出自定义popup - aMap.setInfoWindowAdapter(this) - //信息窗点击事件 - aMap.addOnInfoWindowClickListener(this) - //地图点击事件,用于隐藏infoWindow - aMap.setOnMapClickListener(this) - } - - override fun onCameraChange(cameraPosition: CameraPosition?) { - - } - - //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker - override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { - - } - - override fun onMarkerClick(marker: Marker?): Boolean { - marker?.apply { - clickedMarker = this - if (isInfoWindowShown) { - hideInfoWindow() - } else { - showInfoWindow() - } - } - return true - } - - override fun onMapClick(p0: LatLng?) { - clickedMarker?.apply { - if (isInfoWindowShown) { - hideInfoWindow() - } - } - } - - override fun getInfoWindow(marker: Marker?): View? { - if (infoView == null) { - infoView = LayoutInflater.from(requireContext()).inflate( - R.layout.popu_map_info, null - ) - } - marker?.apply { - renderWindow(this, infoView!!) - } - return infoView - } - - private fun renderWindow(marker: Marker, view: View) { - //反射得到popup里面的控件对象 - val deviceCodeView = view.findViewById(R.id.deviceCodeView) - val deviceModelView = view.findViewById(R.id.deviceModelView) - val deviceValueView = view.findViewById(R.id.deviceValueView) - val updateTimeView = view.findViewById(R.id.updateTimeView) - val locationView = view.findViewById(R.id.locationView) - - //绑定数据 - val clicked = marker.position - deviceModels.forEach { device -> - if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { - deviceCodeView.text = String.format("设备编号: ${device.devcode}") - deviceModelView.text = String.format("设备模型: ${device.modelName}") - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(requireActivity()) { - if (it.code == 200) { - deviceValueView.text = String.format("最新浓度: ${it.data.strength}") - updateTimeView.text = String.format("更新时间: ${it.data.uptime}") - } else { - deviceValueView.text = String.format("最新浓度: 未知") - updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - locationView.text = "经纬度异常,无法查看具体位置" - } else { - val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - val address = result?.regeocodeAddress?.formatAddress - val temp = StringBuilder() - if (address!!.length > 16) { - temp.append(address.substring(0, 14)).append("\r\n") - .append(address.substring(16)) - } else { - temp.append(address) - } - locationView.text = String.format("详细位置: $temp") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - } - } - } - } - - /** - * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 - * */ - override fun getInfoContents(p0: Marker?): View? = null - - override fun onInfoWindowClick(marker: Marker?) { - marker?.apply { - AlertControlDialog.Builder().setContext(requireContext()).setTitle("操作提示") - .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - val lat = position.latitude.toString() - val lng = position.longitude.toString() - if (lat.isBlank() || lng.isBlank()) { - "窨井经纬度异常,无法开启导航".show(requireContext()) - return - } - RouteOnMap.startNavigation(requireContext(), snippet, position) - } - - override fun onCancelClick() { - - } - }).build().show() - } - } - - /***以下是地图生命周期管理************************************************************************/ - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - groupViewModel.getProGroupList() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } - - override fun onDestroy() { - super.onDestroy() - binding.mapView.onDestroy() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt index 1d0aa3d..dd09cf5 100644 --- a/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt +++ b/app/src/main/java/com/casic/smarttube/fragment/OverviewFragment.kt @@ -15,12 +15,16 @@ import com.casic.smarttube.databinding.FragmentOverviewBinding import com.casic.smarttube.model.ProjectGroupModel import com.casic.smarttube.view.GroupDeviceActivity +import com.casic.smarttube.view.GroupDeviceMapActivity import com.casic.smarttube.vm.ProjectGroupViewModel import com.pengxh.kt.lite.adapter.NormalRecyclerAdapter import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseFragment import com.pengxh.kt.lite.divider.RecyclerViewItemDivider import com.pengxh.kt.lite.extensions.navigatePageTo +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.utils.LoadState +import com.pengxh.kt.lite.utils.LoadingDialog import com.pengxh.kt.lite.widget.EmptyView import com.pengxh.kt.lite.widget.TitleBarView import com.pengxh.kt.lite.widget.dialog.AlertInputDialog @@ -32,6 +36,7 @@ private lateinit var groupViewModel: ProjectGroupViewModel private lateinit var groupListAdapter: NormalRecyclerAdapter private var clickedPosition = 0 + private var isRefresh = false override fun initViewBinding( inflater: LayoutInflater, container: ViewGroup? @@ -40,7 +45,15 @@ } override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + } + + override fun onRightClick() { + requireContext().navigatePageTo() + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { @@ -55,66 +68,93 @@ groupListAdapter.notifyItemChanged(clickedPosition) } } - groupViewModel.getGroupList() + } + + override fun onResume() { + super.onResume() + groupViewModel.getProGroupList() } private fun bindRecyclerView(it: ProjectGroupModel) { val dataRows = it.data - if (dataRows.size == 0) { - binding.emptyView.visibility = View.VISIBLE - binding.recyclerView.visibility = View.GONE - } else { - binding.emptyView.visibility = View.GONE - binding.recyclerView.visibility = View.VISIBLE + when { + isRefresh -> { + binding.refreshView.finishRefresh() + isRefresh = false + groupListAdapter.refresh(dataRows) + } - groupListAdapter = object : NormalRecyclerAdapter( - R.layout.item_group_over_view_rv_l, it.data - ) { - override fun convertView( - viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel - ) { - viewHolder.setText(R.id.groupNameView, item.groupId) - .setText(R.id.totalDeviceNumView, item.totalDevice) - .setText(R.id.inUseDeviceNumView, item.alive) - .setText(R.id.notUseDeviceNumView, item.unalive) - .setOnClickListener(R.id.editGroupNameView) { - clickedPosition = position - editGroupName(item) - } - if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { - viewHolder.setText(R.id.groupLocationView, "经纬度异常,无法查看具体位置") - } else { - val point = LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) - val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - viewHolder.setText( - R.id.groupLocationView, - String.format("${result?.regeocodeAddress?.formatAddress}") - ) + else -> { + if (dataRows.size == 0) { + binding.emptyView.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE + } else { + binding.emptyView.visibility = View.GONE + binding.recyclerView.visibility = View.VISIBLE + + groupListAdapter = object : NormalRecyclerAdapter( + R.layout.item_group_over_view_rv_l, it.data + ) { + override fun convertView( + viewHolder: ViewHolder, position: Int, item: ProjectGroupModel.DataModel + ) { + viewHolder.setText(R.id.groupNameView, item.groupId) + .setText(R.id.totalDeviceNumView, item.totalDevice) + .setText(R.id.inUseDeviceNumView, item.alive) + .setText(R.id.notUseDeviceNumView, item.unalive) + .setOnClickListener(R.id.editGroupNameView) { + clickedPosition = position + editGroupName(item) } - } + if (item.latGaode.isBlank() || item.lngGaode.isBlank()) { + viewHolder.setText( + R.id.groupLocationView, + "经纬度异常,无法查看具体位置" + ) + } else { + val point = + LatLonPoint(item.latGaode.toDouble(), item.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched( + result: RegeocodeResult?, + rCode: Int + ) { + if (rCode == 1000) { + viewHolder.setText( + R.id.groupLocationView, + String.format("${result?.regeocodeAddress?.formatAddress}") + ) + } + } - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + override fun onGeocodeSearched( + result: GeocodeResult?, + rCode: Int + ) { + } + }) } - }) + } } + binding.recyclerView.addItemDecoration( + RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) + ) + binding.recyclerView.adapter = groupListAdapter + groupListAdapter.setOnItemClickedListener(object : + NormalRecyclerAdapter.OnItemClickedListener { + override fun onItemClicked( + position: Int, + item: ProjectGroupModel.DataModel + ) { + requireContext().navigatePageTo(item.groupId) + } + }) } } - binding.recyclerView.addItemDecoration( - RecyclerViewItemDivider(0f, 0f, Color.LTGRAY) - ) - binding.recyclerView.adapter = groupListAdapter - groupListAdapter.setOnItemClickedListener(object : - NormalRecyclerAdapter.OnItemClickedListener { - override fun onItemClicked(position: Int, item: ProjectGroupModel.DataModel) { - requireContext().navigatePageTo(item.groupId) - } - }) } } @@ -139,18 +179,31 @@ } override fun observeRequestState() { - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - + groupViewModel.loadState.observe(this) { + if (isRefresh) { + return@observe } + when (it) { + LoadState.Loading -> LoadingDialog.show(requireActivity(), "数据加载中,请稍后...") - override fun onRightClick() { - groupViewModel.getProGroupList() + LoadState.Success -> { + LoadingDialog.dismiss() + } + + LoadState.Fail -> { + LoadingDialog.dismiss() + "数据加载失败,请重试".show(requireContext()) + } } - }) + } } override fun initEvent() { + binding.refreshView.setOnRefreshListener { + isRefresh = true + groupViewModel.getProGroupList() + } + binding.emptyView.setOnClickListener(object : EmptyView.OnClickListener { override fun onReloadButtonClicked() { groupViewModel.getProGroupList() diff --git a/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt new file mode 100644 index 0000000..c33c40e --- /dev/null +++ b/app/src/main/java/com/casic/smarttube/view/GroupDeviceMapActivity.kt @@ -0,0 +1,288 @@ +package com.casic.smarttube.view + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.lifecycle.ViewModelProvider +import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.CameraUpdateFactory +import com.amap.api.maps.CoordinateConverter +import com.amap.api.maps.model.CameraPosition +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.Marker +import com.amap.api.maps.model.MarkerOptions +import com.amap.api.services.core.LatLonPoint +import com.amap.api.services.geocoder.GeocodeResult +import com.amap.api.services.geocoder.GeocodeSearch +import com.amap.api.services.geocoder.RegeocodeQuery +import com.amap.api.services.geocoder.RegeocodeResult +import com.casic.smarttube.R +import com.casic.smarttube.databinding.ActivityGroupDeviceMapBinding +import com.casic.smarttube.extensions.initImmersionBar +import com.casic.smarttube.model.MapDeviceModel +import com.casic.smarttube.utils.RouteOnMap +import com.casic.smarttube.vm.DeviceViewModel +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.show +import com.pengxh.kt.lite.widget.TitleBarView +import com.pengxh.kt.lite.widget.dialog.AlertControlDialog + +class GroupDeviceMapActivity : KotlinBaseActivity(), + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, + AMap.OnInfoWindowClickListener, AMap.OnMapClickListener { + + private val context = this + private val geocoderSearch by lazy { GeocodeSearch(this) } + private lateinit var aMap: AMap + private lateinit var deviceViewModel: DeviceViewModel + private var clickedMarker: Marker? = null + + /** + * 自定义Marker弹出框 + * */ + private var infoView: View? = null + + /** + * 所有设备列表信息集合 + * */ + private var deviceModels: MutableList = ArrayList() + + override fun initViewBinding(): ActivityGroupDeviceMapBinding { + return ActivityGroupDeviceMapBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) + } + + override fun setupTopBarLayout() { + binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { + override fun onLeftClick() { + finish() + } + + override fun onRightClick() { + + } + }) + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + //地图初始化 + initMap(savedInstanceState) + + //默认显示所有设备 + deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] + deviceViewModel.mapDeviceModel.observe(this) { + if (it.code == 200) { + val allMarkerOptions = ArrayList() + val latitudeList = ArrayList() + val longitudeList = ArrayList() + it.data.forEach { device -> + val lat = device.latGaode.toString() + val lng = device.lngGaode.toString() + if (lat.isNotBlank() && lng.isNotBlank()) { + //返回true代表当前位置在大陆、港澳地区,反之不在 + val latitude = lat.toDouble() + val longitude = lng.toDouble() + if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) { + //缓存所有设备详情,点击Marker时候需要 + deviceModels.add(device) + //分别缓存经、纬度 + latitudeList.add(latitude) + longitudeList.add(longitude) + //将所有设备信息转化缓存为Marker点 + allMarkerOptions.add( + MarkerOptions().position(LatLng(latitude, longitude)) + .title(device.devcode).snippet(device.modelName) + ) + } + } + } + + allMarkerOptions.forEach { marker -> + aMap.addMarker(marker) + } + + val latLng = LatLng(latitudeList[0], longitudeList[0]) + val cameraPosition = CameraPosition(latLng, 14f, 0f, 0f) + val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition) + aMap.animateCamera(cameraUpdate, 1500, null) + } + } + deviceViewModel.getMapDeviceList() + } + + override fun initEvent() { + + } + + private fun initMap(savedInstanceState: Bundle?) { + binding.mapView.onCreate(savedInstanceState) + aMap = binding.mapView.map + aMap.mapType = AMap.MAP_TYPE_NORMAL + val uiSettings = aMap.uiSettings + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不允许地图随手势改变方位 + + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker 点击事件监听 + aMap.addOnMarkerClickListener(this) + // 点击marker弹出自定义popup + aMap.setInfoWindowAdapter(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + //地图点击事件,用于隐藏infoWindow + aMap.setOnMapClickListener(this) + } + + override fun onCameraChange(cameraPosition: CameraPosition?) { + + } + + //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker + override fun onCameraChangeFinish(cameraPosition: CameraPosition?) { + + } + + override fun onMarkerClick(marker: Marker?): Boolean { + marker?.apply { + clickedMarker = this + if (isInfoWindowShown) { + hideInfoWindow() + } else { + showInfoWindow() + } + } + return true + } + + override fun onMapClick(p0: LatLng?) { + clickedMarker?.apply { + if (isInfoWindowShown) { + hideInfoWindow() + } + } + } + + override fun getInfoWindow(marker: Marker?): View? { + if (infoView == null) { + infoView = LayoutInflater.from(this).inflate(R.layout.popu_map_info, null) + } + marker?.apply { + renderWindow(this, infoView!!) + } + return infoView + } + + private fun renderWindow(marker: Marker, view: View) { + //反射得到popup里面的控件对象 + val deviceCodeView = view.findViewById(R.id.deviceCodeView) + val deviceModelView = view.findViewById(R.id.deviceModelView) + val deviceValueView = view.findViewById(R.id.deviceValueView) + val updateTimeView = view.findViewById(R.id.updateTimeView) + val locationView = view.findViewById(R.id.locationView) + + //绑定数据 + val clicked = marker.position + deviceModels.forEach { device -> + if (clicked.latitude == device.latGaode!!.toDouble() && clicked.longitude == device.lngGaode!!.toDouble()) { + deviceCodeView.text = String.format("设备编号: ${device.devcode}") + deviceModelView.text = String.format("设备模型: ${device.modelName}") + //获取设备最新浓度信息 + deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) + deviceViewModel.lastDataModel.observe(this) { + if (it.code == 200) { + deviceValueView.text = String.format("最新浓度: ${it.data.strength}") + updateTimeView.text = String.format("更新时间: ${it.data.uptime}") + } else { + deviceValueView.text = String.format("最新浓度: 未知") + updateTimeView.text = String.format("更新时间: 未知") + } + } + if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { + locationView.text = "经纬度异常,无法查看具体位置" + } else { + val point = LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()) + val queryParam = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP) + geocoderSearch.getFromLocationAsyn(queryParam) + geocoderSearch.setOnGeocodeSearchListener(object : + GeocodeSearch.OnGeocodeSearchListener { + override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { + if (rCode == 1000) { + val address = result?.regeocodeAddress?.formatAddress + val temp = StringBuilder() + if (address!!.length > 16) { + temp.append(address.substring(0, 14)).append("\r\n") + .append(address.substring(16)) + } else { + temp.append(address) + } + locationView.text = String.format("详细位置: $temp") + } + } + + override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { + + } + }) + } + } + } + } + + /** + * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框 + * */ + override fun getInfoContents(p0: Marker?): View? = null + + override fun onInfoWindowClick(marker: Marker?) { + marker?.apply { + AlertControlDialog.Builder().setContext(context).setTitle("操作提示") + .setMessage("确定要前往吗").setNegativeButton("取消").setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + val lat = position.latitude.toString() + val lng = position.longitude.toString() + if (lat.isBlank() || lng.isBlank()) { + "窨井经纬度异常,无法开启导航".show(context) + return + } + RouteOnMap.startNavigation(context, snippet, position) + } + + override fun onCancelClick() { + + } + }).build().show() + } + } + + /***以下是地图生命周期管理************************************************************************/ + + override fun onResume() { + super.onResume() + binding.mapView.onResume() + } + + override fun onPause() { + super.onPause() + binding.mapView.onPause() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + binding.mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + super.onDestroy() + binding.mapView.onDestroy() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt index c7f06c9..b6b4e8a 100644 --- a/app/src/main/java/com/casic/smarttube/view/MainActivity.kt +++ b/app/src/main/java/com/casic/smarttube/view/MainActivity.kt @@ -3,29 +3,25 @@ import android.os.Bundle import android.view.KeyEvent import android.view.MenuItem -import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter import androidx.viewpager.widget.ViewPager import com.casic.smarttube.R +import com.casic.smarttube.adapter.TabPageViewAdapter import com.casic.smarttube.databinding.ActivityMainBinding import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.fragment.HomePageFragment import com.casic.smarttube.fragment.MinePageFragment import com.casic.smarttube.fragment.OverviewFragment -import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show class MainActivity : KotlinBaseActivity() { private var menuItem: MenuItem? = null - private var fragmentPages: MutableList = ArrayList() + private var fragmentPages: ArrayList = ArrayList() private var clickTime: Long = 0 init { - fragmentPages.add(HomePageFragment()) fragmentPages.add(OverviewFragment()) fragmentPages.add(MinePageFragment()) } @@ -35,30 +31,13 @@ } override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) + binding.rootView.initImmersionBar(this, false, R.color.mainThemeColor) } override fun initOnCreate(savedInstanceState: Bundle?) { //保留icon原图颜色 binding.bottomNavigation.itemIconTintList = null - binding.bottomNavigation.setOnItemSelectedListener { menuItem -> - when (menuItem.itemId) { - R.id.nav_home -> { - binding.mainViewPager.currentItem = 0 - } - - R.id.nav_overview -> { - binding.mainViewPager.currentItem = 1 - } - - R.id.nav_mine -> { - binding.mainViewPager.currentItem = 2 - } - } - false - } - binding.mainViewPager.adapter = ViewPagerAdapter(fragmentPages, supportFragmentManager) + binding.mainViewPager.adapter = TabPageViewAdapter(supportFragmentManager, fragmentPages) } override fun observeRequestState() { @@ -66,6 +45,18 @@ } override fun initEvent() { + binding.bottomNavigation.setOnItemSelectedListener { menuItem -> + when (menuItem.itemId) { + R.id.nav_overview -> { + binding.mainViewPager.currentItem = 0 + } + + R.id.nav_mine -> { + binding.mainViewPager.currentItem = 1 + } + } + false + } binding.mainViewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageScrollStateChanged(state: Int) { @@ -87,6 +78,10 @@ menuItem!!.isChecked = true } }) + + binding.addDeviceButton.setOnClickListener { + navigatePageTo() + } } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { @@ -100,18 +95,4 @@ } } else super.onKeyDown(keyCode, event) } - - inner class ViewPagerAdapter(list: MutableList, manager: FragmentManager) : - FragmentPagerAdapter(manager) { - - private var viewPages: List = list - - override fun getItem(position: Int): Fragment = viewPages[position] - - override fun getCount(): Int = viewPages.size - - override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { - - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt b/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt deleted file mode 100644 index b5be93b..0000000 --- a/app/src/main/java/com/casic/smarttube/view/MapDeviceBriefActivity.kt +++ /dev/null @@ -1,174 +0,0 @@ -package com.casic.smarttube.view - -import android.os.Bundle -import androidx.lifecycle.ViewModelProvider -import com.amap.api.maps.AMap -import com.amap.api.maps.AMapOptions -import com.amap.api.maps.CameraUpdateFactory -import com.amap.api.maps.model.BitmapDescriptorFactory -import com.amap.api.maps.model.CameraPosition -import com.amap.api.maps.model.LatLng -import com.amap.api.maps.model.MarkerOptions -import com.amap.api.services.core.LatLonPoint -import com.amap.api.services.geocoder.GeocodeResult -import com.amap.api.services.geocoder.GeocodeSearch -import com.amap.api.services.geocoder.RegeocodeQuery -import com.amap.api.services.geocoder.RegeocodeResult -import com.casic.smarttube.R -import com.casic.smarttube.databinding.ActivityMapDeviceBriefBinding -import com.casic.smarttube.extensions.initImmersionBar -import com.casic.smarttube.utils.RouteOnMap -import com.casic.smarttube.vm.DeviceViewModel -import com.gyf.immersionbar.ImmersionBar -import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.utils.LiteKitConstant -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialog -import com.pengxh.kt.lite.widget.TitleBarView - -class MapDeviceBriefActivity : KotlinBaseActivity() { - - private val kTag = "MapDeviceBriefActivity" - private lateinit var deviceViewModel: DeviceViewModel - private lateinit var aMap: AMap - private lateinit var params: ArrayList - private val geocoderSearch by lazy { GeocodeSearch(this) } - - - override fun initViewBinding(): ActivityMapDeviceBriefBinding { - return ActivityMapDeviceBriefBinding.inflate(layoutInflater) - } - - override fun setupTopBarLayout() { - ImmersionBar.with(this).statusBarDarkFont(false).init() - binding.rootView.initImmersionBar(this, true, R.color.mainThemeColor) - binding.titleView.setOnClickListener(object : TitleBarView.OnClickListener { - override fun onLeftClick() { - finish() - } - - override fun onRightClick() { - - } - }) - } - - override fun initOnCreate(savedInstanceState: Bundle?) { - aMap = binding.mapView.map - aMap.mapType = AMap.MAP_TYPE_NORMAL - val uiSettings = aMap.uiSettings - uiSettings.isCompassEnabled = true - uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER - uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 - uiSettings.isRotateGesturesEnabled = false//不允许地图旋转 - - this.params = intent.getStringArrayListExtra(LiteKitConstant.INTENT_PARAM_KEY)!! - - deviceViewModel = ViewModelProvider(this)[DeviceViewModel::class.java] - } - - override fun observeRequestState() { - deviceViewModel.loadState.observe(this) { - when (it) { - LoadState.Loading -> LoadingDialog.show(this, "数据加载中...") - else -> LoadingDialog.dismiss() - } - } - } - - override fun initEvent() { - deviceViewModel.obtainDeviceDetail(params[0], params[1]) - deviceViewModel.deviceDetailModel.observe(this) { - if (it.code == 200) { - val device = it.data - - binding.deviceCodeView.text = String.format("设备编号: ${device.devcode}") - binding.deviceModelView.text = String.format("设备模型: ${params[2]}") - - //获取设备最新浓度信息 - deviceViewModel.obtainTubeLastData(device.groupId, device.devcode) - deviceViewModel.lastDataModel.observe(this) { v -> - if (v.code == 200) { - binding.deviceValueView.text = String.format("最新浓度: ${v.data.strength}") - binding.updateTimeView.text = String.format("更新时间: ${v.data.uptime}") - } else { - binding.deviceValueView.text = String.format("最新浓度: 未知") - binding.updateTimeView.text = String.format("更新时间: 未知") - } - } - if (device.latGaode.isBlank() || device.lngGaode.isBlank()) { - binding.locationView.text = "经纬度异常,无法查看具体位置" - } else { - val queryParam = RegeocodeQuery( - LatLonPoint(device.latGaode.toDouble(), device.lngGaode.toDouble()), - 200f, - GeocodeSearch.AMAP - ) - val latLng = LatLng(device.latGaode.toDouble(), device.lngGaode.toDouble()) - geocoderSearch.getFromLocationAsyn(queryParam) - geocoderSearch.setOnGeocodeSearchListener(object : - GeocodeSearch.OnGeocodeSearchListener { - override fun onRegeocodeSearched(result: RegeocodeResult?, rCode: Int) { - if (rCode == 1000) { - binding.locationView.text = - String.format("详细位置: ${result?.regeocodeAddress?.formatAddress}") - } - } - - override fun onGeocodeSearched(result: GeocodeResult?, rCode: Int) { - - } - }) - - val cameraPosition = CameraPosition(latLng, 18f, 0f, 0f) - val newCameraPosition = CameraUpdateFactory.newCameraPosition(cameraPosition) - aMap.animateCamera(newCameraPosition, 1500, object : AMap.CancelableCallback { - override fun onFinish() { - //添加Marker - val markerOptions = MarkerOptions().position(latLng) - .icon(BitmapDescriptorFactory.fromResource(R.mipmap.well_location)) - .draggable(false) - aMap.addMarker(markerOptions) - } - - override fun onCancel() { - - } - }) - aMap.setOnMarkerClickListener { - RouteOnMap.startNavigation( - this@MapDeviceBriefActivity, "", latLng - ) - true - } - } - } - } - } - - /**地图相关*********/ - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding.mapView.onCreate(savedInstanceState) - } - - override fun onResume() { - super.onResume() - binding.mapView.onResume() - } - - override fun onPause() { - super.onPause() - binding.mapView.onPause() - } - - override fun onDestroy() { - binding.mapView.onDestroy() - super.onDestroy() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - binding.mapView.onSaveInstanceState(outState) - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_group_device_map.xml b/app/src/main/res/layout/activity_group_device_map.xml new file mode 100644 index 0000000..078406e --- /dev/null +++ b/app/src/main/res/layout/activity_group_device_map.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index bb4ff3c..ffe86f1 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,26 +1,40 @@ - + android:background="@color/mainBackColor"> - + android:layout_height="match_parent" + android:orientation="vertical"> - - + + + + + - \ No newline at end of file + android:layout_gravity="center|bottom" + android:backgroundTint="@color/white" + android:contentDescription="@string/app_name" + android:src="@android:drawable/ic_input_add" + app:borderWidth="0dp" + app:elevation="@dimen/dp_5" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_map_device_brief.xml b/app/src/main/res/layout/activity_map_device_brief.xml deleted file mode 100644 index dc425d4..0000000 --- a/app/src/main/res/layout/activity_map_device_brief.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml deleted file mode 100644 index 9616185..0000000 --- a/app/src/main/res/layout/fragment_home.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_overview.xml b/app/src/main/res/layout/fragment_overview.xml index f5aff85..4070947 100644 --- a/app/src/main/res/layout/fragment_overview.xml +++ b/app/src/main/res/layout/fragment_overview.xml @@ -11,7 +11,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/mainThemeColor" - app:tbv_right_image="@drawable/ic_refresh_white" + app:tbv_right_image="@drawable/ic_change_map" app:tbv_show_left_image="false" app:tbv_show_right_image="true" app:tbv_smaller_title="true" @@ -27,10 +27,21 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - + android:layout_height="match_parent" + app:srlEnableLoadMore="false"> + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml index 3b21717..de0db9e 100644 --- a/app/src/main/res/menu/bottom_nav_menu.xml +++ b/app/src/main/res/menu/bottom_nav_menu.xml @@ -4,14 +4,6 @@ xmlns:tools="http://schemas.android.com/tools"> - - -