Conflicts:
	app/src/main/java/com/navinfo/omqs/Constant.kt
	app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListAdapter.kt
This commit is contained in:
qiji4215 2023-04-24 16:26:40 +08:00
commit 123583652c
27 changed files with 794 additions and 581 deletions

View File

@ -0,0 +1,35 @@
{
"tables" : [
{
"table": "OMDB_RD_LINK",
"code": 2001,
"name": "道路线"
},
{
"table": "OMDB_RD_LINK_KIND",
"code": 2008,
"name": "道路种别"
},
{
"table": "OMDB_RD_LINK_DIRECT",
"code": 2001,
"name": "道路方向"
},
{
"table": "OMDB_SPEEDLIMIT_COND",
"code": 2001,
"name": "条件点限速"
},
{
"table": "OMDB_SPEEDLIMIT_VAR",
"code": 2001,
"name": "可变点限速"
},
{
"table": "OMDB_SPEEDLIMIT",
"code": 2001,
"name": "常规点限速"
}
]
}

View File

@ -1,11 +1,8 @@
package com.navinfo.omqs
import androidx.core.util.rangeTo
import io.realm.Realm
import java.util.*
class Constant {
companion object {
/**
* sd卡根目录
@ -35,11 +32,21 @@ class Constant {
*/
lateinit var USER_DATA_PATH: String
/**
* 当前用户ID
*/
lateinit var CURRENT_USER_ID: String
/**
* 离线地图目录
*/
lateinit var OFFLINE_MAP_PATH: String
/**
* 下载目录
*/
lateinit var DOWNLOAD_PATH: String
/**
* 服务器地址
*/
@ -74,6 +81,7 @@ class Constant {
//选择拍照或者录像
const val SELECT_TAKEPHOTO_OR_RECORD = "select_takephoto_or_record"
const val OMDB_CONFIG = "omdb.config"
}
}

View File

@ -11,11 +11,13 @@ import com.blankj.utilcode.util.ZipUtils
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.navinfo.collect.library.data.entity.RenderEntity
import com.navinfo.omqs.Constant
import com.navinfo.omqs.bean.ImportConfig
import com.navinfo.omqs.hilt.ImportOMDBHiltFactory
import com.navinfo.omqs.hilt.OMDBDataBaseHiltFactory
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.realm.Realm
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
@ -28,13 +30,13 @@ import kotlin.streams.toList
/**
* 导入omdb数据的帮助类
* */
class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val context: Context,@Assisted("omdbFile") val omdbFile: File,@Assisted("configFile") val configFile: File) {
class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val context: Context,@Assisted("omdbFile") val omdbFile: File) {
@Inject
lateinit var omdbHiltFactory: OMDBDataBaseHiltFactory
@Inject
lateinit var gson: Gson
private val database by lazy { omdbHiltFactory.obtainOmdbDataBaseHelper(context, omdbFile.absolutePath, 1).writableDatabase }
private val configFile: File = File("${Constant.DATA_PATH}/${Constant.CURRENT_USER_ID}", Constant.OMDB_CONFIG)
/**
* 读取config的配置文件
@ -99,10 +101,10 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
* @param omdbZipFile omdb数据抽取生成的Zip文件
* @param configFile 对应的配置文件
* */
suspend fun importOmdbZipFile(omdbZipFile: File): Flow<List<Map<String, Any>>> = withContext(Dispatchers.IO) {
suspend fun importOmdbZipFile(omdbZipFile: File): Flow<String> = withContext(Dispatchers.IO) {
val importConfig = openConfigFile()
val unZipFolder = File(omdbZipFile.parentFile, "result")
flow<List<Map<String, Any>>> {
flow<String> {
if (unZipFolder.exists()) {
unZipFolder.deleteRecursively()
}
@ -110,26 +112,45 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
// 开始解压zip文件
val unZipFiles = ZipUtils.unzipFile(omdbZipFile, unZipFolder)
// 遍历解压后的文件,读取该数据返回
for (txtFile in unZipFiles) {
val listResult: MutableList<Map<String, Any>> = mutableListOf()
// 根据文件名称获取对应的配置
val currentConfig=importConfig.tables.find {
txtFile.name.substring(0, txtFile.name.lastIndexOf("."))==it.table
for ((index, currentConfig) in importConfig.tables.withIndex()) {
val txtFile = unZipFiles.find {
it.name == currentConfig.table
}
val list = FileIOUtils.readFile2List(txtFile, "UTF-8")
// 将list数据转换为map
for (line in list) {
val map = gson.fromJson<Map<String, Any>>(line, object : TypeToken<MutableMap<String, Any>>() {}.type)
.toMutableMap()
currentConfig?.let {
map["QItable"] = currentConfig.table
map["QIname"] = currentConfig.name
map["QIcode"] = currentConfig.code
listResult.add(map)
val listResult: MutableList<Map<String, Any>> = mutableListOf()
currentConfig?.let {
val list = FileIOUtils.readFile2List(txtFile, "UTF-8")
if (list!=null) {
// 将list数据转换为map
for (line in list) {
val map = gson.fromJson<Map<String, Any>>(line, object : TypeToken<MutableMap<String, Any>>() {}.type)
.toMutableMap()
map["QItable"] = currentConfig.table
map["QIname"] = currentConfig.name
map["QIcode"] = currentConfig.code
listResult.add(map)
}
}
}
// 将listResult数据插入到Realm数据库中
Realm.getDefaultInstance().beginTransaction()
for (map in listResult) { // 每一个map就是Realm的一条数据
// 先查询这个mesh下有没有数据如果有则跳过即可
// val meshEntity = Realm.getDefaultInstance().where(RenderEntity::class.java).equalTo("properties['mesh']", map["mesh"].toString()).findFirst()
val renderEntity = RenderEntity()
renderEntity.code = map["QIcode"].toString().toInt()
renderEntity.name = map["QIname"].toString()
renderEntity.table = map["QItable"].toString()
// 其他数据插入到Properties中
renderEntity.geometry = map["geometry"].toString()
for (entry in map) {
renderEntity.properties[entry.key] = entry.value.toString()
}
Realm.getDefaultInstance().insert(renderEntity)
}
Realm.getDefaultInstance().commitTransaction()
// 1个文件发送一次flow流
emit(listResult)
emit("${index+1}/${importConfig.tables.size}")
}
}
}

View File

@ -8,5 +8,5 @@ import java.io.File
@AssistedFactory
interface ImportOMDBHiltFactory {
fun obtainImportOMDBHelper(@Assisted("context")context: Context, @Assisted("omdbFile") omdbFile: File, @Assisted("configFile") dbVersion: File): ImportOMDBHelper
fun obtainImportOMDBHelper(@Assisted("context")context: Context, @Assisted("omdbFile") omdbFile: File): ImportOMDBHelper
}

View File

@ -104,13 +104,13 @@ class TaskDownloadScope(
var randomAccessFile: RandomAccessFile? = null
try {
//创建离线地图 下载文件夹,.map文件夹的下一级
val fileDir = File("${Constant.OFFLINE_MAP_PATH}download")
val fileDir = File("${Constant.DOWNLOAD_PATH}download")
if (!fileDir.exists()) {
fileDir.mkdirs()
}
val fileTemp =
File("${Constant.OFFLINE_MAP_PATH}download/${taskBean.id}_${taskBean.dataVersion}")
File("${Constant.DOWNLOAD_PATH}${taskBean.id}_${taskBean.dataVersion}")
val startPosition = taskBean.currentSize
//验证断点有效性
if (startPosition < 0) throw IOException("jingo Start position less than zero")
@ -119,8 +119,13 @@ class TaskDownloadScope(
url = taskBean.getDownLoadUrl()
)
val responseBody = response.body()
change(FileDownloadStatus.LOADING)
responseBody ?: throw IOException("jingo ResponseBody is null")
if (startPosition == 0L) {
taskBean.fileSize = responseBody.contentLength()
}
//写入文件
randomAccessFile = RandomAccessFile(fileTemp, "rwd")
randomAccessFile.seek(startPosition)
@ -144,7 +149,7 @@ class TaskDownloadScope(
Log.e("jingo", "文件下载完成 ${taskBean.currentSize} == ${taskBean.fileSize}")
if (taskBean.currentSize == taskBean.fileSize) {
val res =
fileTemp.renameTo(File("${Constant.OFFLINE_MAP_PATH}${taskBean.evaluationTaskName}.zip"))
fileTemp.renameTo(File("${Constant.DOWNLOAD_PATH}${taskBean.evaluationTaskName}.zip"))
Log.e("jingo", "文件下载完成 修改文件 $res")
change(FileDownloadStatus.DONE)
} else {

View File

@ -3,6 +3,7 @@ package com.navinfo.omqs.tools
import android.content.Context
import com.navinfo.omqs.Constant
import com.navinfo.omqs.bean.OfflineMapCityBean
import com.navinfo.omqs.bean.TaskBean
import java.io.File
class FileManager {
@ -20,13 +21,14 @@ class FileManager {
}
//初始化数据文件夹
fun initRootDir(context:Context){
fun initRootDir(context: Context) {
// 在SD卡创建项目目录
val sdCardPath = context.getExternalFilesDir(null)
sdCardPath?.let {
Constant.ROOT_PATH = sdCardPath.absolutePath
Constant.MAP_PATH = Constant.ROOT_PATH + "/map/"
Constant.OFFLINE_MAP_PATH = Constant.MAP_PATH + "offline/"
Constant.DOWNLOAD_PATH = Constant.ROOT_PATH + "/download/"
val file = File(Constant.MAP_PATH)
if (!file.exists()) {
file.mkdirs()
@ -37,7 +39,7 @@ class FileManager {
with(File(Constant.DATA_PATH)) {
if (!this.exists()) this.mkdirs()
}
}else{
} else {
Constant.DATA_PATH = Constant.ROOT_PATH + "/data/"
}
}
@ -102,5 +104,65 @@ class FileManager {
}
}
}
/**
* 检查离线地图文件
*/
suspend fun checkOMDBFileInfo(taskBean: TaskBean) {
//访问离线地图文件夹
val fileDir = File("${Constant.DOWNLOAD_PATH}")
//如果连本地文件夹还没有,就不用修改任何数据了
if (!fileDir.exists()) {
return
}
//访问离线地图临时下载文件夹
val fileTempDir = File(Constant.DOWNLOAD_PATH)
//是否有一份.map文件了
var mapFile: File? = null
//文件夹里文件挨个访问
for (item in fileDir.listFiles()) {
//先找到对应的省市文件例如540000_西藏自治区_20230401195018.map",以id开头
if (item.isFile && item.name.startsWith("${taskBean.id}_")) {
//如果本地文件与从网络获取到版本号一致,表示这个文件已经下载完毕,不用处理了
if (item.name == "${taskBean.id}_${taskBean.dataVersion}") {
taskBean.status = FileDownloadStatus.DONE
return
}
//文件存在,版本号不对应,留给下面流程处理
mapFile = item
break
}
}
//临时下载文件夹
if (fileTempDir.exists()) {
for (item in fileTempDir.listFiles()) {
//先找到对应的省市文件例如540000_20230401195018",以id开头
if (item.isFile && item.name.startsWith("${taskBean.id}_")) {
//如果本地文件与从网络获取到版本号一致,表示这个文件已经在下载列表中
if (item.name == "${taskBean.id}_${taskBean.dataVersion}") {
//如果这个临时文件的大小和下载大小是一致的,说明已经下载完了,但是在下载环节没有更名移动成功,需要重命名和移动文件夹
if (item.length() == taskBean.fileSize) {
//移动更名文件后删除旧数据,修改状态
if (item.renameTo(File("${Constant.OFFLINE_MAP_PATH}${taskBean.evaluationTaskName}.zip"))) {
//删除旧版本数据
mapFile?.delete()
taskBean.status = FileDownloadStatus.DONE
return
}
} else { // 临时文件大小和目标不一致,说明下载了一半
taskBean.status = FileDownloadStatus.PAUSE
taskBean.currentSize = item.length()
return
}
} else { //虽然省市id开头一致但是版本号不一致说明之前版本下载了一部分现在要更新了原来下载的文件直接删除
taskBean.status = FileDownloadStatus.UPDATE
item.delete()
return
}
break
}
}
}
}
}
}

View File

@ -7,6 +7,7 @@ import android.widget.Toast
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.ResourceUtils
import com.navinfo.omqs.Constant
import com.navinfo.omqs.bean.LoginUserBean
import com.navinfo.omqs.db.RoomAppDatabase
@ -158,19 +159,26 @@ class LoginViewModel @Inject constructor(
Constant.VERSION_ID = userId
Constant.USER_DATA_PATH = Constant.DATA_PATH + Constant.USER_ID + "/" + Constant.VERSION_ID
// 在SD卡创建用户目录解压资源等
val userFolder = File("${Constant.DATA_PATH}/${userId}")
Constant.CURRENT_USER_ID = userId
// 初始化Realm
Realm.init(context.applicationContext)
val password = "encryp".encodeToByteArray().copyInto(ByteArray(64))
// 656e6372797000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Log.d("OMQSApplication", "密码是: ${byteArrayToHexString(password)}")
val config = RealmConfiguration.Builder()
.directory(File("${Constant.DATA_PATH}/${userId}"))
.directory(userFolder)
.name("OMQS.realm")
.encryptionKey(password)
// .modules(Realm.getDefaultModule(), MyRealmModule())
.schemaVersion(1)
.build()
Realm.setDefaultConfiguration(config)
// 拷贝配置文件到用户目录下
val omdbConfigFile = File(userFolder.absolutePath, Constant.OMDB_CONFIG);
if (!omdbConfigFile.exists()) {
ResourceUtils.copyFileFromAssets(Constant.OMDB_CONFIG, omdbConfigFile.absolutePath)
}
}
/**

View File

@ -38,7 +38,7 @@ class MainViewModel @Inject constructor(
private var niLocationList: MutableList<NiLocation> = ArrayList<NiLocation>()
init {
mapController.layerManagerHandler.setOnQsRecordItemClickListener(object :
mapController.markerHandle.setOnQsRecordItemClickListener(object :
OnQsRecordItemClickListener {
override fun onQsRecordList(list: MutableList<String>) {
liveDataQsRecordIdList.value = list

View File

@ -212,7 +212,7 @@ class EvaluationResultViewModel @Inject constructor(
it.copyToRealmOrUpdate(liveDataQsRecordBean.value)
}
// realm.close()
mapController.layerManagerHandler.addOrUpdateQsRecordMark(liveDataQsRecordBean.value!!)
mapController.markerHandle.addOrUpdateQsRecordMark(liveDataQsRecordBean.value!!)
liveDataFinish.postValue(true)
}
}
@ -228,7 +228,7 @@ class EvaluationResultViewModel @Inject constructor(
objects?.deleteFromRealm()
}
// realm.close()
mapController.layerManagerHandler.removeQsRecordMark(liveDataQsRecordBean.value!!)
mapController.markerHandle.removeQsRecordMark(liveDataQsRecordBean.value!!)
liveDataFinish.postValue(true)
}
}

View File

@ -77,15 +77,14 @@ class PersonalCenterFragment : BaseFragment(), FSAFActivityCallbacks {
val file = UriUtils.uri2File(uri)
// 开始导入数据
// 656e6372797000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
val job = CoroutineUtils.launchWithLoading(
CoroutineUtils.launchWithLoading(
requireContext(),
loadingMessage = "生成数据..."
) {
val importOMDBHelper: ImportOMDBHelper =
importOMDBHiltFactory.obtainImportOMDBHelper(
requireContext(),
file,
File(file.parentFile, "config.json")
file
)
viewModel.obtainOMDBZipData(importOMDBHelper)
}
@ -99,19 +98,19 @@ class PersonalCenterFragment : BaseFragment(), FSAFActivityCallbacks {
override fun onResult(uri: Uri) {
val file = UriUtils.uri2File(uri)
// 开始导入数据
CoroutineUtils.launchWithLoading(
requireContext(),
loadingMessage = "导入数据..."
) {
val importOMDBHelper: ImportOMDBHelper =
importOMDBHiltFactory.obtainImportOMDBHelper(
requireContext(),
file,
File(file.parentFile, "config.json")
)
val importOMDBHelper: ImportOMDBHelper =
importOMDBHiltFactory.obtainImportOMDBHelper(
requireContext(),
file
)
viewModel.importOMDBData(importOMDBHelper)
}
// // 开始导入数据
// CoroutineUtils.launchWithLoading(
// requireContext(),
// loadingMessage = "导入数据..."
// ) {
//
// }
}
})
}

View File

@ -136,39 +136,15 @@ class PersonalCenterViewModel @Inject constructor(
/**
* 导入OMDB数据
* */
suspend fun importOMDBData(importOMDBHelper: ImportOMDBHelper) {
Log.d("OMQSApplication", "开始导入数据")
// Realm.getDefaultInstance().beginTransaction()
importOMDBHelper.importOmdbZipFile(importOMDBHelper.omdbFile).collect {
Realm.getDefaultInstance().beginTransaction()
for (map in it) { // 每一个map就是Realm的一条数据
val renderEntity = RenderEntity()
renderEntity.code = map["QIcode"].toString().toInt()
renderEntity.name = map["QIname"].toString()
renderEntity.table = map["QItable"].toString()
// 其他数据插入到Properties中
renderEntity.geometry = map["GEOMETRY"].toString()
for (entry in map) {
renderEntity.properties[entry.key] = entry.value.toString()
}
Realm.getDefaultInstance().insert(renderEntity)
fun importOMDBData(importOMDBHelper: ImportOMDBHelper) {
viewModelScope.launch(Dispatchers.IO) {
Log.d("OMQSApplication", "开始导入数据")
importOMDBHelper.importOmdbZipFile(importOMDBHelper.omdbFile).collect {
Log.d("importOMDBData", it)
}
Realm.getDefaultInstance().commitTransaction()
Log.d("OMQSApplication", "导入数据完成")
}
// Realm.getDefaultInstance().commitTransaction()
// val gson = Gson()
// // 数据导入结束后开始生成渲染表所需的json文件并生成压缩包
// for (table in importOMDBHelper.openConfigFile().tables/*listOf<String>("HAD_LINK")*/) {
// val omdbList = Realm.getDefaultInstance().where(OMDBEntity::class.java).equalTo("table", table.table).findAll()
// val outputFile = File(importOMDBHelper.omdbFile, "${table.table}.txt")
// // 将读取到的数据转换为json数据文件
// for (omdb in omdbList) {
// FileIOUtils.writeFileFromString(outputFile, gson.toJson(omdb))
// }
// }
Log.d("OMQSApplication", "导入数据完成")
}
fun importScProblemData(uri: Uri) {

View File

@ -10,7 +10,7 @@ import com.navinfo.omqs.R
import com.navinfo.omqs.bean.TaskBean
import com.navinfo.omqs.databinding.AdapterTaskListBinding
import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
import com.navinfo.omqs.tools.FileManager
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder
@ -23,7 +23,7 @@ import com.navinfo.omqs.ui.other.BaseViewHolder
*使用 LifecycleRegistry ViewHolder 分发生命周期(这里使用了这个)
*/
class TaskListAdapter(
private val downloadManager: TaskDownloadManager, private val context: Context
private val downloadManager: TaskDownloadManager
) : BaseRecyclerViewAdapter<TaskBean>() {
@ -31,11 +31,11 @@ class TaskListAdapter(
if (it.tag != null) {
val taskBean = data[it.tag as Int]
when (taskBean.status) {
FileManager.Companion.FileDownloadStatus.NONE, FileManager.Companion.FileDownloadStatus.UPDATE, FileManager.Companion.FileDownloadStatus.PAUSE, FileManager.Companion.FileDownloadStatus.ERROR -> {
FileDownloadStatus.NONE, FileDownloadStatus.UPDATE, FileDownloadStatus.PAUSE, FileDownloadStatus.ERROR -> {
Log.e("jingo", "开始下载 ${taskBean.status}")
downloadManager.start(taskBean.id)
}
FileManager.Companion.FileDownloadStatus.LOADING, FileManager.Companion.FileDownloadStatus.WAITING -> {
FileDownloadStatus.LOADING, FileDownloadStatus.WAITING -> {
Log.e("jingo", "暂停 ${taskBean.status}")
downloadManager.pause(taskBean.id)
}
@ -70,6 +70,8 @@ class TaskListAdapter(
binding.taskDownloadBtn.tag = position
binding.taskDownloadBtn.setOnClickListener(downloadBtnClick)
binding.taskName.text = taskBean.evaluationTaskName
binding.taskCityName.text = taskBean.cityName
binding.taskDataVersion.text = "版本号:${taskBean.dataVersion}"
// binding.offlineMapCitySize.text = cityBean.getFileSizeText()
}
@ -82,41 +84,43 @@ class TaskListAdapter(
}
private fun changeViews(binding: AdapterTaskListBinding, cityBean: TaskBean) {
binding.taskProgress.progress =
(cityBean.currentSize * 100 / cityBean.fileSize).toInt()
when (cityBean.status) {
FileManager.Companion.FileDownloadStatus.NONE -> {
private fun changeViews(binding: AdapterTaskListBinding, taskBean: TaskBean) {
if (taskBean.fileSize > 0L) {
binding.taskProgress.progress =
(taskBean.currentSize * 100 / taskBean.fileSize).toInt()
}
when (taskBean.status) {
FileDownloadStatus.NONE -> {
if (binding.taskProgress.visibility == View.VISIBLE) binding.taskProgress.visibility =
View.INVISIBLE
binding.taskDownloadBtn.text = "下载"
}
FileManager.Companion.FileDownloadStatus.WAITING -> {
FileDownloadStatus.WAITING -> {
if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
View.VISIBLE
binding.taskDownloadBtn.text = "等待中"
}
FileManager.Companion.FileDownloadStatus.LOADING -> {
FileDownloadStatus.LOADING -> {
if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
View.VISIBLE
binding.taskDownloadBtn.text = "暂停"
}
FileManager.Companion.FileDownloadStatus.PAUSE -> {
FileDownloadStatus.PAUSE -> {
if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
View.VISIBLE
binding.taskDownloadBtn.text = "继续"
}
FileManager.Companion.FileDownloadStatus.ERROR -> {
FileDownloadStatus.ERROR -> {
if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
View.VISIBLE
binding.taskDownloadBtn.text = "重试"
}
FileManager.Companion.FileDownloadStatus.DONE -> {
FileDownloadStatus.DONE -> {
if (binding.taskProgress.visibility == View.VISIBLE) binding.taskProgress.visibility =
View.INVISIBLE
binding.taskDownloadBtn.text = "已完成"
}
FileManager.Companion.FileDownloadStatus.UPDATE -> {
FileDownloadStatus.UPDATE -> {
if (binding.taskProgress.visibility == View.VISIBLE) binding.taskProgress.visibility =
View.INVISIBLE
binding.taskDownloadBtn.text = "更新"

View File

@ -5,6 +5,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.navinfo.omqs.databinding.FragmentTaskListBinding
import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
@ -22,7 +23,6 @@ class TaskListFragment : BaseFragment(){
private val adapter: TaskListAdapter by lazy {
TaskListAdapter(
downloadManager,
requireContext()
)
}
@ -46,6 +46,9 @@ class TaskListFragment : BaseFragment(){
adapter.refreshData(it)
}
viewModel.getTaskList(requireContext())
binding.taskBack.setOnClickListener{
findNavController().navigateUp()
}
}
override fun onDestroyView() {

View File

@ -52,8 +52,11 @@ class TaskListViewModel @Inject constructor(
else -> {}
}
val objects = realm.where(TaskBean::class.java).findAll()
liveDataTaskList.postValue(realm.copyFromRealm(objects))
// realm.close()
val taskList = realm.copyFromRealm(objects)
for(item in taskList){
FileManager.checkOMDBFileInfo(item)
}
liveDataTaskList.postValue(taskList)
}
}

View File

@ -0,0 +1,6 @@
<vector android:height="24dp" android:tint="#1717E0"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
<path android:fillColor="@android:color/white" android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
</vector>

View File

@ -1,4 +1,4 @@
<vector android:height="24dp" android:tint="#18FD00"
<vector android:height="24dp" android:tint="#1717E0"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,15c1.66,0 2.99,-1.34 2.99,-3L15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6v6c0,1.66 1.34,3 3,3zM17.3,12c0,3 -2.54,5.1 -5.3,5.1S6.7,15 6.7,12L5,12c0,3.42 2.72,6.23 6,6.72L11,22h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z"/>

View File

@ -6,26 +6,48 @@
android:layout_height="wrap_content"
android:background="@color/ivory"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:paddingRight="10dp"
tools:context="com.navinfo.omqs.ui.fragment.tasklist.TaskListAdapter">
<TextView
android:id="@+id/task_name"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="省市名称"
android:layout_toLeftOf="@id/task_download_btn"
android:text="任务名称"
android:textColor="@color/white"
android:textSize="@dimen/default_font_size" />
<TextView
android:id="@+id/task_city_name"
style="@style/map_size_font_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/task_name"
android:layout_marginTop="5dp"
android:text="省市名称"
android:textSize="@dimen/card_title_font_3size" />
<TextView
android:id="@+id/task_data_version"
style="@style/map_size_font_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/task_city_name"
android:layout_alignTop="@id/task_city_name"
android:layout_marginLeft="5dp"
android:text="版本号"
android:textSize="@dimen/card_title_font_3size" />
<TextView
android:id="@+id/task_size"
style="@style/map_size_font_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/task_name"
android:drawableLeft="@mipmap/point_blue"
android:layout_below="@id/task_city_name"
android:layout_marginTop="5dp"
android:drawableLeft="@mipmap/point_blue"
android:text="文件大小"
android:textSize="@dimen/card_title_font_3size" />
@ -34,9 +56,9 @@
android:id="@+id/task_download_btn"
style="@style/map_download_style_btn"
android:layout_width="60dp"
android:layout_alignTop="@id/task_name"
android:layout_alignBottom="@id/task_size"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="center"
android:shadowColor="@android:color/transparent"
android:text="下载"
android:textColor="@color/btn_blue_solid"
@ -60,8 +82,8 @@
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="16dp"
android:layout_below="@id/task_download_btn"
android:progressDrawable="@drawable/progress_bg"
android:layout_below="@id/task_size"
android:paddingTop="10dp"
android:progressDrawable="@drawable/progress_bg"
android:visibility="invisible" />
</RelativeLayout>

View File

@ -4,10 +4,11 @@
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="fragment"
type="com.navinfo.omqs.ui.fragment.evaluationresult.EvaluationResultFragment"
/>
type="com.navinfo.omqs.ui.fragment.evaluationresult.EvaluationResultFragment" />
<variable
name="viewModel"
type="com.navinfo.omqs.ui.fragment.evaluationresult.EvaluationResultViewModel" />
@ -42,7 +43,7 @@
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:padding="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toTopOf="@id/evaluation_camera"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/evaluation_appbar_layout">
@ -59,77 +60,98 @@
<TextView
android:id="@+id/evaluation_class_type"
android:text="@{viewModel.liveDataQsRecordBean.classType}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@drawable/fm_card_map_down_status_bg"
android:onClick="@{fragment.onClick}"
android:background="@drawable/fm_card_map_down_status_bg" />
android:text="@{viewModel.liveDataQsRecordBean.classType}" />
<TextView
android:id="@+id/evaluation_problem_type"
android:text="@{viewModel.liveDataQsRecordBean.problemType}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@drawable/fm_card_map_down_status_bg"
android:onClick="@{fragment.onClick}"
android:background="@drawable/fm_card_map_down_status_bg" />
android:text="@{viewModel.liveDataQsRecordBean.problemType}" />
<TextView
android:id="@+id/evaluation_phenomenon"
android:text="@{viewModel.liveDataQsRecordBean.phenomenon}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@drawable/fm_card_map_down_status_bg"
android:onClick="@{fragment.onClick}"
android:background="@drawable/fm_card_map_down_status_bg" />
android:text="@{viewModel.liveDataQsRecordBean.phenomenon}" />
<TextView
android:id="@+id/evaluation_link"
android:text="@{viewModel.liveDataQsRecordBean.problemLink}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@drawable/fm_card_map_down_status_bg"
android:onClick="@{fragment.onClick}"
android:background="@drawable/fm_card_map_down_status_bg" />
android:text="@{viewModel.liveDataQsRecordBean.problemLink}" />
<TextView
android:id="@+id/evaluation_cause"
android:text="@{viewModel.liveDataQsRecordBean.cause}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@drawable/fm_card_map_down_status_bg"
android:onClick="@{fragment.onClick}"
android:background="@drawable/fm_card_map_down_status_bg" />
android:text="@{viewModel.liveDataQsRecordBean.cause}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="备注信息" />
<com.navinfo.omqs.ui.widget.MyEditeText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入备注信息"
android:gravity="start"
android:maxLines="3"
android:lines="3"
android:text="@={viewModel.liveDataQsRecordBean.description}"
android:inputType="textMultiLine"
android:background="@drawable/fm_card_map_down_status_bg"
/>
<!-- <com.google.android.material.tabs.TabLayout-->
<!-- android:id="@+id/evaluation_class_tab_layout"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginTop="5dp" />-->
android:gravity="start"
android:hint="请输入备注信息"
android:inputType="textMultiLine"
android:lines="3"
android:maxLines="3"
android:text="@={viewModel.liveDataQsRecordBean.description}" />
<!-- <androidx.viewpager2.widget.ViewPager2-->
<!-- android:id="@+id/evaluation_viewpager"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent"-->
<!-- android:layout_marginTop="5dp" />-->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_margin="5dp"
android:background="@color/gray_121" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/evaluation_voice_recyclerview"
android:layout_width="match_parent"
android:layout_height="80dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<ImageView
android:id="@+id/evaluation_camera"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="5dp"
android:src="@drawable/baseline_camera_alt_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/evaluation_voice" />
<ImageView
android:id="@+id/evaluation_voice"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="5dp"
android:src="@drawable/baseline_keyboard_voice_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/evaluation_camera"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -7,6 +7,28 @@
android:background="@color/white"
tools:context=".ui.fragment.tasklist.TaskListFragment">
<TextView
android:id="@+id/task_title"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="任务列表"
android:gravity="center"
android:textSize="18sp"
android:textColor="@color/white"
android:background="@color/default_blue"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/task_back"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:src="@drawable/btn_back_xml"
android:paddingLeft="15dp"
android:paddingRight="10dp"
app:layout_constraintLeft_toLeftOf="@id/task_title"
app:layout_constraintTop_toTopOf="@id/task_title"
app:layout_constraintBottom_toBottomOf="@id/task_title"
/>
<EditText
android:id="@+id/task_search"
style="@style/input_blue_type"
@ -14,7 +36,7 @@
android:layout_height="wrap_content"
android:hint="搜索"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toBottomOf="@id/task_title" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/task_recyclerview"

View File

@ -32,7 +32,6 @@ import org.oscim.backend.CanvasAdapter
import org.oscim.backend.canvas.Bitmap
import org.oscim.backend.canvas.Paint
import org.oscim.core.GeoPoint
import org.oscim.event.EventListener
import org.oscim.layers.GroupLayer
import org.oscim.layers.marker.MarkerInterface
import org.oscim.layers.marker.MarkerItem
@ -56,23 +55,6 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
private var baseGroupLayer // 用于盛放所有基础底图的图层组,便于统一管理
: GroupLayer? = null
protected val mTracePath:String = tracePath
/**
* 默认文字颜色
*/
private val mDefaultTextColor = "#4E55AF"
/**
* 文字画笔
*/
private lateinit var paint: Paint
//画布
private lateinit var canvas: org.oscim.backend.canvas.Canvas
private lateinit var itemizedLayer: MyItemizedLayer
private lateinit var markerRendererFactory: MarkerRendererFactory
private var resId = R.mipmap.map_icon_point_add
private var itemListener: OnQsRecordItemClickListener? = null
/**
* 轨迹渲染图层
@ -88,6 +70,7 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
* 增加作业渲染
*/
private lateinit var labelNiLocationLayer: LabelLayer
/**
* 显示待测评OMDB数据的图层
* */
@ -108,8 +91,6 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
private fun initMap() {
loadBaseMap()
//初始化之间数据图层
initQsRecordDataLayer()
initOMDBVectorTileLayer()
@ -131,26 +112,10 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
mMapView.switchTileVectorLayerTheme(NIMapView.MAP_THEME.DEFAULT)
//初始化之间数据图层
initQsRecordDataLayer()
mMapView.updateMap()
// initMapLifeSource()
// 设置矢量图层均在12级以上才显示
mMapView.vtmMap.events.bind(UpdateListener { e, mapPosition ->
if (e == org.oscim.map.Map.SCALE_EVENT) {
itemizedLayer.isEnabled = mapPosition.getZoomLevel() >= 12
// 测评数据图层在指定Zoom后开始显示
val isOmdbZoom = mapPosition.zoomLevel>=Constant.OMDB_MIN_ZOOM
baseGroupLayer?.layers?.forEach {
it.isEnabled = !isOmdbZoom
}
omdbVectorTileLayer.isEnabled = isOmdbZoom
omdbLabelLayer.isEnabled = isOmdbZoom
}
})
}
private fun initOMDBVectorTileLayer() {
@ -228,405 +193,6 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
mMapView.updateMap()
}
fun setOnQsRecordItemClickListener(listener: OnQsRecordItemClickListener?) {
itemListener = listener
}
/**
* 增加或更新marker
*/
suspend fun addOrUpdateQsRecordMark(data: QsRecordBean) {
for (item in itemizedLayer.itemList) {
if (item is MarkerItem) {
if (item.title == data.id) {
itemizedLayer.itemList.remove(item)
break
}
}
}
createMarkerItem(data)
withContext(Dispatchers.Main) {
mMapView.updateMap(true)
}
}
/**
* 删除marker
*/
suspend fun removeQsRecordMark(data: QsRecordBean) {
for (item in itemizedLayer.itemList) {
if (item is MarkerItem) {
if (item.title == data.id) {
itemizedLayer.itemList.remove(item)
itemizedLayer.populate()
return
}
}
}
}
/**
* 初始话质检数据图层
*/
private fun initQsRecordDataLayer() {
canvas = CanvasAdapter.newCanvas()
paint = CanvasAdapter.newPaint()
paint.setTypeface(Paint.FontFamily.DEFAULT, Paint.FontStyle.NORMAL)
paint.setTextSize(NUM_13 * CanvasAdapter.getScale())
paint.strokeWidth = 2 * CanvasAdapter.getScale()
paint.color = Color.parseColor(mDefaultTextColor)
val bitmapPoi: Bitmap = AndroidBitmap(
BitmapFactory.decodeResource(
mContext.resources,
R.mipmap.map_icon_blue2
)
)
val symbol = MarkerSymbol(bitmapPoi, MarkerSymbol.HotspotPlace.BOTTOM_CENTER)
markerRendererFactory = MarkerRendererFactory { markerLayer ->
object : ClusterMarkerRenderer(
mContext,
markerLayer,
symbol,
ClusterStyle(
org.oscim.backend.canvas.Color.WHITE,
org.oscim.backend.canvas.Color.BLUE
)
) {
// override fun getClusterBitmap(size: Int): Bitmap? {
// return super.getclusterbitmap(size)
// }
}
}
itemizedLayer =
MyItemizedLayer(
mMapView.vtmMap,
mutableListOf(),
markerRendererFactory,
object : MyItemizedLayer.OnItemGestureListener {
override fun onItemSingleTapUp(
list: MutableList<Int>,
nearest: Int
): Boolean {
itemListener?.let {
val idList = mutableListOf<String>()
if (list.size == 0) {
} else {
for (i in list) {
val markerInterface: MarkerInterface =
itemizedLayer.itemList[i]
if (markerInterface is MarkerItem) {
idList.add(markerInterface.title)
}
}
it.onQsRecordList(idList.distinct().toMutableList())
}
}
return true
}
override fun onItemLongPress(
list: MutableList<Int>?,
nearest: Int
): Boolean {
return true
}
})
addLayer(itemizedLayer, NIMapView.LAYER_GROUPS.OPERATE)
mContext.lifecycleScope.launch(Dispatchers.IO) {
var list = mutableListOf<QsRecordBean>()
val realm = Realm.getDefaultInstance()
Log.e("jingo","realm hashCOde ${realm.hashCode()}")
realm.executeTransaction {
val objects = realm.where<QsRecordBean>().findAll()
list = realm.copyFromRealm(objects)
}
// realm.close()
for (item in list) {
createMarkerItem(item)
}
}
}
private suspend fun createMarkerItem(item: QsRecordBean) {
val bitmap: Bitmap = createTextMarkerBitmap(mContext, item.description, resId)
if (item.t_lifecycle != 2) {
val geometry: Geometry? = GeometryTools.createGeometry(item.geometry)
if (geometry != null) {
var geoPoint: GeoPoint? = null
if (geometry.geometryType != null) {
when (geometry.geometryType.uppercase(Locale.getDefault())) {
"POINT" -> geoPoint =
GeoPoint(geometry.coordinate.y, geometry.coordinate.x)
// "LINESTRING" -> {
// val lineString = geometry as LineString
// if (lineString != null && lineString.coordinates.size > 0) {
// geoPoint = GeoPoint(
// lineString.coordinates[0].y,
// lineString.coordinates[0].x
// )
// }
// val drawableLine: Drawable =
// convertGeometry2Drawable(geometry, lineStyle)
// if (drawableLine != null) {
// dataVectorLayer.add(drawableLine)
// }
// }
// "POLYGON" -> {
// val polygon = geometry as Polygon
// if (polygon != null && polygon.coordinates.size > 0) {
// geoPoint = GeoPoint(
// polygon.coordinates[0].y,
// polygon.coordinates[0].x
// )
// }
// val drawablePolygon: Drawable =
// convertGeometry2Drawable(geometry, polygonStyle)
// if (drawablePolygon != null) {
// dataVectorLayer.add(drawablePolygon)
// }
// }
}
}
if (geoPoint != null) {
var geoMarkerItem: MarkerItem
// if (item.getType() === 1) {
geoMarkerItem = ClusterMarkerItem(
1, item.id, item.description, geoPoint
)
// } else {
// geoMarkerItem = MarkerItem(
// ePointTemp.getType(),
// ePointTemp.getId(),
// ePointTemp.getStyleText(),
// geoPoint
// )
// }
val markerSymbol =
MarkerSymbol(bitmap, MarkerSymbol.HotspotPlace.CENTER)
geoMarkerItem.marker = markerSymbol
itemizedLayer.itemList.add(geoMarkerItem)
}
}
}
itemizedLayer.populate()
}
/**
* 文字和图片拼装文字换行
*
* @param context
* @param text
* @param resId
* @return
*/
private fun createTextMarkerBitmap(context: Context, text: String, resId: Int): Bitmap {
var text: String? = text
return if (text == null || text.trim { it <= ' ' }.isEmpty()) {
val drawable = ResourcesCompat.getDrawable(context.resources, resId, null)
val originBitmap = android.graphics.Bitmap.createBitmap(
drawable!!.intrinsicWidth,
drawable.intrinsicHeight * 2,
android.graphics.Bitmap.Config.ARGB_8888
)
val androidCanvas = Canvas(originBitmap)
val startX = (originBitmap.width - drawable.intrinsicWidth) / 2
drawable.setBounds(
startX, 0, startX + drawable.intrinsicWidth, drawable.intrinsicHeight
)
drawable.draw(androidCanvas)
val bitmap: Bitmap = AndroidBitmap(originBitmap)
canvas.setBitmap(bitmap)
bitmap
} else {
val drawable = ResourcesCompat.getDrawable(context.resources, resId, null)
val textList: MutableList<String> = ArrayList()
val fontSize: Float = NUM_13 * CanvasAdapter.getScale()
paint.setTextSize(fontSize)
var maxWidth = 0f
//最多4行一行7个
if (text.trim { it <= ' ' }.length > 24) {
val size = (drawable!!.intrinsicHeight / 4).toFloat()
if (size < fontSize) paint.setTextSize(size)
if (text.trim { it <= ' ' }.length > 28) text = text.substring(0, 26) + "..."
val temp1 = text.substring(0, 7)
textList.add(temp1)
text = text.substring(7)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 7)
textList.add(temp2)
text = text.substring(7)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
val temp3 = text.substring(0, 7)
textList.add(temp3)
text = text.substring(7)
newWidth = paint.getTextWidth(temp3)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 21) {
val size = (drawable!!.intrinsicHeight / 4).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 6)
textList.add(temp1)
text = text.substring(6)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 6)
textList.add(temp2)
text = text.substring(6)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
val temp3 = text.substring(0, 6)
textList.add(temp3)
text = text.substring(6)
newWidth = paint.getTextWidth(temp3)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 18) {
val size = (drawable!!.intrinsicHeight / 3).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 7)
textList.add(temp1)
text = text.substring(7)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 7)
textList.add(temp2)
text = text.substring(7)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 18) {
val size = (drawable!!.intrinsicHeight / 3).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 7)
textList.add(temp1)
text = text.substring(7)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 7)
textList.add(temp2)
text = text.substring(7)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 14) {
val size = (drawable!!.intrinsicHeight / 3).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 6)
textList.add(temp1)
text = text.substring(6)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 6)
textList.add(temp2)
text = text.substring(6)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 12) {
val size = (drawable!!.intrinsicHeight / 2).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 7)
textList.add(temp1)
text = text.substring(7)
maxWidth = paint.getTextWidth(temp1)
textList.add(text)
val newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 10) {
val size = (drawable!!.intrinsicHeight / 2).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 6)
textList.add(temp1)
text = text.substring(6)
maxWidth = paint.getTextWidth(temp1)
textList.add(text)
val newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 7) {
val size = (drawable!!.intrinsicHeight / 2).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 5)
textList.add(temp1)
text = text.substring(5)
maxWidth = paint.getTextWidth(temp1)
textList.add(text)
val newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else {
val size = drawable!!.intrinsicHeight.toFloat()
if (size < fontSize) paint.setTextSize(size)
textList.add(text)
maxWidth = paint.getTextWidth(text)
}
paint.color = Color.parseColor(mDefaultTextColor)
val originBitmap = android.graphics.Bitmap.createBitmap(
if (drawable.intrinsicWidth > maxWidth) drawable.intrinsicWidth else maxWidth.toInt(),
drawable.intrinsicHeight * 2,
android.graphics.Bitmap.Config.ARGB_4444
)
val androidCanvas = Canvas(originBitmap)
val startX = (originBitmap.width - drawable.intrinsicWidth) / 2
drawable.setBounds(
startX, 0, startX + drawable.intrinsicWidth, drawable.intrinsicHeight
)
drawable.draw(androidCanvas)
val bitmap: Bitmap = AndroidBitmap(originBitmap)
canvas.setBitmap(bitmap)
var startHeight = (drawable.intrinsicHeight + paint.getTextHeight(text)).toInt()
for (txt in textList) {
canvas.drawText(
txt, (bitmap.width - paint.getTextWidth(txt)) / 2, startHeight.toFloat(), paint
)
startHeight += paint.getTextHeight(txt).toInt()
}
bitmap
}
}
//显示轨迹图层
fun showNiLocationLayer() {
@ -639,12 +205,8 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
vectorNiLocationTileLayer.isEnabled = false
labelNiLocationLayer.isEnabled = false
}
}
interface OnQsRecordItemClickListener {
fun onQsRecordList(list: MutableList<String>)
}
/**
* 基础

View File

@ -2,17 +2,36 @@ package com.navinfo.collect.library.map.handler
import android.content.Context
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.lifecycleScope
import com.navinfo.collect.library.R
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.collect.library.map.GeoPoint
import com.navinfo.collect.library.map.NIMapView
import com.navinfo.collect.library.map.cluster.ClusterMarkerItem
import com.navinfo.collect.library.map.cluster.ClusterMarkerRenderer
import com.navinfo.collect.library.map.layers.MyItemizedLayer
import com.navinfo.collect.library.utils.GeometryTools
import com.navinfo.collect.library.utils.StringUtil
import io.realm.Realm
import io.realm.kotlin.where
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.locationtech.jts.geom.Geometry
import org.oscim.android.canvas.AndroidBitmap
import org.oscim.layers.marker.ItemizedLayer
import org.oscim.backend.CanvasAdapter
import org.oscim.backend.canvas.Bitmap
import org.oscim.backend.canvas.Paint
import org.oscim.layers.marker.*
import org.oscim.layers.marker.ItemizedLayer.OnItemGestureListener
import org.oscim.layers.marker.MarkerInterface
import org.oscim.layers.marker.MarkerItem
import org.oscim.layers.marker.MarkerSymbol
import org.oscim.map.Map
import java.util.*
import kotlin.collections.ArrayList
/**
* marker 操作
@ -23,6 +42,29 @@ class MarkHandler(context: AppCompatActivity, mapView: NIMapView) :
// //默认marker图层
private var mDefaultMarkerLayer: ItemizedLayer
/**
* 默认文字颜色
*/
private val mDefaultTextColor = "#4E55AF"
/**
* 文字画笔
*/
private lateinit var paint: Paint
//画布
private lateinit var canvas: org.oscim.backend.canvas.Canvas
private lateinit var itemizedLayer: MyItemizedLayer
private lateinit var markerRendererFactory: MarkerRendererFactory
private var resId = R.mipmap.map_icon_point_add
private var itemListener: OnQsRecordItemClickListener? = null
/**
* 文字大小
*/
private val NUM_13 = 13
init {
//新增marker图标样式
val mDefaultBitmap =
@ -49,6 +91,19 @@ class MarkHandler(context: AppCompatActivity, mapView: NIMapView) :
}
)
addLayer(mDefaultMarkerLayer, NIMapView.LAYER_GROUPS.OPERATE);
//初始化之间数据图层
initQsRecordDataLayer()
// 设置矢量图层均在12级以上才显示
mMapView.vtmMap.events.bind(Map.UpdateListener { e, mapPosition ->
if (e == Map.SCALE_EVENT) {
itemizedLayer.isEnabled = mapPosition.getZoomLevel() >= 12
}
})
mMapView.updateMap()
}
fun setOnQsRecordItemClickListener(listener: OnQsRecordItemClickListener?) {
itemListener = listener
}
//增加marker
@ -99,4 +154,404 @@ class MarkHandler(context: AppCompatActivity, mapView: NIMapView) :
}
}
}
/**
* 增加或更新marker
*/
suspend fun addOrUpdateQsRecordMark(data: QsRecordBean) {
for (item in itemizedLayer.itemList) {
if (item is MarkerItem) {
if (item.title == data.id) {
itemizedLayer.itemList.remove(item)
break
}
}
}
createMarkerItem(data)
withContext(Dispatchers.Main) {
mMapView.updateMap(true)
}
}
/**
* 删除marker
*/
suspend fun removeQsRecordMark(data: QsRecordBean) {
for (item in itemizedLayer.itemList) {
if (item is MarkerItem) {
if (item.title == data.id) {
itemizedLayer.itemList.remove(item)
itemizedLayer.populate()
return
}
}
}
}
/**
* 初始话质检数据图层
*/
private fun initQsRecordDataLayer() {
canvas = CanvasAdapter.newCanvas()
paint = CanvasAdapter.newPaint()
paint.setTypeface(Paint.FontFamily.DEFAULT, Paint.FontStyle.NORMAL)
paint.setTextSize(NUM_13 * CanvasAdapter.getScale())
paint.strokeWidth = 2 * CanvasAdapter.getScale()
paint.color = Color.parseColor(mDefaultTextColor)
val bitmapPoi: Bitmap = AndroidBitmap(
BitmapFactory.decodeResource(
mContext.resources,
R.mipmap.map_icon_blue2
)
)
val symbol = MarkerSymbol(bitmapPoi, MarkerSymbol.HotspotPlace.BOTTOM_CENTER)
markerRendererFactory = MarkerRendererFactory { markerLayer ->
object : ClusterMarkerRenderer(
mContext,
markerLayer,
symbol,
ClusterStyle(
org.oscim.backend.canvas.Color.WHITE,
org.oscim.backend.canvas.Color.BLUE
)
) {
// override fun getClusterBitmap(size: Int): Bitmap? {
// return super.getclusterbitmap(size)
// }
}
}
itemizedLayer =
MyItemizedLayer(
mMapView.vtmMap,
mutableListOf(),
markerRendererFactory,
object : MyItemizedLayer.OnItemGestureListener {
override fun onItemSingleTapUp(
list: MutableList<Int>,
nearest: Int
): Boolean {
itemListener?.let {
val idList = mutableListOf<String>()
if (list.size == 0) {
} else {
for (i in list) {
val markerInterface: MarkerInterface =
itemizedLayer.itemList[i]
if (markerInterface is MarkerItem) {
idList.add(markerInterface.title)
}
}
it.onQsRecordList(idList.distinct().toMutableList())
}
}
return true
}
override fun onItemLongPress(
list: MutableList<Int>?,
nearest: Int
): Boolean {
return true
}
})
addLayer(itemizedLayer, NIMapView.LAYER_GROUPS.OPERATE)
mContext.lifecycleScope.launch(Dispatchers.IO) {
var list = mutableListOf<QsRecordBean>()
val realm = Realm.getDefaultInstance()
Log.e("jingo", "realm hashCOde ${realm.hashCode()}")
realm.executeTransaction {
val objects = realm.where<QsRecordBean>().findAll()
list = realm.copyFromRealm(objects)
}
// realm.close()
for (item in list) {
createMarkerItem(item)
}
}
}
private suspend fun createMarkerItem(item: QsRecordBean) {
val bitmap: Bitmap = createTextMarkerBitmap(mContext, item.description, resId)
if (item.t_lifecycle != 2) {
val geometry: Geometry? = GeometryTools.createGeometry(item.geometry)
if (geometry != null) {
var geoPoint: org.oscim.core.GeoPoint? = null
if (geometry.geometryType != null) {
when (geometry.geometryType.uppercase(Locale.getDefault())) {
"POINT" -> geoPoint =
org.oscim.core.GeoPoint(geometry.coordinate.y, geometry.coordinate.x)
// "LINESTRING" -> {
// val lineString = geometry as LineString
// if (lineString != null && lineString.coordinates.size > 0) {
// geoPoint = GeoPoint(
// lineString.coordinates[0].y,
// lineString.coordinates[0].x
// )
// }
// val drawableLine: Drawable =
// convertGeometry2Drawable(geometry, lineStyle)
// if (drawableLine != null) {
// dataVectorLayer.add(drawableLine)
// }
// }
// "POLYGON" -> {
// val polygon = geometry as Polygon
// if (polygon != null && polygon.coordinates.size > 0) {
// geoPoint = GeoPoint(
// polygon.coordinates[0].y,
// polygon.coordinates[0].x
// )
// }
// val drawablePolygon: Drawable =
// convertGeometry2Drawable(geometry, polygonStyle)
// if (drawablePolygon != null) {
// dataVectorLayer.add(drawablePolygon)
// }
// }
}
}
if (geoPoint != null) {
var geoMarkerItem: MarkerItem
// if (item.getType() === 1) {
geoMarkerItem = ClusterMarkerItem(
1, item.id, item.description, geoPoint
)
// } else {
// geoMarkerItem = MarkerItem(
// ePointTemp.getType(),
// ePointTemp.getId(),
// ePointTemp.getStyleText(),
// geoPoint
// )
// }
val markerSymbol =
MarkerSymbol(bitmap, MarkerSymbol.HotspotPlace.CENTER)
geoMarkerItem.marker = markerSymbol
itemizedLayer.itemList.add(geoMarkerItem)
}
}
}
itemizedLayer.populate()
}
/**
* 文字和图片拼装文字换行
*
* @param context
* @param text
* @param resId
* @return
*/
private fun createTextMarkerBitmap(context: Context, text: String, resId: Int): Bitmap {
var text: String? = text
return if (text == null || text.trim { it <= ' ' }.isEmpty()) {
val drawable = ResourcesCompat.getDrawable(context.resources, resId, null)
val originBitmap = android.graphics.Bitmap.createBitmap(
drawable!!.intrinsicWidth,
drawable.intrinsicHeight * 2,
android.graphics.Bitmap.Config.ARGB_8888
)
val androidCanvas = Canvas(originBitmap)
val startX = (originBitmap.width - drawable.intrinsicWidth) / 2
drawable.setBounds(
startX, 0, startX + drawable.intrinsicWidth, drawable.intrinsicHeight
)
drawable.draw(androidCanvas)
val bitmap: Bitmap = AndroidBitmap(originBitmap)
canvas.setBitmap(bitmap)
bitmap
} else {
val drawable = ResourcesCompat.getDrawable(context.resources, resId, null)
val textList: MutableList<String> = java.util.ArrayList()
val fontSize: Float = NUM_13 * CanvasAdapter.getScale()
paint.setTextSize(fontSize)
var maxWidth = 0f
//最多4行一行7个
if (text.trim { it <= ' ' }.length > 24) {
val size = (drawable!!.intrinsicHeight / 4).toFloat()
if (size < fontSize) paint.setTextSize(size)
if (text.trim { it <= ' ' }.length > 28) text = text.substring(0, 26) + "..."
val temp1 = text.substring(0, 7)
textList.add(temp1)
text = text.substring(7)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 7)
textList.add(temp2)
text = text.substring(7)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
val temp3 = text.substring(0, 7)
textList.add(temp3)
text = text.substring(7)
newWidth = paint.getTextWidth(temp3)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 21) {
val size = (drawable!!.intrinsicHeight / 4).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 6)
textList.add(temp1)
text = text.substring(6)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 6)
textList.add(temp2)
text = text.substring(6)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
val temp3 = text.substring(0, 6)
textList.add(temp3)
text = text.substring(6)
newWidth = paint.getTextWidth(temp3)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 18) {
val size = (drawable!!.intrinsicHeight / 3).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 7)
textList.add(temp1)
text = text.substring(7)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 7)
textList.add(temp2)
text = text.substring(7)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 18) {
val size = (drawable!!.intrinsicHeight / 3).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 7)
textList.add(temp1)
text = text.substring(7)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 7)
textList.add(temp2)
text = text.substring(7)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 14) {
val size = (drawable!!.intrinsicHeight / 3).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 6)
textList.add(temp1)
text = text.substring(6)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 6)
textList.add(temp2)
text = text.substring(6)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 12) {
val size = (drawable!!.intrinsicHeight / 2).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 7)
textList.add(temp1)
text = text.substring(7)
maxWidth = paint.getTextWidth(temp1)
textList.add(text)
val newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 10) {
val size = (drawable!!.intrinsicHeight / 2).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 6)
textList.add(temp1)
text = text.substring(6)
maxWidth = paint.getTextWidth(temp1)
textList.add(text)
val newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 7) {
val size = (drawable!!.intrinsicHeight / 2).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 5)
textList.add(temp1)
text = text.substring(5)
maxWidth = paint.getTextWidth(temp1)
textList.add(text)
val newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else {
val size = drawable!!.intrinsicHeight.toFloat()
if (size < fontSize) paint.setTextSize(size)
textList.add(text)
maxWidth = paint.getTextWidth(text)
}
paint.color = Color.parseColor(mDefaultTextColor)
val originBitmap = android.graphics.Bitmap.createBitmap(
if (drawable.intrinsicWidth > maxWidth) drawable.intrinsicWidth else maxWidth.toInt(),
drawable.intrinsicHeight * 2,
android.graphics.Bitmap.Config.ARGB_4444
)
val androidCanvas = Canvas(originBitmap)
val startX = (originBitmap.width - drawable.intrinsicWidth) / 2
drawable.setBounds(
startX, 0, startX + drawable.intrinsicWidth, drawable.intrinsicHeight
)
drawable.draw(androidCanvas)
val bitmap: Bitmap = AndroidBitmap(originBitmap)
canvas.setBitmap(bitmap)
var startHeight = (drawable.intrinsicHeight + paint.getTextHeight(text)).toInt()
for (txt in textList) {
canvas.drawText(
txt, (bitmap.width - paint.getTextWidth(txt)) / 2, startHeight.toFloat(), paint
)
startHeight += paint.getTextHeight(txt).toInt()
}
bitmap
}
}
}
interface OnQsRecordItemClickListener {
fun onQsRecordList(list: MutableList<String>)
}