增加离线地图下载流程

This commit is contained in:
squallzhjch
2023-03-30 10:50:20 +08:00
parent 97a48237ba
commit 3a80a4ee5d
129 changed files with 1590 additions and 13847 deletions

View File

@@ -1,45 +0,0 @@
package com.navinfo.omqs.ui.activity
import android.os.Bundle
import androidx.activity.viewModels
import androidx.core.view.WindowCompat
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.ActivityMainBinding
/**
* 地图主页面
*/
class MainActivity : BaseActivity() {
private lateinit var binding: ActivityMainBinding
private val viewModel by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
//关联生命周期
binding.lifecycleOwner = this
//给xml转递对象
binding.mainActivity = this
//给xml传递viewModel对象
binding.viewModel = viewModel
//初始化地图
viewModel.initMap(this, binding.mapView.mainActivityMap)
//让viewModel监听activity生命周期
lifecycle.addObserver(viewModel)
}
/**
* 打开个人中菜单
*/
fun openMenu() {
binding.mainActivityDrawer.open()
}
}

View File

@@ -1,51 +0,0 @@
package com.navinfo.omqs.ui.activity
import android.content.Context
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModel
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.collect.library.map.NIMapView
class MainViewModel : ViewModel(), DefaultLifecycleObserver {
/**
* 地图控制器
*/
private lateinit var mapController: NIMapController
/**
* 初始化地图
*/
fun initMap(context: Context, mapView: NIMapView) {
mapController = NIMapController(context = context, mapView = mapView)
}
override fun onStart(owner: LifecycleOwner) {
super.onStart(owner)
//开启定位
mapController.locationLayerHandler.startLocation()
}
override fun onPause(owner: LifecycleOwner) {
mapController.mMapView.onPause()
}
override fun onDestroy(owner: LifecycleOwner) {
mapController.mMapView.onDestroy()
//结束定位
mapController.locationLayerHandler.stopLocation()
}
override fun onResume(owner: LifecycleOwner) {
mapController.mMapView.onResume()
}
/**
* 点击我的位置,回到我的位置
*/
fun onClickLocationButton() {
mapController.locationLayerHandler.animateToCurrentPosition()
}
}

View File

@@ -1,4 +1,4 @@
package com.navinfo.omqs.ui.activity
package com.navinfo.omqs.ui.activity.login
import android.content.Intent
import android.os.Bundle
@@ -6,6 +6,8 @@ import androidx.activity.viewModels
import androidx.databinding.DataBindingUtil
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.ActivityLoginBinding
import com.navinfo.omqs.ui.activity.map.MainActivity
import com.navinfo.omqs.ui.activity.PermissionsActivity
/**
* 登陆页面
@@ -35,6 +37,6 @@ class LoginActivity : PermissionsActivity() {
fun onClickLoginButton() {
val intent = Intent(this@LoginActivity, MainActivity::class.java)
startActivity(intent)
finish()
// finish()
}
}

View File

@@ -1,15 +1,15 @@
package com.navinfo.omqs.ui.activity
package com.navinfo.omqs.ui.activity.login
import android.view.View
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.navinfo.omqs.model.LoginUser
import com.navinfo.omqs.bean.LoginUserBean
class LoginViewModel : ViewModel() {
val loginUser: MutableLiveData<LoginUser> = MutableLiveData()
val loginUser: MutableLiveData<LoginUserBean> = MutableLiveData()
init {
loginUser.value = LoginUser(username = "admin", password = "123456")
loginUser.value = LoginUserBean(username = "admin", password = "123456")
}
/**
@@ -18,6 +18,5 @@ class LoginViewModel : ViewModel() {
fun onClick(view: View) {
loginUser.value!!.username = "admin2"
loginUser.postValue(loginUser.value)
}
}

View File

@@ -0,0 +1,77 @@
package com.navinfo.omqs.ui.activity.map
import android.os.Bundle
import android.util.Log
import androidx.activity.viewModels
import androidx.core.view.WindowCompat
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.viewModelScope
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.ActivityMainBinding
import com.navinfo.omqs.ui.activity.BaseActivity
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
/**
* 地图主页面
*/
@AndroidEntryPoint
class MainActivity : BaseActivity() {
private lateinit var binding: ActivityMainBinding
private val viewModel by viewModels<MainViewModel>()
//注入地图控制器
@Inject
lateinit var mapController: NIMapController
override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
//初始化地图
mapController.init(this, binding.mapView.mainActivityMap)
//关联生命周期
binding.lifecycleOwner = this
//给xml转递对象
binding.mainActivity = this
//给xml传递viewModel对象
binding.viewModel = viewModel
// lifecycle.addObserver(viewModel)
}
override fun onStart() {
super.onStart()
//开启定位
mapController.locationLayerHandler.startLocation()
}
override fun onPause() {
super.onPause()
mapController.mMapView.onPause()
}
override fun onDestroy() {
super.onDestroy()
mapController.mMapView.onDestroy()
mapController.locationLayerHandler.stopLocation()
Log.e("jingo","MainActivity 销毁")
}
override fun onResume() {
super.onResume()
mapController.mMapView.onResume()
}
/**
* 打开个人中菜单
*/
fun openMenu() {
binding.mainActivityDrawer.open()
}
}

View File

@@ -0,0 +1,31 @@
package com.navinfo.omqs.ui.activity.map
import android.util.Log
import androidx.lifecycle.ViewModel
import com.navinfo.collect.library.map.NIMapController
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.scopes.ActivityRetainedScoped
import javax.inject.Inject
import javax.inject.Singleton
/**
* 创建Activity全局viewmode
*/
@HiltViewModel
class MainViewModel @Inject constructor(
private val mapController: NIMapController,
) : ViewModel() {
/**
* 点击我的位置,回到我的位置
*/
fun onClickLocationButton() {
mapController.locationLayerHandler.animateToCurrentPosition()
}
override fun onCleared() {
Log.e("jingo","MainViewModel 被释放了")
super.onCleared()
}
}

View File

@@ -1,45 +0,0 @@
package com.navinfo.omqs.ui.fragment
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.FragmentFirstBinding
/**
* A simple [Fragment] subclass as the default destination in the navigation.
*/
class FirstFragment : Fragment() {
private var _binding: FragmentFirstBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentFirstBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.buttonFirst.setOnClickListener {
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@@ -0,0 +1,25 @@
package com.navinfo.omqs.ui.fragment.offlinemap
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
/**
* 离线地图主页面viewpage适配器
*/
class OfflineMapAdapter(activity: FragmentActivity) :
FragmentStateAdapter(activity) {
private val stateFragment = OfflineMapStateListFragment()
private val cityListFragment = OfflineMapCityListFragment()
override fun getItemCount(): Int {
return 2
}
override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> stateFragment
else ->
cityListFragment
}
}
}

View File

@@ -0,0 +1,33 @@
package com.navinfo.omqs.ui.fragment.offlinemap
import androidx.databinding.ViewDataBinding
import com.navinfo.omqs.R
import com.navinfo.omqs.BR
import com.navinfo.omqs.bean.OfflineMapCityBean
import com.navinfo.omqs.databinding.AdapterOfflineMapCityBinding
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder
import javax.inject.Inject
/**
* 离线地图城市列表 RecyclerView 适配器
*/
class OfflineMapCityListAdapter @Inject constructor() :
BaseRecyclerViewAdapter<OfflineMapCityBean>() {
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
var binding: ViewDataBinding = holder.dataBinding
//立刻刷新UI解决闪烁
// binding.executePendingBindings()
binding.setVariable(BR.cityBean, data[position])
(binding as AdapterOfflineMapCityBinding).offlineMapDownloadBtn.setOnClickListener {
}
}
override fun getItemViewType(position: Int): Int {
return R.layout.adapter_offline_map_city
}
}

View File

@@ -0,0 +1,49 @@
package com.navinfo.omqs.ui.fragment.offlinemap
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.navinfo.omqs.databinding.FragmentOfflineMapCityListBinding
import dagger.hilt.android.AndroidEntryPoint
/**
* 离线地图城市列表
*/
@AndroidEntryPoint
class OfflineMapCityListFragment : Fragment() {
private var _binding: FragmentOfflineMapCityListBinding? = null
private val viewModel by viewModels<OfflineMapCityListViewModel>()
private val binding get() = _binding!!
private val adapter: OfflineMapCityListAdapter by lazy { OfflineMapCityListAdapter() }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentOfflineMapCityListBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val layoutManager = LinearLayoutManager(context)
_binding!!.offlineMapCityListRecyclerview.layoutManager = layoutManager
_binding!!.offlineMapCityListRecyclerview.adapter = adapter
viewModel.cityListLiveData.observe(viewLifecycleOwner) {
adapter.refreshData(it)
}
viewModel.getCityList()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
Log.e("jingo","OfflineMapCityListFragment onDestroyView")
}
}

View File

@@ -0,0 +1,49 @@
package com.navinfo.omqs.ui.fragment.offlinemap
import android.app.Application
import android.content.Context
import android.widget.Toast
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.navinfo.omqs.http.NetResult
import com.navinfo.omqs.http.NetworkService
import com.navinfo.omqs.bean.OfflineMapCityBean
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.launch
import javax.inject.Inject
/**
* 离线地图城市列表viewModel
*/
@HiltViewModel
class OfflineMapCityListViewModel @Inject constructor(
private val networkService: NetworkService,
@ApplicationContext val context: Context
) : ViewModel() {
val cityListLiveData = MutableLiveData<List<OfflineMapCityBean>>()
/**
* 去获取离线地图列表
*/
fun getCityList() {
viewModelScope.launch {
when (val result = networkService.getOfflineMapCityList()) {
is NetResult.Success -> {
cityListLiveData.postValue(result.data!!)
}
is NetResult.Error -> {
Toast.makeText(context, "${result.exception.message}", Toast.LENGTH_SHORT)
.show()
}
is NetResult.Failure -> {
Toast.makeText(context, "${result.code}:${result.msg}", Toast.LENGTH_SHORT)
.show()
}
NetResult.Loading -> {}
}
}
}
}

View File

@@ -0,0 +1,66 @@
package com.navinfo.omqs.ui.fragment.offlinemap
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import com.google.android.material.tabs.TabLayoutMediator
import com.navinfo.omqs.databinding.FragmentOfflineMapBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* 离线地图
*/
class OfflineMapFragment : Fragment() {
private var _binding: FragmentOfflineMapBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentOfflineMapBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//禁止滑动,因为页面在抽屉里,和抽屉的滑动有冲突
binding.offlineMapViewpager.isUserInputEnabled = false
//创建viewpager2的适配器
binding.offlineMapViewpager.adapter = activity?.let { OfflineMapAdapter(it) }
//绑定viewpager2与tabLayout
TabLayoutMediator(
binding.offlineMapTabLayout,
binding.offlineMapViewpager
) { tab, position ->
when (position) {
0 -> tab.text = "下载管理"
1 -> tab.text = "城市列表"
}
}.attach()
//处理返回按钮
binding.offlineMapBack.setOnClickListener {
findNavController().popBackStack()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
Log.e("jingo","OfflineMapFragment onDestroyView")
}
}

View File

@@ -0,0 +1,38 @@
package com.navinfo.omqs.ui.fragment.offlinemap
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import com.navinfo.omqs.databinding.FragmentOfflineMapBinding
import com.navinfo.omqs.databinding.FragmentOfflineMapStateListBinding
class OfflineMapStateListFragment : Fragment() {
private var _binding: FragmentOfflineMapStateListBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentOfflineMapStateListBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
Log.e("jingo","OfflineMapStateListFragment onDestroyView")
}
}

View File

@@ -1,40 +1,42 @@
package com.navinfo.omqs.ui.fragment
package com.navinfo.omqs.ui.fragment.personalcenter
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.FragmentSecondBinding
import com.navinfo.omqs.databinding.FragmentPersonalCenterBinding
/**
* A simple [Fragment] subclass as the second destination in the navigation.
* 个人中心
*/
class SecondFragment : Fragment() {
class PersonalCenterFragment : Fragment() {
private var _binding: FragmentSecondBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private var _binding: FragmentPersonalCenterBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentSecondBinding.inflate(inflater, container, false)
_binding = FragmentPersonalCenterBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.buttonSecond.setOnClickListener {
findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
Log.e("jingo", "NIMapController PersonalCenterFragment onViewCreated")
binding.root.setNavigationItemSelectedListener {
when (it.itemId) {
R.id.personal_center_menu_offline_map ->
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
}
true
}
}

View File

@@ -0,0 +1,32 @@
package com.navinfo.omqs.ui.other
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
/**
* RecyclerView 适配器基础类
*/
abstract class BaseRecyclerViewAdapter<T>(var data: List<T> = listOf()) :
RecyclerView.Adapter<BaseViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
return BaseViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
viewType,
parent,
false
)
)
}
override fun getItemCount(): Int {
return data.size
}
fun refreshData(newData:List<T>){
this.data = newData
this.notifyDataSetChanged()
}
}

View File

@@ -0,0 +1,11 @@
package com.navinfo.omqs.ui.other
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
/**
* dataBinding viewHolder 基类
*/
open class BaseViewHolder(var dataBinding: ViewDataBinding) :
RecyclerView.ViewHolder(dataBinding.root) {
}

View File

@@ -0,0 +1,64 @@
package com.navinfo.omqs.ui.widget
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.opengl.ETC1.getHeight
import android.opengl.ETC1.getWidth
import android.util.AttributeSet
import android.widget.ProgressBar
/**
* 带文字提示的进度条
*/
class MyProgressBar : ProgressBar {
private lateinit var mPaint: Paint
private var text: String = ""
private var rate = 0f
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
initView()
}
constructor(context: Context?) : super(context) {
initView()
}
private fun initView() {
mPaint = Paint()
mPaint.isAntiAlias = true
mPaint.color = Color.BLUE
}
@Synchronized
override fun setProgress(progress: Int) {
setText(progress)
super.setProgress(progress)
}
private fun setText(progress: Int) {
rate = progress * 1.0f / this.getMax()
val i = (rate * 100).toInt()
text = "$i%"
}
@Synchronized
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val rect = Rect()
mPaint.getTextBounds(text, 0, text.length, rect)
// int x = (getWidth()/2) - rect.centerX();
// int y = (getHeight()/2) - rect.centerY();
var x = (width * rate).toInt()
if (x == width) {
// 如果为百分之百则在左边绘制。
x = width - rect.right
}
val y: Int = 0 - rect.top
mPaint.textSize = 22f
canvas.drawText(text, x.toFloat(), y.toFloat(), mPaint)
}
}