Conflicts:
	app/build.gradle
	app/src/main/java/com/navinfo/omqs/OMQSApplication.kt
	app/src/main/java/com/navinfo/omqs/ui/MainActivity.kt
	app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt
	app/src/main/res/layout/fragment_offline_map_state_list.xml
	app/src/main/res/layout/map_view.xml
	collect-library/build.gradle
This commit is contained in:
qiji4215
2023-04-19 15:52:28 +08:00
90 changed files with 2972 additions and 812 deletions

View File

@@ -1,84 +0,0 @@
package com.navinfo.omqs.ui
import android.content.Intent
import android.os.Bundle
import androidx.core.view.WindowCompat
import androidx.navigation.ui.AppBarConfiguration
import com.github.k1rakishou.fsaf.FileChooser
import com.github.k1rakishou.fsaf.callback.FSAFActivityCallbacks
import com.navinfo.omqs.databinding.ActivityMainBinding
import com.navinfo.omqs.ui.activity.PermissionsActivity
class MainActivity : PermissionsActivity(), FSAFActivityCallbacks {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityMainBinding
private val fileChooser by lazy { FileChooser(this@MainActivity) }
override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// val navController = findNavController(R.id.nav_host_fragment_content_main)
//// appBarConfiguration = AppBarConfiguration(navController.graph)
//// setupActionBarWithNavController(navController, appBarConfiguration)
fileChooser.setCallbacks(this@MainActivity)
// binding.fab.setOnClickListener { view ->
// Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
// .setAnchorView(R.id.fab)
// .setAction("Action", null).show()
// // 开始数据导入功能
// fileChooser.openChooseFileDialog(object: FileChooserCallback() {
// override fun onCancel(reason: String) {
// }
//
// override fun onResult(uri: Uri) {
// val file = UriUtils.uri2File(uri)
// Snackbar.make(view, "文件大小为:${file.length()}", Snackbar.LENGTH_LONG)
// .show()
// }
// })
// }
}
override fun onPermissionsGranted() {
}
override fun onPermissionsDenied() {
}
// override fun onCreateOptionsMenu(menu: Menu): Boolean {
// // Inflate the menu; this adds items to the action bar if it is present.
// menuInflater.inflate(R.menu.menu_main, menu)
// return true
// }
// override fun onOptionsItemSelected(item: MenuItem): Boolean {
// // Handle action bar item clicks here. The action bar will
// // automatically handle clicks on the Home/Up button, so long
// // as you specify a parent activity in AndroidManifest.xml.
// return when (item.itemId) {
// R.id.action_settings -> true
// else -> super.onOptionsItemSelected(item)
// }
// }
//
// override fun onSupportNavigateUp(): Boolean {
// val navController = findNavController(R.id.nav_host_fragment_content_main)
// return navController.navigateUp(appBarConfiguration)
// || super.onSupportNavigateUp()
// }
override fun fsafStartActivityForResult(intent: Intent, requestCode: Int) {
startActivityForResult(intent, requestCode)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
fileChooser.onActivityResult(requestCode, resultCode, data)
}
}

View File

@@ -58,11 +58,11 @@ class LoginActivity : PermissionsActivity() {
loginDialog = null
}
LoginStatus.LOGIN_STATUS_SUCCESS -> {
val intent = Intent(this@LoginActivity, MainActivity::class.java)
startActivity(intent)
// finish()
loginDialog?.dismiss()
loginDialog = null
val intent = Intent(this@LoginActivity, MainActivity::class.java)
startActivity(intent)
finish()
}
LoginStatus.LOGIN_STATUS_CANCEL -> {
loginDialog?.dismiss()

View File

@@ -8,10 +8,10 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.navinfo.omqs.bean.LoginUserBean
import com.navinfo.omqs.db.RoomAppDatabase
import com.navinfo.omqs.http.NetResult
import com.navinfo.omqs.http.NetworkService
import com.navinfo.omqs.tools.FileManager
import com.navinfo.omqs.tools.RealmCoroutineScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.*
import okio.IOException
@@ -57,7 +57,7 @@ enum class LoginStatus {
@HiltViewModel
class LoginViewModel @Inject constructor(
private val networkService: NetworkService,
private val realmManager: RealmCoroutineScope
private val roomAppDatabase: RoomAppDatabase
) : ViewModel() {
//用户信息
val loginUser: MutableLiveData<LoginUserBean> = MutableLiveData()
@@ -126,9 +126,7 @@ class LoginViewModel @Inject constructor(
for (cityBean in result.data) {
FileManager.checkOfflineMapFileInfo(cityBean)
}
realmManager.launch {
realmManager.insertOrUpdate(result.data)
}
roomAppDatabase.getOfflineMapDao().insertOrUpdate(result.data)
}
}
is NetResult.Error -> {
@@ -143,7 +141,8 @@ class LoginViewModel @Inject constructor(
.show()
}
}
NetResult.Loading -> {}
is NetResult.Loading -> {}
else -> {}
}
loginStatus.postValue(LoginStatus.LOGIN_STATUS_SUCCESS)
}

View File

@@ -5,6 +5,9 @@ import androidx.activity.viewModels
import androidx.core.view.WindowCompat
import androidx.databinding.DataBindingUtil
import com.blankj.utilcode.util.ToastUtils
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope
import androidx.navigation.findNavController
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.omqs.Constant
import com.navinfo.omqs.R
@@ -26,6 +29,7 @@ class MainActivity : BaseActivity() {
//注入地图控制器
@Inject
lateinit var mapController: NIMapController
@Inject
lateinit var offlineMapDownloadManager: OfflineMapDownloadManager
@@ -37,9 +41,9 @@ class MainActivity : BaseActivity() {
//初始化地图
mapController.init(
this,
binding.mapView.mainActivityMap,
binding.mainActivityMap,
null,
Constant.ROOT_PATH + "/map/"
Constant.MAP_PATH
)
//关联生命周期
binding.lifecycleOwner = this
@@ -48,7 +52,7 @@ class MainActivity : BaseActivity() {
//给xml传递viewModel对象
binding.viewModel = viewModel
// lifecycle.addObserver(viewModel)
lifecycleScope
}
override fun onStart() {
@@ -88,4 +92,15 @@ class MainActivity : BaseActivity() {
binding!!.viewModel!!.onClickCameraButton(this)
}
/**
* 点击录音按钮
*/
fun voiceOnclick() {
val naviController = findNavController(R.id.main_activity_right_fragment)
naviController.navigate(R.id.EvaluationResultFragment)
}
override fun onBackPressed() {
super.onBackPressed()
}
}

View File

@@ -0,0 +1,57 @@
package com.navinfo.omqs.ui.fragment
import android.os.Bundle
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
abstract class BaseFragment : Fragment() {
// override fun onCreateView(
// inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
// ): View {
// val view = OnCreateView(inflater, container, savedInstanceState)
//
// view.isFocusableInTouchMode = true;
// view.requestFocus();
// view.setOnKeyListener { _, keyCode, event ->
// if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_DOWN) {
// onBackPressed()
// }
// false
// }
//
//
// return view
// }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 获取OnBackPressedDispatcher
val dispatcher = requireActivity().onBackPressedDispatcher
val callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
onBackPressed()
}
}
// 添加返回键事件处理逻辑
dispatcher.addCallback(this, callback)
}
// abstract fun OnCreateView(
// inflater: LayoutInflater,
// container: ViewGroup?,
// savedInstanceState: Bundle?
// ): View
fun onBackPressed(): Boolean{
findNavController().navigateUp()
return true
}
}

View File

@@ -0,0 +1,32 @@
package com.navinfo.omqs.ui.fragment.empty
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.navinfo.omqs.databinding.FragmentEmptyBinding
class EmptyFragment :Fragment(){
private var _binding: FragmentEmptyBinding? = null
private val binding get() = _binding!!
// private val viewModel by lazy { viewModels<EvaluationResultViewModel>().value}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentEmptyBinding.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
}
}

View File

@@ -0,0 +1,254 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.NavOptions
import androidx.navigation.findNavController
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.FragmentEvaluationResultBinding
import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.other.shareViewModels
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
private var _binding: FragmentEvaluationResultBinding? = null
private val binding get() = _binding!!
private val viewModel by shareViewModels<EvaluationResultViewModel>("QsRecode")
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
_binding = FragmentEvaluationResultBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
liveDataObserve()
/**
* 点击监听
*/
binding.evaluationClassType.setOnClickListener(this)
binding.evaluationProblemType.setOnClickListener(this)
binding.evaluationPhenomenon.setOnClickListener(this)
binding.evaluationLink.setOnClickListener(this)
binding.evaluationCause.setOnClickListener(this)
//返回按钮点击
binding.evaluationBar.setNavigationOnClickListener {
onBackPressed()
}
//标题栏按钮
binding.evaluationBar.setOnMenuItemClickListener {
when (it.itemId) {
R.id.save -> {
viewModel.saveData()
true
}
R.id.delete -> {
viewModel.deleteData()
true
}
else -> true
}
}
/**
* 读取元数据
*/
viewModel.loadMetadata()
// //监听大分类数据变化
// viewModel.liveDataClassTypeList.observe(viewLifecycleOwner) {
// if (it == null || it.isEmpty()) {
// Toast.makeText(requireContext(), "还没有导入元数据!", Toast.LENGTH_SHORT).show()
// } else {
// binding.evaluationClassType.adapter =
// ArrayAdapter(requireContext(), R.layout.text_item_select, it)
// }
// }
//
// viewModel.liveDataProblemTypeList.observe(viewLifecycleOwner){
// if (it == null || it.isEmpty()) {
// Toast.makeText(requireContext(), "还没有导入元数据!", Toast.LENGTH_SHORT).show()
// }else{
// binding.evaluationProblemType.adapter =
// ArrayAdapter(requireContext(), R.layout.text_item_select, it)
// }
// }
// //选择问题分类的回调
// binding.evaluationClassType.onItemSelectedListener =
// object : AdapterView.OnItemSelectedListener {
// override fun onItemSelected(
// parent: AdapterView<*>?, view: View?, position: Int, id: Long
// ) {
// viewModel.getProblemTypeList(position)
// }
//
// override fun onNothingSelected(parent: AdapterView<*>?) {}
// }
// /**
// * 监听联动选择的内容
// */
// viewModel.problemTypeListLiveData.observe(viewLifecycleOwner) {
// binding.evaluationClassTabLayout.let { tabLayout ->
// tabLayout.removeAllTabs()
// val fragmentList = mutableListOf<Fragment>()
// for (item in it) {
// val tab = tabLayout.newTab()
// tab.text = item
// tabLayout.addTab(tab)
// fragmentList.add(PhenomenonFragment(viewModel.currentClassType, item))
// }
// phenomenonFragmentAdapter =
// activity?.let { a -> EvaluationResultAdapter(a, fragmentList) }
// binding.evaluationViewpager.adapter = phenomenonFragmentAdapter
//
// TabLayoutMediator(
// binding.evaluationClassTabLayout,
// binding.evaluationViewpager
// ) { tab, position ->
// tab.text = it[position]
// }.attach()
// updateHeight(0)
// }
//
// }
// binding.evaluationViewpager.registerOnPageChangeCallback(object :
// ViewPager2.OnPageChangeCallback() {
// override fun onPageSelected(position: Int) {
// super.onPageSelected(position)
// updateHeight(position)
// }
// })
}
// private fun updateHeight(position: Int) {
// phenomenonFragmentAdapter?.let {
// if (it.fragmentList.size > position) {
// val fragment: Fragment = it.fragmentList[position]
// if (fragment.view != null) {
// val viewWidth = View.MeasureSpec.makeMeasureSpec(
// fragment.requireView().width, View.MeasureSpec.EXACTLY
// )
// val viewHeight =
// View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
// fragment.requireView().measure(viewWidth, viewHeight)
// binding.evaluationViewpager.let { viewpager ->
// if (viewpager.layoutParams.height != fragment.requireView().measuredHeight) {
// //必须要用对象去接收,然后修改该对象再采用该对象,否则无法生效...
// val layoutParams: ViewGroup.LayoutParams =
// viewpager.layoutParams
// layoutParams.height = fragment.requireView().measuredHeight
// viewpager.layoutParams = layoutParams
// }
// }
//
// }
// }
// }
//
// }
/**
* 监听liveData
*/
private fun liveDataObserve() {
//监听问题分类更新UI
viewModel.liveDataCurrentClassType.observe(viewLifecycleOwner) {
binding.evaluationClassType.text = it
}
//监听问题类型更新UI
viewModel.liveDataCurrentProblemType.observe(viewLifecycleOwner) {
binding.evaluationProblemType.text = it
}
//监听问题现象更新UI
viewModel.liveDataCurrentPhenomenon.observe(viewLifecycleOwner) {
binding.evaluationPhenomenon.text = it
}
//监听问题环节更新UI
viewModel.liveDataCurrentProblemLink.observe(viewLifecycleOwner) {
binding.evaluationLink.text = it
}
//监听问题初步原因更新UI
viewModel.liveDataCurrentCause.observe(viewLifecycleOwner) {
binding.evaluationCause.text = it
}
//监听是否退出当前页面
viewModel.liveDataFinish.observe(viewLifecycleOwner) {
onBackPressed()
}
}
override fun onDestroyView() {
activity?.apply {
findNavController(R.id.main_activity_middle_fragment).navigateUp()
}
super.onDestroyView()
_binding = null
}
/**
* 处理点击事件
*/
override fun onClick(v: View?) {
v?.let {
when (v.id) {
//上三项,打开面板
R.id.evaluation_class_type, R.id.evaluation_problem_type, R.id.evaluation_phenomenon -> {
activity?.apply {
val controller = findNavController(R.id.main_activity_middle_fragment)
controller.currentDestination?.let {
//如果之前页面是空fragment直接打开面板
if (it.id == R.id.EmptyFragment) {
findNavController(
R.id.main_activity_middle_fragment
).navigate(R.id.PhenomenonFragment)
} else if (it.id != R.id.PhenomenonFragment) {//不是空fragment先弹出之前的fragment
findNavController(
R.id.main_activity_middle_fragment
).navigate(
R.id.PhenomenonFragment,
null,
NavOptions.Builder()
.setPopUpTo(it.id, true).build()
)
}
}
}
}
//下两项,打开面板
R.id.evaluation_link, R.id.evaluation_cause -> {
activity?.apply {
val controller = findNavController(R.id.main_activity_middle_fragment)
controller.currentDestination?.let {
//如果之前页面是空fragment直接打开面板
if (it.id == R.id.EmptyFragment) {
findNavController(
R.id.main_activity_middle_fragment
).navigate(R.id.ProblemLinkFragment)
} else if (it.id != R.id.ProblemLinkFragment) {//不是空fragment先弹出之前的fragment
findNavController(
R.id.main_activity_middle_fragment
).navigate(
R.id.ProblemLinkFragment,
null,
NavOptions.Builder()
.setPopUpTo(it.id, true).build()
)
}
}
}
}
else -> {}
}
}
}
}

View File

@@ -0,0 +1,242 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.navinfo.collect.library.map.GeoPoint
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.omqs.db.RoomAppDatabase
import dagger.hilt.android.lifecycle.HiltViewModel
import io.realm.Realm
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.*
import javax.inject.Inject
@HiltViewModel
class EvaluationResultViewModel @Inject constructor(
private val roomAppDatabase: RoomAppDatabase, private val mapController: NIMapController
) : ViewModel() {
private val markerTitle = "点选marker"
/**
* 操作结束,销毁页面
*/
val liveDataFinish = MutableLiveData<Boolean>()
/**
* 问题分类 liveData给[PhenomenonLeftAdapter]展示的数据
*/
val liveDataClassTypeList = MutableLiveData<List<String>>()
/**
* 问题类型 liveData 给[PhenomenonMiddleAdapter]展示的数据
*/
val liveDataProblemTypeList = MutableLiveData<List<String>>()
/**
* 问题现象 liveData 给[PhenomenonRightGroupHeaderAdapter]展示的数据
*/
val liveDataPhenomenonRightList = MutableLiveData<List<PhenomenonMiddleBean>>()
/**
* 当前选择问题分类 给[EvaluationResultFragment]中 【问题分类】展示数据
*/
var liveDataCurrentClassType = MutableLiveData<String>()
/**
* 当前选择的问题类型 给[EvaluationResultFragment]中 【问题类型】展示数据
*/
var liveDataCurrentProblemType = MutableLiveData<String>()
/**
* 当前选择的问题现象 给[EvaluationResultFragment]中 【问题现象】展示数据
*/
var liveDataCurrentPhenomenon = MutableLiveData<String>()
/**
* 当前选择的问题环节 给[EvaluationResultFragment]中 【问题环节】展示数据
*/
var liveDataCurrentProblemLink = MutableLiveData<String>()
/**
* 当前选择的问初步原因 给[EvaluationResultFragment]中 【初步原因】展示数据
*/
var liveDataCurrentCause = MutableLiveData<String>()
var currentGeoPoint: GeoPoint? = null
init {
Log.e("jingo", "EvaluationResultViewModel 创建了 ${hashCode()}")
mapController.markerHandle.apply {
setOnMapClickListener {
currentGeoPoint = it
addMarker(it, markerTitle)
}
}
val geoPoint = mapController.locationLayerHandler.getCurrentGeoPoint()
geoPoint?.let {
currentGeoPoint = it
mapController.markerHandle.addMarker(geoPoint, markerTitle)
}
}
override fun onCleared() {
super.onCleared()
Log.e("jingo", "EvaluationResultViewModel 销毁了 ${hashCode()}")
mapController.markerHandle.removeMarker(markerTitle)
mapController.markerHandle.removeOnMapClickListener()
}
/**
* 查询数据库,获取问题分类
*/
fun loadMetadata() {
viewModelScope.launch(Dispatchers.IO) {
getClassTypeList()
getProblemLinkList()
}
}
/**
* //获取问题分类列表
*/
fun getClassTypeList() {
viewModelScope.launch(Dispatchers.IO) {
val list = roomAppDatabase.getScProblemTypeDao().findClassTypeList()
list?.let {
//通知页面更新
liveDataClassTypeList.postValue(it)
//如果右侧栏没数据,给个默认值
if (liveDataCurrentClassType.value == null) {
liveDataCurrentClassType.postValue(it[0])
}
getProblemList(it[0])
}
}
}
/**
* 获取问题环节列表和初步问题
*/
fun getProblemLinkList() {
viewModelScope.launch(Dispatchers.IO) {
val list = roomAppDatabase.getScRootCauseAnalysisDao().findAllData()
list?.let { tl ->
if (tl.isNotEmpty()) {
val typeTitleList = mutableListOf<String>()
val phenomenonRightList = mutableListOf<PhenomenonMiddleBean>()
for (item in tl) {
if (!typeTitleList.contains(item.problemLink)) {
typeTitleList.add(item.problemLink)
}
phenomenonRightList.add(
PhenomenonMiddleBean(
title = item.problemLink, text = item.problemCause, isSelect = false
)
)
}
if (liveDataCurrentProblemLink.value == null) {
liveDataCurrentProblemLink.postValue(phenomenonRightList[0].text)
}
if (liveDataCurrentCause.value == null) {
liveDataCurrentCause.postValue(typeTitleList[0])
}
liveDataProblemTypeList.postValue(typeTitleList)
liveDataPhenomenonRightList.postValue(phenomenonRightList)
}
}
}
}
/**
* 获取问题类型列表和问题现象
*/
private suspend fun getProblemList(classType: String) {
val typeList = roomAppDatabase.getScProblemTypeDao().findProblemTypeList(classType)
typeList?.let { tl ->
if (tl.isNotEmpty()) {
val typeTitleList = mutableListOf<String>()
val phenomenonRightList = mutableListOf<PhenomenonMiddleBean>()
for (item in tl) {
if (!typeTitleList.contains(item.problemType)) {
typeTitleList.add(item.problemType)
}
phenomenonRightList.add(
PhenomenonMiddleBean(
title = item.problemType, text = item.phenomenon, isSelect = false
)
)
}
if (liveDataCurrentPhenomenon.value == null) {
liveDataCurrentPhenomenon.postValue(phenomenonRightList[0].text)
}
if (liveDataCurrentProblemType.value == null) {
liveDataCurrentProblemType.postValue(typeTitleList[0])
}
liveDataProblemTypeList.postValue(typeTitleList)
liveDataPhenomenonRightList.postValue(phenomenonRightList)
}
}
}
/**
* 查询问题类型
*/
fun getProblemTypeList(classType: String) {
viewModelScope.launch(Dispatchers.IO) {
liveDataCurrentClassType.postValue(classType)
getProblemList(classType)
}
}
fun setPhenomenonMiddleBean(bean: PhenomenonMiddleBean) {
if (liveDataCurrentPhenomenon.value != bean.text) liveDataCurrentPhenomenon.value =
bean.text
if (liveDataCurrentProblemType.value != bean.title) liveDataCurrentProblemType.value =
bean.title
}
fun setProblemLinkMiddleBean(bean: PhenomenonMiddleBean) {
if (liveDataCurrentProblemLink.value != bean.text) liveDataCurrentProblemLink.value =
bean.text
if (liveDataCurrentCause.value != bean.title) liveDataCurrentCause.value = bean.title
}
fun saveData() {
viewModelScope.launch(Dispatchers.IO) {
val qsRecord = QsRecordBean(
id = UUID.randomUUID().toString(),
classType = liveDataCurrentClassType.value.toString(),
type = liveDataCurrentProblemType.value.toString(),
phenomenon = liveDataCurrentPhenomenon.value.toString(),
problemLink = liveDataCurrentProblemLink.value.toString(),
cause = liveDataCurrentCause.value.toString(),
)
qsRecord.geometry = currentGeoPoint!!.toGeometry()
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
it.copyToRealmOrUpdate(qsRecord)
}
realm.close()
mapController.mMapView.updateMap()
liveDataFinish.postValue(true)
}
}
fun deleteData() {
}
}

View File

@@ -0,0 +1,125 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
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.navigation.findNavController
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.FragmentPhenomenonBinding
import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.other.shareViewModels
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class PhenomenonFragment :
BaseFragment() {
private var _binding: FragmentPhenomenonBinding? = null
private val binding get() = _binding!!
private val viewModel: EvaluationResultViewModel by shareViewModels("QsRecode")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentPhenomenonBinding.inflate(inflater, container, false)
Log.e("jingo", "PhenomenonFragment onCreateView ${hashCode()}")
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//左侧菜单
binding.phenomenonLeftRecyclerview.setHasFixedSize(true)
binding.phenomenonLeftRecyclerview.layoutManager = LinearLayoutManager(requireContext())
val leftAdapter = PhenomenonLeftAdapter { _, text ->
viewModel.getProblemTypeList(text)
}
binding.phenomenonLeftRecyclerview.adapter = leftAdapter
//左侧菜单查询结果监听
viewModel.liveDataClassTypeList.observe(viewLifecycleOwner) {
leftAdapter.refreshData(it)
}
//右侧菜单
binding.phenomenonRightRecyclerview.setHasFixedSize(true)
var rightLayoutManager = LinearLayoutManager(requireContext())
binding.phenomenonRightRecyclerview.layoutManager = rightLayoutManager
val rightAdapter = PhenomenonRightGroupHeaderAdapter { _, bean ->
viewModel.setPhenomenonMiddleBean(bean)
}
binding.phenomenonRightRecyclerview.adapter = rightAdapter
//右侧菜单增加组标题
binding.phenomenonRightRecyclerview.addItemDecoration(
PhenomenonRightGroupHeaderDecoration(
requireContext()
)
)
//右侧菜单查询数据监听
viewModel.liveDataPhenomenonRightList.observe(viewLifecycleOwner) {
rightAdapter.refreshData(it)
}
val middleAdapter = PhenomenonMiddleAdapter { _, title ->
rightLayoutManager.scrollToPositionWithOffset(rightAdapter.getGroupTopIndex(title), 0)
}
binding.phenomenonRightRecyclerview.addOnScrollListener(object :
OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
}
//findLastVisibleItemPosition() :最后一个可见位置
// findFirstVisibleItemPosition() :第一个可见位置
// findLastCompletelyVisibleItemPosition() :最后一个完全可见位置
// findFirstCompletelyVisibleItemPosition() :第一个完全可见位置
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val firstIndex = rightLayoutManager.findFirstVisibleItemPosition()
middleAdapter.setRightTitle(rightAdapter.data[firstIndex].title)
}
})
//中间菜单
binding.phenomenonMiddleRecyclerview.setHasFixedSize(true)
binding.phenomenonMiddleRecyclerview.layoutManager = LinearLayoutManager(requireContext())
binding.phenomenonMiddleRecyclerview.adapter = middleAdapter
//中间侧菜单查询结果监听
viewModel.liveDataProblemTypeList.observe(viewLifecycleOwner) {
middleAdapter.refreshData(it)
}
binding.phenomenonDrawer.setOnClickListener {
when (binding.group.visibility) {
View.INVISIBLE, View.GONE ->
binding.group.visibility = View.VISIBLE
else ->
binding.group.visibility = View.GONE
}
}
viewModel.getClassTypeList()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
Log.e("jingo", "PhenomenonFragment onDestroyView ${hashCode()}")
}
override fun onResume() {
super.onResume()
}
}

View File

@@ -0,0 +1,54 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
import android.view.LayoutInflater
import android.view.ViewGroup
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.TextItemSelectBinding
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder
class PhenomenonLeftAdapter(private var itemListener: ((Int, String) -> Unit?)? = null) :
BaseRecyclerViewAdapter<String>() {
private var selectTitle = ""
override fun getItemViewRes(position: Int): Int {
return R.layout.text_item_select
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
val viewBinding =
TextItemSelectBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return BaseViewHolder(viewBinding)
}
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
val bd = holder.viewBinding as TextItemSelectBinding
val title = data[position]
bd.itemId.text = title
if (selectTitle == title) {
bd.itemId.setBackgroundColor(holder.viewBinding.root.context.getColor(R.color.cv_gray_153))
} else {
bd.itemId.setBackgroundColor(holder.viewBinding.root.context.getColor(R.color.white))
}
bd.root.setOnClickListener {
if (selectTitle != title) {
selectTitle = title
notifyDataSetChanged()
}
itemListener?.invoke(position, title)
}
}
override fun refreshData(newData: List<String>) {
data = newData
selectTitle = newData[0]
notifyDataSetChanged()
}
fun setRightTitle(title: String) {
if (title != selectTitle) {
selectTitle = title
notifyDataSetChanged()
}
}
}

View File

@@ -0,0 +1,54 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
import android.view.LayoutInflater
import android.view.ViewGroup
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.TextItemSelectBinding
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder
class PhenomenonMiddleAdapter(private var itemListener: ((Int, String) -> Unit?)? = null) :
BaseRecyclerViewAdapter<String>() {
private var selectTitle = ""
override fun getItemViewRes(position: Int): Int {
return R.layout.text_item_select
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
val viewBinding =
TextItemSelectBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return BaseViewHolder(viewBinding)
}
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
val bd = holder.viewBinding as TextItemSelectBinding
val title = data[position]
bd.itemId.text = title
if (selectTitle == title) {
bd.itemId.setBackgroundColor(holder.viewBinding.root.context.getColor(R.color.cv_gray_153))
} else {
bd.itemId.setBackgroundColor(holder.viewBinding.root.context.getColor(R.color.white))
}
bd.root.setOnClickListener {
if (selectTitle != title) {
selectTitle = title
notifyDataSetChanged()
}
itemListener?.invoke(position, title)
}
}
override fun refreshData(newData: List<String>) {
data = newData
selectTitle = newData[0]
notifyDataSetChanged()
}
fun setRightTitle(title: String) {
if (title != selectTitle) {
selectTitle = title
notifyDataSetChanged()
}
}
}

View File

@@ -0,0 +1,6 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
/**
* 问题现象列表
*/
data class PhenomenonMiddleBean(val title: String, val text: String, var isSelect: Boolean = false)

View File

@@ -0,0 +1,103 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
import android.view.LayoutInflater
import android.view.ViewGroup
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.TextItemSelectBinding
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder
class PhenomenonRightGroupHeaderAdapter(private var itemListener: ((Int, PhenomenonMiddleBean) -> Unit?)? = null) :
BaseRecyclerViewAdapter<PhenomenonMiddleBean>() {
private var groupTitleList = mutableListOf<String>()
override fun getItemViewRes(position: Int): Int {
return R.layout.text_item_select
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
val viewBinding =
TextItemSelectBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return BaseViewHolder(viewBinding)
}
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
val bd = holder.viewBinding as TextItemSelectBinding
bd.itemId.text = data[position].text
bd.root.setOnClickListener {
itemListener?.invoke(position, data[position])
}
}
/**
* 判断position对应的Item是否是组的第一项
*
* @param position
* @return
*/
fun isItemHeader(position: Int): Boolean {
if (position >= data.size)
return false
return if (position == 0) {
true
} else {
val lastGroupName = data[position - 1].title
val currentGroupName = data[position].title
//判断上一个数据的组别和下一个数据的组别是否一致,如果不一致则是不同组,也就是为第一项(头部)
lastGroupName != currentGroupName
}
}
fun isLastGroupTitle(position: Int): Boolean {
if (groupTitleList.isNotEmpty() && data[position].title == groupTitleList.last()) {
return true
}
return false
}
/**
* 获取position对应的Item组名
*
* @param position
* @return
*/
fun getGroupName(position: Int): String {
return data[position].title
}
fun getGroupTopIndex(position: Int): Int {
var nowPosition = position
val title = data[position].title
for (i in data.size - 2 downTo 0) {
if (data[i].title == title) {
nowPosition = i
} else {
break
}
}
return nowPosition
}
fun getGroupTopIndex(title: String): Int {
for (i in data.indices) {
if (data[i].title == title)
return i
}
return 0
}
override fun refreshData(newData: List<PhenomenonMiddleBean>) {
super.refreshData(newData)
groupTitleList.clear()
for (item in newData) {
if (groupTitleList.size > 0) {
if (groupTitleList.last() != item.title) {
groupTitleList.add(item.title)
}
} else {
groupTitleList.add(item.title)
}
}
}
}

View File

@@ -0,0 +1,205 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.util.Log
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
/**
* 自定义装饰器(实现分组+吸顶效果)
*/
class PhenomenonRightGroupHeaderDecoration(context: Context) : ItemDecoration() {
//头部的高
private val mItemHeaderHeight: Int
private val mTextPaddingLeft: Int
//画笔,绘制头部和分割线
private val mItemHeaderPaint: Paint
private val mTextPaint: Paint
private val mLinePaint: Paint
private val mTextRect: Rect
private var lastGroupView: View? = null
init {
mItemHeaderHeight = dp2px(context, 40f)
mTextPaddingLeft = dp2px(context, 6f)
mTextRect = Rect()
mItemHeaderPaint = Paint(Paint.ANTI_ALIAS_FLAG)
mItemHeaderPaint.color = Color.GRAY
mTextPaint = Paint(Paint.ANTI_ALIAS_FLAG)
mTextPaint.textSize = 46f
mTextPaint.color = Color.WHITE
mLinePaint = Paint(Paint.ANTI_ALIAS_FLAG)
mLinePaint.color = Color.GRAY
}
/**
* 绘制Item的分割线和组头
*
* @param c
* @param parent
* @param state
*/
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
if (parent.adapter is PhenomenonRightGroupHeaderAdapter) {
val adapter = parent.adapter as PhenomenonRightGroupHeaderAdapter
val count = parent.childCount //获取可见范围内Item的总数
for (i in 0 until count) {
val view: View = parent.getChildAt(i)
val position = parent.getChildLayoutPosition(view)
val isHeader: Boolean = adapter.isItemHeader(position)
val left = parent.paddingLeft
val right = parent.width - parent.paddingRight
if (isHeader) {
c.drawRect(
left.toFloat(),
(view.top - mItemHeaderHeight).toFloat(),
right.toFloat(),
view.top.toFloat(),
mItemHeaderPaint
)
val text = adapter.getGroupName(position)
mTextPaint.getTextBounds(
text,
0,
text.length,
mTextRect
)
c.drawText(
adapter.getGroupName(position),
(left + mTextPaddingLeft).toFloat(),
(view.top - mItemHeaderHeight + mItemHeaderHeight / 2 + mTextRect.height() / 2).toFloat(),
mTextPaint
)
} else {
c.drawRect(
left.toFloat(),
(view.top - 1).toFloat(), right.toFloat(),
view.top.toFloat(), mLinePaint
)
}
}
}
}
/**
* 绘制Item的顶部布局吸顶效果
*
* @param c
* @param parent
* @param state
*/
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
if (parent.adapter is PhenomenonRightGroupHeaderAdapter) {
val adapter = parent.adapter as PhenomenonRightGroupHeaderAdapter
val position =
(parent.layoutManager as LinearLayoutManager?)!!.findFirstVisibleItemPosition()
parent.findViewHolderForAdapterPosition(position)?.let {
val view: View = it.itemView
val isHeader: Boolean = adapter.isItemHeader(position + 1)
val top = parent.paddingTop
val left = parent.paddingLeft
val right = parent.width - parent.paddingRight
if (isHeader) {
val bottom = mItemHeaderHeight.coerceAtMost(view.bottom)
c.drawRect(
left.toFloat(),
(top + view.top - mItemHeaderHeight).toFloat(),
right.toFloat(),
(top + bottom).toFloat(),
mItemHeaderPaint
)
val text = adapter.getGroupName(position)
mTextPaint.getTextBounds(
text,
0,
text.length,
mTextRect
)
c.drawText(
adapter.getGroupName(position),
(left + mTextPaddingLeft).toFloat(),
(top + mItemHeaderHeight / 2 + mTextRect.height() / 2 - (mItemHeaderHeight - bottom)).toFloat(),
mTextPaint
)
} else {
c.drawRect(
left.toFloat(),
top.toFloat(), right.toFloat(),
(top + mItemHeaderHeight).toFloat(), mItemHeaderPaint
)
val text = adapter.getGroupName(position)
mTextPaint.getTextBounds(
text,
0,
text.length,
mTextRect
)
c.drawText(
adapter.getGroupName(position), (left + mTextPaddingLeft).toFloat(),
(top + mItemHeaderHeight / 2 + mTextRect.height() / 2).toFloat(), mTextPaint
)
}
}
c.save()
}
}
/**
* 设置Item的间距
*
* @param outRect
* @param view
* @param parent
* @param state
*/
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
if (parent.adapter is PhenomenonRightGroupHeaderAdapter) {
val adapter = parent.adapter as PhenomenonRightGroupHeaderAdapter
//获取当前view在整个列表中的位置
val position = parent.getChildLayoutPosition(view)
//是不是改组的第一个
val isHeader: Boolean = adapter.isItemHeader(position)
if (isHeader) {
outRect.top = mItemHeaderHeight
if (adapter.isLastGroupTitle(position)) {
lastGroupView = view
}
} else if (position == (parent.adapter as PhenomenonRightGroupHeaderAdapter).itemCount - 1) {
//判断这条是不是最后一条
//如果是最后一个,找到他所在组的第一个
lastGroupView?.let {
if (it.top > 0) {
outRect.bottom = it.top - it.height * 2
}
}
outRect.top = 1
} else {
outRect.top = 1
}
}
}
/**
* dp转换成px
*/
private fun dp2px(context: Context, dpValue: Float): Int {
val scale: Float = context.resources.displayMetrics.density
return (dpValue * scale + 0.5f).toInt()
}
}

View File

@@ -0,0 +1,99 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.navinfo.omqs.databinding.FragmentProblemLinkBinding
import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.other.shareViewModels
class ProblemLinkFragment : BaseFragment() {
private var _binding: FragmentProblemLinkBinding? = null
private val binding get() = _binding!!
private val viewModel: EvaluationResultViewModel by shareViewModels("QsRecode")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentProblemLinkBinding.inflate(inflater, container, false)
Log.e("jingo", "linkFragment onCreateView ${hashCode()}")
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//右侧菜单
binding.linkRightRecyclerview.setHasFixedSize(true)
var rightLayoutManager = LinearLayoutManager(requireContext())
binding.linkRightRecyclerview.layoutManager = rightLayoutManager
val rightAdapter = PhenomenonRightGroupHeaderAdapter { _, bean ->
viewModel.setProblemLinkMiddleBean(bean)
}
binding.linkRightRecyclerview.adapter = rightAdapter
//右侧菜单增加组标题
binding.linkRightRecyclerview.addItemDecoration(
PhenomenonRightGroupHeaderDecoration(
requireContext()
)
)
//右侧菜单查询数据监听
viewModel.liveDataPhenomenonRightList.observe(viewLifecycleOwner) {
rightAdapter.refreshData(it)
}
val middleAdapter = PhenomenonMiddleAdapter { _, title ->
rightLayoutManager.scrollToPositionWithOffset(rightAdapter.getGroupTopIndex(title), 0)
}
binding.linkRightRecyclerview.addOnScrollListener(object :
RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val firstIndex = rightLayoutManager.findFirstVisibleItemPosition()
middleAdapter.setRightTitle(rightAdapter.data[firstIndex].title)
}
})
//中间菜单
binding.linkMiddleRecyclerview.setHasFixedSize(true)
binding.linkMiddleRecyclerview.layoutManager = LinearLayoutManager(requireContext())
binding.linkMiddleRecyclerview.adapter = middleAdapter
//中间侧菜单查询结果监听
viewModel.liveDataProblemTypeList.observe(viewLifecycleOwner) {
middleAdapter.refreshData(it)
}
binding.linkDrawer.setOnClickListener {
when (binding.group.visibility) {
View.INVISIBLE, View.GONE ->
binding.group.visibility = View.VISIBLE
else ->
binding.group.visibility = View.GONE
}
}
viewModel.getProblemLinkList()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
Log.e("jingo", "linkFragment onDestroyView ${hashCode()}")
}
override fun onResume() {
super.onResume()
}
}

View File

@@ -3,7 +3,6 @@ package com.navinfo.omqs.ui.fragment.offlinemap
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import dagger.hilt.EntryPoint
/**
* 离线地图主页面viewpage适配器

View File

@@ -6,9 +6,9 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Observer
import com.navinfo.collect.library.data.entity.OfflineMapCityBean
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.AdapterOfflineMapCityBinding
import com.navinfo.omqs.bean.OfflineMapCityBean
import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder
@@ -22,7 +22,7 @@ import javax.inject.Inject
*使用 LiveData 的 observeForever 然后在 ViewHolder 销毁前手动调用 removeObserver
*使用 LifecycleRegistry 给 ViewHolder 分发生命周期(这里使用了这个)
*/
class OfflineMapCityListAdapter @Inject constructor(
class OfflineMapCityListAdapter(
private val downloadManager: OfflineMapDownloadManager, private val context: Context
) : BaseRecyclerViewAdapter<OfflineMapCityBean>() {
@@ -126,7 +126,7 @@ class OfflineMapCityListAdapter @Inject constructor(
}
}
override fun getItemViewType(position: Int): Int {
override fun getItemViewRes(position: Int): Int {
return R.layout.adapter_offline_map_city
}
}

View File

@@ -4,14 +4,10 @@ import android.content.Context
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.navinfo.collect.library.data.entity.OfflineMapCityBean
import com.navinfo.omqs.tools.FileManager
import com.navinfo.omqs.tools.RealmCoroutineScope
import com.navinfo.omqs.db.RoomAppDatabase
import com.navinfo.omqs.bean.OfflineMapCityBean
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import io.realm.Realm
import io.realm.Sort
import io.realm.kotlin.where
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject
@@ -22,6 +18,7 @@ import javax.inject.Inject
@HiltViewModel
class OfflineMapCityListViewModel @Inject constructor(
@ApplicationContext val context: Context,
private val roomDatabase: RoomAppDatabase
) : ViewModel() {
val cityListLiveData = MutableLiveData<List<OfflineMapCityBean>>()
@@ -31,13 +28,14 @@ class OfflineMapCityListViewModel @Inject constructor(
*/
fun getCityList() {
viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
val objects = realm.where<OfflineMapCityBean>().findAll().sort("id", Sort.ASCENDING)
val list = realm.copyFromRealm(objects)
realm.close()
for (item in list) {
FileManager.checkOfflineMapFileInfo(item)
}
// val realm = Realm.getDefaultInstance()
// val objects = realm.where<OfflineMapCityBean>().findAll().sort("id", Sort.ASCENDING)
// val list = realm.copyFromRealm(objects)
// realm.close()
// for (item in list) {
// FileManager.checkOfflineMapFileInfo(item)
// }
val list = roomDatabase.getOfflineMapDao().getOfflineMapList()
cityListLiveData.postValue(list)
}
}

View File

@@ -1,23 +1,16 @@
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() {

View File

@@ -6,16 +6,33 @@ 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 androidx.fragment.app.viewModels
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.LinearLayoutManager
import com.navinfo.omqs.databinding.FragmentOfflineMapStateListBinding
import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
/**
* 离线地图管理页面
*/
@AndroidEntryPoint
class OfflineMapStateListFragment : Fragment() {
@Inject
lateinit var downloadManager: OfflineMapDownloadManager
private var _binding: FragmentOfflineMapStateListBinding? = null
private val viewModel by viewModels<OfflineMapStateListViewModel>()
private val binding get() = _binding!!
private val adapter: OfflineMapCityListAdapter by lazy {
OfflineMapCityListAdapter(
downloadManager,
requireContext()
)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@@ -27,11 +44,24 @@ class OfflineMapStateListFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val layoutManager = LinearLayoutManager(context)
//// 设置 RecyclerView 的固定大小,避免在滚动时重新计算视图大小和布局,提高性能
binding.offlineMapCityStateListRecyclerview.setHasFixedSize(true)
binding.offlineMapCityStateListRecyclerview.layoutManager = layoutManager
binding.offlineMapCityStateListRecyclerview.adapter = adapter
viewModel.cityListLiveData.observe(viewLifecycleOwner) {
adapter.refreshData(it)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onResume() {
super.onResume()
viewModel.getCityList()
}
}

View File

@@ -0,0 +1,40 @@
package com.navinfo.omqs.ui.fragment.offlinemap
import android.content.Context
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.navinfo.omqs.db.RoomAppDatabase
import com.navinfo.omqs.bean.OfflineMapCityBean
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject
/**
* 离线地图城市列表viewModel
*/
@HiltViewModel
class OfflineMapStateListViewModel @Inject constructor(
@ApplicationContext val context: Context,
private val roomDatabase: RoomAppDatabase
) : ViewModel() {
val cityListLiveData = MutableLiveData<List<OfflineMapCityBean>>()
/**
* 去获取正在下载或 已经下载的离线地图列表
*/
fun getCityList() {
viewModelScope.launch(Dispatchers.IO) {
val list = roomDatabase.getOfflineMapDao().getOfflineMapListWithOutNone()
if (cityListLiveData.value != null) {
if (cityListLiveData.value!!.size != list.size)
cityListLiveData.postValue(list)
}else{
cityListLiveData.postValue(list)
}
}
}
}

View File

@@ -1,10 +0,0 @@
package com.navinfo.omqs.ui.fragment.offlinemap
import com.navinfo.omqs.databinding.AdapterOfflineMapCityBinding
import com.navinfo.omqs.ui.other.BaseViewHolder
class OfflineMapViewHolder(dataBinding: AdapterOfflineMapCityBinding) : BaseViewHolder(dataBinding) {
init{
dataBinding.offlineMapDownloadBtn
}
}

View File

@@ -15,10 +15,12 @@ import com.github.k1rakishou.fsaf.callback.FSAFActivityCallbacks
import com.github.k1rakishou.fsaf.callback.FileChooserCallback
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.FragmentPersonalCenterBinding
import dagger.hilt.android.AndroidEntryPoint
/**
* 个人中心
*/
@AndroidEntryPoint
class PersonalCenterFragment : Fragment(), FSAFActivityCallbacks {
private var _binding: FragmentPersonalCenterBinding? = null
@@ -54,6 +56,18 @@ class PersonalCenterFragment : Fragment(), FSAFActivityCallbacks {
}
})
}
R.id.personal_center_menu_import_yuan_data->{
// 用户选中导入数据,打开文件选择器,用户选择导入的数据文件目录
fileChooser.openChooseFileDialog(object: FileChooserCallback() {
override fun onCancel(reason: String) {
}
override fun onResult(uri: Uri) {
viewModel.importScProblemData(uri)
}
})
}
}
true
}

View File

@@ -1,16 +1,89 @@
package com.navinfo.omqs.ui.fragment.personalcenter
import android.net.Uri
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.UriUtils
import com.navinfo.omqs.bean.ScProblemTypeBean
import com.navinfo.omqs.bean.ScRootCauseAnalysisBean
import com.navinfo.omqs.db.RoomAppDatabase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.apache.poi.ss.usermodel.Cell
import org.apache.poi.ss.usermodel.Row
import org.apache.poi.ss.usermodel.Sheet
import org.apache.poi.ss.usermodel.WorkbookFactory
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
import javax.inject.Inject
class PersonalCenterViewModel: ViewModel() {
@HiltViewModel
class PersonalCenterViewModel @Inject constructor(
private val roomAppDatabase: RoomAppDatabase
) : ViewModel() {
fun importOmdbData(omdbFile: File) {
// 检查File是否为sqlite数据库
if (omdbFile == null || omdbFile.exists()) {
if (omdbFile == null || !omdbFile.exists()) {
throw Exception("文件不存在")
}
if (!omdbFile.name.endsWith(".sqlite") and !omdbFile.name.endsWith("db")) {
throw Exception("文件不存在")
}
}
fun importScProblemData(uri: Uri) {
viewModelScope.launch(Dispatchers.IO) {
try {
val file = UriUtils.uri2File(uri)
val inputStream: InputStream =
FileInputStream(file) //getAssets().open("sample.xlsx")
val workbook = WorkbookFactory.create(inputStream)
//获取所有sheet
val sheet1 = workbook.getSheet("SC_PROBLEM_TYPE")
sheet1?.let {
val rowCount: Int = it.physicalNumberOfRows // 获取行数
val list = mutableListOf<ScProblemTypeBean>()
for (i in 1 until rowCount) {
val row: Row = it.getRow(i) // 获取行
val cellCount: Int = row.physicalNumberOfCells // 获取列数
if (cellCount == 3) {
val bean = ScProblemTypeBean()
bean.classType = row.getCell(0).stringCellValue
bean.problemType = row.getCell(1).stringCellValue
bean.phenomenon = row.getCell(2).stringCellValue
list.add(bean)
Log.e("jingo", bean.toString())
}
}
roomAppDatabase.getScProblemTypeDao().insertOrUpdateList(list)
}
val sheet2 = workbook.getSheet("SC_ROOT_CAUSE_ANALYSIS")
sheet2?.let {
val rowCount: Int = it.physicalNumberOfRows // 获取行数
val list = mutableListOf<ScRootCauseAnalysisBean>()
for (i in 1 until rowCount) {
val row: Row = it.getRow(i) // 获取行
val cellCount: Int = row.physicalNumberOfCells // 获取列数
if (cellCount == 2) {
val bean = ScRootCauseAnalysisBean()
bean.problemLink = row.getCell(0).stringCellValue
bean.problemCause = row.getCell(1).stringCellValue
list.add(bean)
Log.e("jingo", bean.toString())
}
}
roomAppDatabase.getScRootCauseAnalysisDao().insertOrUpdateList(list)
}
workbook.close()
} catch (e: IOException) {
e.printStackTrace()
Log.e("jingo", e.toString())
}
}
}
}

View File

@@ -0,0 +1,5 @@
package com.navinfo.omqs.ui.other
interface AdapterItemClickListener {
fun onItemClick(position: Int)
}

View File

@@ -5,6 +5,7 @@ import android.view.View.OnClickListener
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import com.navinfo.omqs.R
/**
* RecyclerView 适配器基础类
@@ -26,32 +27,38 @@ abstract class BaseRecyclerViewAdapter<T>(var data: List<T> = listOf()) :
// )
// }
abstract fun getItemViewRes(position: Int): Int
override fun getItemViewType(position: Int): Int {
return getItemViewRes(position)
}
override fun getItemCount(): Int {
return data.size
}
fun refreshData(newData: List<T>) {
this.data = newData
this.notifyDataSetChanged()
}
override fun onViewAttachedToWindow(holder: BaseViewHolder) {
super.onViewAttachedToWindow(holder)
holder.onStart()
}
override fun onViewDetachedFromWindow(holder: BaseViewHolder) {
super.onViewDetachedFromWindow(holder)
holder.apply {
onStop()
}
}
//
// override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
// this.recyclerView = recyclerView
// super.onAttachedToRecyclerView(recyclerView)
// this.recyclerView = recyclerView
// override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
open fun refreshData(newData: List<T>) {
this.data = newData
this.notifyDataSetChanged()
}
// }
//
// override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {

View File

@@ -0,0 +1,107 @@
package com.navinfo.omqs.ui.other
import androidx.annotation.MainThread
import androidx.fragment.app.Fragment
import androidx.fragment.app.createViewModelLazy
import androidx.lifecycle.*
import androidx.lifecycle.viewmodel.CreationExtras
/**
* 用来共享的viewModel
*/
val vMStores = HashMap<String, ViewModelStoreOwner>()
@MainThread
inline fun <reified VM : ViewModel> Fragment.shareViewModels(
scopeName: String,
noinline ownerProducer: () -> ViewModelStoreOwner = { this },
noinline factoryProducer: (() -> ViewModelProvider.Factory)? = null
): Lazy<VM> {
val owner by lazy(LazyThreadSafetyMode.NONE) { ownerProducer() }
val store: ViewModelStoreOwner
if (vMStores.keys.contains(scopeName)) {
store = vMStores[scopeName]!!
} else {
vMStores[scopeName] = owner
store = owner
this.let { fragment ->
fragment.lifecycle.addObserver(object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event == Lifecycle.Event.ON_DESTROY) {
fragment.lifecycle.removeObserver(this)
store.viewModelStore.clear()
vMStores.remove(scopeName)
}
}
})
}
}
// store.register(this)
return createViewModelLazy(
VM::class,
{ store.viewModelStore },
{
(store as? HasDefaultViewModelProviderFactory)?.defaultViewModelCreationExtras
?: CreationExtras.Empty
},
factoryProducer ?: {
(store as? HasDefaultViewModelProviderFactory)?.defaultViewModelProviderFactory
?: defaultViewModelProviderFactory
})
}
//
//@MainThread
//inline fun <reified VM : ViewModel> LifecycleOwner.shareViewModels(
// scopeName: String,
// factory: ViewModelProvider.Factory? = null
//): Lazy<VM> {
// val store: VMStore
// if (vMStores.keys.contains(scopeName)) {
// store = vMStores[scopeName]!!
// } else {
// store = VMStore()
// vMStores[scopeName] = store
// }
// store.register(this)
// return ViewModelLazy(VM::class,
// { store.viewModelStore },
// { factory ?: MyViewModelFactory() })
//}
class MyViewModelFactory(
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return modelClass.getConstructor().newInstance()
}
}
class VMStore(val owner: ViewModelStoreOwner) {
// private val bindTargets = ArrayList<LifecycleOwner>()
// fun register(host: LifecycleOwner) {
// if (!bindTargets.contains(host)) {
// bindTargets.add(host)
// host.lifecycle.addObserver(object : LifecycleEventObserver {
// override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
// if (event == Lifecycle.Event.ON_DESTROY) {
// host.lifecycle.removeObserver(this)
// bindTargets.remove(host)
// if (bindTargets.isEmpty()) {//如果当前商店没有关联对象,则释放资源
// vMStores.entries.find { it.value == this@VMStore }?.also {
// owner.viewModelStore.clear()
// vMStores.remove(it.key)
// }
// }
// }
// }
// })
// }
// }
}