fix: 合并冲突

This commit is contained in:
xiaoyan 2023-04-24 10:56:29 +08:00
commit e3a9b09aa2
52 changed files with 1497 additions and 447 deletions

View File

@ -16,6 +16,7 @@
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- 访问网络,网络定位需要上网 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 允许访问振动设备 -->
@ -36,10 +37,10 @@
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:largeHeap="true"
android:theme="@style/Theme.OMQualityInspection"
android:requestLegacyExternalStorage="true">
android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
android:theme="@style/Theme.OMQualityInspection">
<activity
android:name=".ui.activity.login.LoginActivity"
android:exported="true"
@ -59,7 +60,9 @@
android:screenOrientation="landscape"
android:theme="@style/Theme.OMQualityInspection" />
<meta-data android:name="ScopedStorage" android:value="true" />
<meta-data
android:name="ScopedStorage"
android:value="true" />
</application>
</manifest>

View File

@ -27,7 +27,7 @@ class Constant {
/**
* 服务器地址
*/
const val SERVER_ADDRESS = "http://fastmap.navinfo.com/drdc/"
const val SERVER_ADDRESS = "http://fastmap.navinfo.com/"
const val DEBUG = true

View File

@ -2,6 +2,7 @@ package com.navinfo.omqs
import android.app.Application
import android.util.Log
import com.navinfo.omqs.db.MyRealmModule
import com.navinfo.omqs.tools.FileManager
import com.navinfo.omqs.ui.manager.TakePhotoManager
import com.navinfo.omqs.util.NetUtils
@ -20,6 +21,7 @@ class OMQSApplication : Application() {
Util.getInstance().init(applicationContext)
NetUtils.getInstance().init(this)
TakePhotoManager.getInstance().init(this, 1)
FileManager.initRootDir(this)
}
private fun getKey(inputString: String): String {

View File

@ -0,0 +1,21 @@
package com.navinfo.omqs.bean
import io.realm.RealmObject
import io.realm.annotations.RealmClass
@RealmClass
open class HadLinkDvoBean @JvmOverloads constructor(
/**
* 图幅号
*/
var mesh: String = "",
/**
* linkPid
*/
var linkPid: String = "",
/**
* (几何)加偏后
*/
var geometry: String = ""
) : RealmObject()

View File

@ -3,6 +3,7 @@ package com.navinfo.omqs.bean
import android.os.Parcelable
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.navinfo.omqs.tools.FileManager
import kotlinx.parcelize.Parcelize
@ -17,19 +18,9 @@ data class OfflineMapCityBean @JvmOverloads constructor(
var version: Long = 0L,
var fileSize: Long = 0L,
var currentSize: Long = 0L,
var status: Int = NONE
var status: Int = FileManager.Companion.FileDownloadStatus.NONE
) : Parcelable {
companion object Status {
const val NONE = 0 //无状态
const val WAITING = 1 //等待中
const val LOADING = 2 //下载中
const val PAUSE = 3 //暂停
const val ERROR = 4 //错误
const val DONE = 5 //完成
const val UPDATE = 6 //有新版本要更新
}
// // status的转换对象
// var statusEnum: StatusEnum
// get() {

View File

@ -11,20 +11,33 @@ import kotlinx.parcelize.Parcelize
data class ScProblemTypeBean(
@PrimaryKey(autoGenerate = true)
var id: Long = 0,
/**
* elementType
* 要素类型
*/
@ColumnInfo("ELEMENT_TYPE")
val elementType: String = "",
/**
* 要素代码
*/
@ColumnInfo("ELEMENT_CODE")
val elementCode: String = "",
/**
* 问题分类
*/
@ColumnInfo("CLASS_TYPE")
var classType: String = "",
val classType: String = "",
/**
* 问题类型
*/
@ColumnInfo("TYPE")
var problemType: String = "",
val problemType: String = "",
/**
* 问题现象
*/
@ColumnInfo("PHENOMENON")
var phenomenon: String = ""
val phenomenon: String = ""
) : Parcelable

View File

@ -0,0 +1,64 @@
package com.navinfo.omqs.bean
import com.google.gson.annotations.SerializedName
import com.navinfo.omqs.Constant
import com.navinfo.omqs.system.SystemConstant
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
@RealmClass
open class TaskBean @JvmOverloads constructor(
/**
* 测评任务id
*/
@PrimaryKey
var id: Int = 0,
/**
* 测评任务名称
*/
var evaluationTaskName: String = "",
/**
* 市编码
*/
var cityCode: String = "",
/**
*市名称
*/
var cityName: String = "",
/**
* omdb标准版
*/
var dataVersion: String = "",
/**
* 测评人名称
*/
var evaluatorName: String = "",
/**
* 项目标签
*/
var project: String = "",
/**
* 图幅号
*/
@SerializedName("hadLinkDvo")
var hadLinkDvoList: RealmList<HadLinkDvoBean> = RealmList<HadLinkDvoBean>(),
/**
* 文件大小
*/
var fileSize: Long = 0L,
/**
* 当前下载进度
*/
var currentSize: Long = 0L,
/**
* 当前下载状态
*/
var status: Int = FileDownloadStatus.NONE
) : RealmObject(){
fun getDownLoadUrl():String{
return "${Constant.SERVER_ADDRESS}devcp/download?fileStr=26"
}
}

View File

@ -1,7 +1,9 @@
package com.navinfo.omqs.db
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.omqs.bean.HadLinkDvoBean
import com.navinfo.omqs.bean.TaskBean
//@io.realm.annotations.RealmModule(classes = [QsRecordBean::class])
//class MyRealmModule {
//}
@io.realm.annotations.RealmModule(classes = [TaskBean::class, HadLinkDvoBean::class])
class MyRealmModule {
}

View File

@ -5,6 +5,7 @@ import com.navinfo.omqs.db.RealmOperateHelper
import com.navinfo.omqs.db.RoomAppDatabase
import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager
import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -34,6 +35,16 @@ class MainActivityModule {
): OfflineMapDownloadManager =
OfflineMapDownloadManager(networkServiceAPI, roomAppDatabase, mapController)
/**
* 注入任务下载
*/
@ActivityRetainedScoped
@Provides
fun providesTaskListDownloadManager(
networkServiceAPI: RetrofitNetworkServiceAPI,
): TaskDownloadManager =
TaskDownloadManager(networkServiceAPI)
/**
* 实验失败这样创建viewmodel不会在activity销毁的时候同时销毁
* 4-14:因为没有传入activity的 owner,无法检测生命周期

View File

@ -0,0 +1,7 @@
package com.navinfo.omqs.http
class DefaultTaskResponse<T> {
var success: Boolean = false
var msg: String = ""
var obj: T? = null
}

View File

@ -1,6 +1,7 @@
package com.navinfo.omqs.http
import com.navinfo.omqs.bean.OfflineMapCityBean
import com.navinfo.omqs.bean.TaskBean
/**
@ -11,4 +12,8 @@ interface NetworkService {
* 获取离线地图城市列表
*/
suspend fun getOfflineMapCityList():NetResult<List<OfflineMapCityBean>>
/**
* 获取任务列表
*/
suspend fun getTaskList(evaluatorNo:String): NetResult<DefaultTaskResponse<List<TaskBean>>>
}

View File

@ -1,6 +1,7 @@
package com.navinfo.omqs.http
import com.navinfo.omqs.bean.OfflineMapCityBean
import com.navinfo.omqs.bean.TaskBean
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject
@ -32,4 +33,23 @@ class NetworkServiceImpl @Inject constructor(
NetResult.Error(e)
}
}
override suspend fun getTaskList(evaluatorNo: String): NetResult<DefaultTaskResponse<List<TaskBean>>> =
//在IO线程中运行
withContext(Dispatchers.IO) {
return@withContext try {
val result = netApi.retrofitGetTaskList(evaluatorNo)
if (result.isSuccessful) {
if (result.code() == 200) {
NetResult.Success(result.body())
} else {
NetResult.Failure(result.code(), result.message())
}
} else {
NetResult.Failure(result.code(), result.message())
}
} catch (e: Exception) {
NetResult.Error(e)
}
}
}

View File

@ -1,10 +1,12 @@
package com.navinfo.omqs.http
import com.navinfo.omqs.bean.OfflineMapCityBean
import com.navinfo.omqs.bean.TaskBean
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query
import retrofit2.http.Streaming
import retrofit2.http.Url
@ -46,8 +48,15 @@ interface RetrofitNetworkServiceAPI {
*/
@Streaming
@GET
suspend fun retrofitDownLoadFile(@Header("RANGE") start: String? = "0", @Url url: String):Response<ResponseBody>
suspend fun retrofitDownLoadFile(
@Header("RANGE") start: String? = "0",
@Url url: String
): Response<ResponseBody>
@GET("/devcp/task?evaluatType=2")
suspend fun retrofitGetTaskList(
@Query("evaluatorNo") evaluatorNo: String,
): Response<DefaultTaskResponse<List<TaskBean>>>
/**
* @FormUrlEncoded 请求格式注解请求实体是一个From表单每个键值对需要使用@Field注解

View File

@ -112,6 +112,4 @@ class OfflineMapDownloadManager(
scopeMap[id]!!.removeObserver()
}
}
}

View File

@ -6,6 +6,8 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import com.navinfo.omqs.Constant
import com.navinfo.omqs.bean.OfflineMapCityBean
import com.navinfo.omqs.tools.FileManager
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
import kotlinx.coroutines.*
import java.io.File
import java.io.IOException
@ -23,7 +25,7 @@ class OfflineMapDownloadScope(
private val downloadManager: OfflineMapDownloadManager,
val cityBean: OfflineMapCityBean,
) :
CoroutineScope by CoroutineScope(Dispatchers.IO) {
CoroutineScope by CoroutineScope(Dispatchers.IO + CoroutineName("OfflineMapDownLoad")) {
/**
*下载任务用来取消的
*/
@ -46,7 +48,7 @@ class OfflineMapDownloadScope(
//改进的代码
fun start() {
change(OfflineMapCityBean.WAITING)
change(FileDownloadStatus.WAITING)
downloadManager.launchScope(this@OfflineMapDownloadScope)
}
@ -56,7 +58,7 @@ class OfflineMapDownloadScope(
*/
fun pause() {
downloadJob?.cancel("pause")
change(OfflineMapCityBean.PAUSE)
change(FileDownloadStatus.PAUSE)
}
/**
@ -65,11 +67,8 @@ class OfflineMapDownloadScope(
*/
fun launch() {
downloadJob = launch() {
Log.e("jingo", "启动下载1")
download()
Log.e("jingo", "启动下载2")
downloadManager.launchNext(cityBean.id)
Log.e("jingo", "启动下载3")
}
}
@ -78,7 +77,7 @@ class OfflineMapDownloadScope(
* 是否是等待任务
*/
fun isWaiting(): Boolean {
return cityBean.status == OfflineMapCityBean.WAITING
return cityBean.status == FileDownloadStatus.WAITING
}
/**
@ -86,7 +85,7 @@ class OfflineMapDownloadScope(
* @param status [OfflineMapCityBean.Status]
*/
private fun change(status: Int) {
if (cityBean.status != status || status == OfflineMapCityBean.LOADING) {
if (cityBean.status != status || status == FileDownloadStatus.LOADING) {
cityBean.status = status
downloadData.postValue(cityBean)
launch(Dispatchers.IO) {
@ -128,7 +127,7 @@ class OfflineMapDownloadScope(
url = cityBean.url
)
val responseBody = response.body()
change(OfflineMapCityBean.LOADING)
change(FileDownloadStatus.LOADING)
responseBody ?: throw IOException("jingo ResponseBody is null")
//写入文件
randomAccessFile = RandomAccessFile(fileTemp, "rwd")
@ -144,7 +143,7 @@ class OfflineMapDownloadScope(
if (readLength != -1) {
randomAccessFile.write(buffer, 0, readLength)
cityBean.currentSize += readLength
change(OfflineMapCityBean.LOADING)
change(FileDownloadStatus.LOADING)
} else {
break
}
@ -155,15 +154,15 @@ class OfflineMapDownloadScope(
val res =
fileTemp.renameTo(File("${Constant.OFFLINE_MAP_PATH}${cityBean.fileName}"))
Log.e("jingo", "文件下载完成 修改文件 $res")
change(OfflineMapCityBean.DONE)
change(FileDownloadStatus.DONE)
withContext(Dispatchers.Main) {
downloadManager.mapController.layerManagerHandler.loadBaseMap()
}
} else {
change(OfflineMapCityBean.PAUSE)
change(FileDownloadStatus.PAUSE)
}
} catch (e: Throwable) {
change(OfflineMapCityBean.ERROR)
change(FileDownloadStatus.ERROR)
} finally {
inputStream?.close()
randomAccessFile?.close()

View File

@ -0,0 +1,113 @@
package com.navinfo.omqs.http.taskdownload
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import com.navinfo.omqs.bean.TaskBean
import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
import java.util.concurrent.ConcurrentHashMap
/**
* 管理任务数据下载
*/
class TaskDownloadManager(
val netApi: RetrofitNetworkServiceAPI,
) {
/**
* 最多同时下载数量
*/
private val MAX_SCOPE = 3
/**
* 存储有哪些城市需要下载的队列
*/
private val scopeMap: ConcurrentHashMap<Int, TaskDownloadScope> by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
ConcurrentHashMap<Int, TaskDownloadScope>()
}
/**
* 存储正在下载的城市队列
*/
private val taskScopeMap: ConcurrentHashMap<Int, TaskDownloadScope> by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
ConcurrentHashMap<Int, TaskDownloadScope>()
}
/**
* 启动下载任务
* 请不要直接使用此方法启动下载任务,它是交由[OfflineMapDownloadScope]进行调用
*/
fun launchScope(scope: TaskDownloadScope) {
if (taskScopeMap.size >= MAX_SCOPE) {
return
}
if (taskScopeMap.contains(scope.taskBean.id)) {
return
}
taskScopeMap[scope.taskBean.id] = scope
scope.launch()
}
/**
* 启动下一个任务,如果有正在等待中的任务的话
* 请不要直接使用此方法启动下载任务,它是交由[OfflineMapDownloadScope]进行调用
* @param previousUrl 上一个下载任务的下载连接
*/
fun launchNext(id: Int) {
taskScopeMap.remove(id)
for (entrySet in scopeMap) {
val downloadScope = entrySet.value
if (downloadScope.isWaiting()) {
launchScope(downloadScope)
break
}
}
}
/**
* 暂停任务
* 只有等待中的任务和正在下载中的任务才可以进行暂停操作
*/
fun pause(id: Int) {
if (taskScopeMap.containsKey(id)) {
val downloadScope = taskScopeMap[id]
downloadScope?.let {
downloadScope.pause()
}
launchNext(id)
}
}
/**
* 将下载任务加入到协程作用域的下载队列里
* 请求一个下载任务[OfflineMapDownloadScope]
* 这是创建[OfflineMapDownloadScope]的唯一途径,请不要通过其他方式创建[OfflineMapDownloadScope]
*/
fun start(id: Int) {
scopeMap[id]?.start()
}
fun addTask(taskBean: TaskBean) {
if (!scopeMap.containsKey(taskBean.id)) {
scopeMap[taskBean.id] = TaskDownloadScope(this, taskBean)
}
}
fun observer(
id: Int, lifecycleOwner: LifecycleOwner, observer: Observer<TaskBean>
) {
if (scopeMap.containsKey(id)) {
scopeMap[id]!!.observer(lifecycleOwner, observer)
}
}
fun removeObserver(id: Int) {
if (scopeMap.containsKey(id)) {
scopeMap[id]!!.removeObserver()
}
}
}

View File

@ -0,0 +1,168 @@
package com.navinfo.omqs.http.taskdownload
import android.util.Log
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import com.navinfo.omqs.Constant
import com.navinfo.omqs.bean.TaskBean
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
import kotlinx.coroutines.*
import java.io.File
import java.io.IOException
import java.io.InputStream
import java.io.RandomAccessFile
class TaskDownloadScope(
private val downloadManager: TaskDownloadManager,
val taskBean: TaskBean,
) :
CoroutineScope by CoroutineScope(Dispatchers.IO + CoroutineName("OfflineMapDownLoad")) {
/**
*下载任务用来取消的
*/
private var downloadJob: Job? = null
/**
* 管理观察者同时只有一个就行了
*/
private val observer = Observer<Any> {}
// private var lifecycleOwner: LifecycleOwner? = null
/**
*通知UI更新
*/
private val downloadData = MutableLiveData<TaskBean>()
init {
downloadData.value = taskBean
}
//改进的代码
fun start() {
change(FileDownloadStatus.WAITING)
downloadManager.launchScope(this@TaskDownloadScope)
}
/**
* 暂停任务
* 其实就是取消任务移除监听
*/
fun pause() {
downloadJob?.cancel("pause")
change(FileDownloadStatus.PAUSE)
}
/**
* 启动协程进行下载
* 请不要尝试在外部调用此方法,那样会脱离[OfflineMapDownloadManager]的管理
*/
fun launch() {
downloadJob = launch() {
download()
downloadManager.launchNext(taskBean.id)
}
}
/**
* 是否是等待任务
*/
fun isWaiting(): Boolean {
return taskBean.status == FileDownloadStatus.WAITING
}
/**
* 更新任务
* @param status [OfflineMapCityBean.Status]
*/
private fun change(status: Int) {
if (taskBean.status != status || status == FileDownloadStatus.LOADING) {
taskBean.status = status
downloadData.postValue(taskBean)
launch(Dispatchers.IO) {
// downloadManager.roomDatabase.getOfflineMapDao().update(taskBean)
}
}
}
/**
* 添加下载任务观察者
*/
fun observer(owner: LifecycleOwner, ob: Observer<TaskBean>) {
removeObserver()
// this.lifecycleOwner = owner
downloadData.observe(owner, ob)
}
/**
* 下载文件
*/
private suspend fun download() {
var inputStream: InputStream? = null
var randomAccessFile: RandomAccessFile? = null
try {
//创建离线地图 下载文件夹,.map文件夹的下一级
val fileDir = File("${Constant.OFFLINE_MAP_PATH}download")
if (!fileDir.exists()) {
fileDir.mkdirs()
}
val fileTemp =
File("${Constant.OFFLINE_MAP_PATH}download/${taskBean.id}_${taskBean.dataVersion}")
val startPosition = taskBean.currentSize
//验证断点有效性
if (startPosition < 0) throw IOException("jingo Start position less than zero")
val response = downloadManager.netApi.retrofitDownLoadFile(
start = "bytes=$startPosition-",
url = taskBean.getDownLoadUrl()
)
val responseBody = response.body()
change(FileDownloadStatus.LOADING)
responseBody ?: throw IOException("jingo ResponseBody is null")
//写入文件
randomAccessFile = RandomAccessFile(fileTemp, "rwd")
randomAccessFile.seek(startPosition)
taskBean.currentSize = startPosition
inputStream = responseBody.byteStream()
val bufferSize = 1024 * 2
val buffer = ByteArray(bufferSize)
var readLength = 0
while (downloadJob?.isActive == true) {
readLength = inputStream.read(buffer)
if (readLength != -1) {
randomAccessFile.write(buffer, 0, readLength)
taskBean.currentSize += readLength
change(FileDownloadStatus.LOADING)
} else {
break
}
}
Log.e("jingo", "文件下载完成 ${taskBean.currentSize} == ${taskBean.fileSize}")
if (taskBean.currentSize == taskBean.fileSize) {
val res =
fileTemp.renameTo(File("${Constant.OFFLINE_MAP_PATH}${taskBean.evaluationTaskName}.zip"))
Log.e("jingo", "文件下载完成 修改文件 $res")
change(FileDownloadStatus.DONE)
} else {
change(FileDownloadStatus.PAUSE)
}
} catch (e: Throwable) {
change(FileDownloadStatus.ERROR)
} finally {
inputStream?.close()
randomAccessFile?.close()
}
}
fun removeObserver() {
downloadData.observeForever(observer)
// lifecycleOwner?.let {
downloadData.removeObserver(observer)
// null
// }
}
}

View File

@ -6,7 +6,19 @@ import com.navinfo.omqs.bean.OfflineMapCityBean
import java.io.File
class FileManager {
companion object {
object FileDownloadStatus {
const val NONE = 0 //无状态
const val WAITING = 1 //等待中
const val LOADING = 2 //下载中
const val PAUSE = 3 //暂停
const val ERROR = 4 //错误
const val DONE = 5 //完成
const val UPDATE = 6 //有新版本要更新
}
//初始化数据文件夹
fun initRootDir(context:Context){
// 在SD卡创建项目目录
@ -51,7 +63,7 @@ class FileManager {
if (item.isFile && item.name.startsWith(cityBean.id)) {
//如果本地文件与从网络获取到版本号一致,表示这个文件已经下载完毕,不用处理了
if (item.name.contains("_${cityBean.version}.map")) {
cityBean.status = OfflineMapCityBean.DONE
cityBean.status = FileDownloadStatus.DONE
return
}
//文件存在,版本号不对应,留给下面流程处理
@ -72,16 +84,16 @@ class FileManager {
if (item.renameTo(File("${Constant.OFFLINE_MAP_PATH}${cityBean.fileName}"))) {
//删除旧版本数据
mapFile?.delete()
cityBean.status = OfflineMapCityBean.DONE
cityBean.status = FileDownloadStatus.DONE
return
}
} else { // 临时文件大小和目标不一致,说明下载了一半
cityBean.status = OfflineMapCityBean.PAUSE
cityBean.status = FileDownloadStatus.PAUSE
cityBean.currentSize = item.length()
return
}
} else { //虽然省市id开头一致但是版本号不一致说明之前版本下载了一部分现在要更新了原来下载的文件直接删除
cityBean.status = OfflineMapCityBean.UPDATE
cityBean.status = FileDownloadStatus.UPDATE
item.delete()
return
}

View File

@ -29,10 +29,10 @@ open abstract class PermissionsActivity : BaseActivity() {
//定位权限
permissionList.add(Permission.ACCESS_FINE_LOCATION)
permissionList.add(Permission.ACCESS_COARSE_LOCATION)
// //android10
// if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
//android10
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
// permissionList.add(Permission.ACCESS_BACKGROUND_LOCATION)
// }
}
XXPermissions.with(this)
// 申请单个权限
.permission(permissionList)

View File

@ -4,6 +4,8 @@ import android.os.Bundle
import androidx.activity.viewModels
import androidx.core.view.WindowCompat
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import com.blankj.utilcode.util.ToastUtils
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController
import com.navinfo.collect.library.map.NIMapController
@ -14,6 +16,8 @@ import com.navinfo.omqs.databinding.ActivityMainBinding
import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager
import com.navinfo.omqs.system.SystemConstant
import com.navinfo.omqs.ui.activity.BaseActivity
import com.navinfo.omqs.ui.fragment.evaluationresult.EvaluationResultFragment
import com.navinfo.omqs.ui.fragment.evaluationresult.EvaluationResultViewModel
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@ -52,8 +56,12 @@ class MainActivity : BaseActivity() {
binding.mainActivity = this
//给xml传递viewModel对象
binding.viewModel = viewModel
// lifecycle.addObserver(viewModel)
lifecycleScope
viewModel.liveDataQsRecordIdList.observe(this) {
//处理页面跳转
viewModel.navigation(this, it)
}
}
override fun onStart() {
@ -63,9 +71,11 @@ class MainActivity : BaseActivity() {
mapController.locationLayerHandler.startLocation()
//启动轨迹存储
mapController.locationLayerHandler.setNiLocationListener(NiLocationListener {
binding!!.viewModel!!.addSaveTrace(it)
binding!!.viewModel!!.startSaveTraceThread(this)
viewModel.addSaveTrace(it)
// binding.viewModel!!.startSaveTraceThread(this)
})
//显示轨迹图层
// mapController.layerManagerHandler.showNiLocationLayer(Constant.DATA_PATH+ SystemConstant.USER_ID+"/trace.sqlite")
mapController.layerManagerHandler.showNiLocationLayer()
}
@ -96,6 +106,7 @@ class MainActivity : BaseActivity() {
* 打开相机预览
*/
fun openCamera() {
binding.viewModel!!.onClickCameraButton(this)
//显示轨迹图层
//binding!!.viewModel!!.onClickCameraButton(this)
}
@ -108,7 +119,7 @@ class MainActivity : BaseActivity() {
naviController.navigate(R.id.EvaluationResultFragment)
}
override fun onBackPressed() {
super.onBackPressed()
}
// override fun onBackPressed() {
// super.onBackPressed()
// }
}

View File

@ -2,12 +2,16 @@ package com.navinfo.omqs.ui.activity.map
import android.content.Context
import android.content.DialogInterface
import android.os.Bundle
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.navigation.findNavController
import com.blankj.utilcode.util.ToastUtils
import com.navinfo.collect.library.data.dao.impl.TraceDataBase
import com.navinfo.collect.library.data.entity.NiLocation
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.collect.library.map.handler.OnQsRecordItemClickListener
import com.navinfo.collect.library.utils.GeometryTools
import com.navinfo.collect.library.utils.GeometryToolsKt
import com.navinfo.omqs.Constant
@ -19,7 +23,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import io.realm.RealmSet
import org.oscim.core.GeoPoint
import org.videolan.libvlc.LibVlcUtil
import java.util.*
import javax.inject.Inject
/**
@ -30,9 +33,19 @@ class MainViewModel @Inject constructor(
private val mapController: NIMapController,
) : ViewModel() {
val liveDataQsRecordIdList = MutableLiveData<List<String>>()
private var mCameraDialog: CommonDialog? = null
private var niLocationList:MutableList<NiLocation> = ArrayList<NiLocation>()
private var niLocationList: MutableList<NiLocation> = ArrayList<NiLocation>()
init {
mapController.layerManagerHandler.setOnQsRecordItemClickListener(object :
OnQsRecordItemClickListener {
override fun onQsRecordList(list: MutableList<String>) {
liveDataQsRecordIdList.value = list
}
})
}
/**
* 点击我的位置回到我的位置
@ -46,14 +59,21 @@ class MainViewModel @Inject constructor(
}
//点击相机按钮
fun onClickCameraButton(context: Context){
fun onClickCameraButton(context: Context) {
Log.e("qj", LibVlcUtil.hasCompatibleCPU(context).toString())
ToastUtils.showShort("点击了相机")
if (mCameraDialog == null) {
mCameraDialog = CommonDialog(context, context.resources.getDimension(R.dimen.head_img_width).toInt() * 3 + context.resources.getDimension(R.dimen.ten).toInt() + context.resources.getDimension(R.dimen.twenty_four).toInt(), context.resources.getDimension(R.dimen.head_img_width).toInt() + 10, 1)
mCameraDialog = CommonDialog(
context,
context.resources.getDimension(R.dimen.head_img_width)
.toInt() * 3 + context.resources.getDimension(R.dimen.ten)
.toInt() + context.resources.getDimension(R.dimen.twenty_four).toInt(),
context.resources.getDimension(R.dimen.head_img_width).toInt() + 10,
1
)
mCameraDialog!!.setCancelable(true)
}
mCameraDialog!!.openCamear(mCameraDialog!!.getmShareUtil().continusTakePhotoState)
@ -62,10 +82,11 @@ class MainViewModel @Inject constructor(
mCameraDialog!!.hideLoading()
mCameraDialog!!.stopVideo()
try {
if (!mCameraDialog!!.getmShareUtil().connectstate){
if (!mCameraDialog!!.getmShareUtil().connectstate) {
mCameraDialog!!.updateCameraResources(1, mCameraDialog!!.getmDeviceNum())
}
TakePhotoManager.getInstance().getCameraVedioClent(mCameraDialog!!.getmDeviceNum()).StopSearch()
TakePhotoManager.getInstance().getCameraVedioClent(mCameraDialog!!.getmDeviceNum())
.StopSearch()
} catch (e: Exception) {
}
})
@ -77,12 +98,12 @@ class MainViewModel @Inject constructor(
})
}
fun startSaveTraceThread(context: Context){
fun startSaveTraceThread(context: Context) {
Thread(Runnable {
try {
while (true){
while (true) {
if(niLocationList!=null&&niLocationList.size>0){
if (niLocationList != null && niLocationList.size > 0) {
var niLocation = niLocationList[0]
val geometry = GeometryTools.createGeometry(GeoPoint(niLocation.latitude,niLocation.longitude))
@ -99,23 +120,60 @@ class MainViewModel @Inject constructor(
}
}
TraceDataBase.getDatabase(context, Constant.DATA_PATH+ SystemConstant.USER_ID+"/trace.sqlite").niLocationDao.insert(niLocation)
TraceDataBase.getDatabase(
context,
Constant.DATA_PATH + SystemConstant.USER_ID + "/trace.sqlite"
).niLocationDao.insert(niLocation)
niLocationList.removeAt(0)
Log.e("qj","saveTrace")
Log.e("qj", "saveTrace")
}
Thread.sleep(30)
}
} catch (e: InterruptedException) {
e.printStackTrace()
Log.e("qj","异常==${e.message}")
Log.e("qj", "异常==${e.message}")
}
}).start()
}
//增加轨迹存储
fun addSaveTrace(niLocation: NiLocation){
if(niLocation!=null&&niLocationList!=null){
fun addSaveTrace(niLocation: NiLocation) {
if (niLocation != null && niLocationList != null) {
niLocationList.add(niLocation)
}
}
fun navigation(activity: MainActivity, list: List<String>) {
//获取右侧fragment容器
val naviController = activity.findNavController(R.id.main_activity_right_fragment)
naviController.currentDestination?.let { navDestination ->
// when (val fragment =
// activity.supportFragmentManager.findFragmentById(navDestination.id)) {
// //判断右侧的fragment是不是质检数据
//// is EvaluationResultFragment -> {
//// val viewModelFragment =
//// ViewModelProvider(fragment)[EvaluationResultViewModel::class.java]
//// viewModelFragment.notifyData(list)
//// }
// is EmptyFragment -> {
// if (list.size == 1) {
// val bundle = Bundle()
// bundle.putString("QsId", list[0])
// naviController.navigate(R.id.EvaluationResultFragment, bundle)
// }
// }
// }
when (navDestination.id) {
R.id.EmptyFragment -> {
if (list.size == 1) {
val bundle = Bundle()
bundle.putString("QsId", list[0])
naviController.navigate(R.id.EvaluationResultFragment, bundle)
}
}
}
}
}
}

View File

@ -4,6 +4,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.navigation.NavOptions
import androidx.navigation.findNavController
import com.navinfo.omqs.R
@ -14,30 +15,26 @@ import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
private var _binding: FragmentEvaluationResultBinding? = null
private val binding get() = _binding!!
private lateinit var binding: FragmentEvaluationResultBinding
private val viewModel by shareViewModels<EvaluationResultViewModel>("QsRecode")
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
_binding = FragmentEvaluationResultBinding.inflate(inflater, container, false)
binding =
DataBindingUtil.inflate(inflater, R.layout.fragment_evaluation_result, container, false)
binding.fragment = this
binding.viewModel = viewModel
binding.lifecycleOwner = this
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)
//监听是否退出当前页面
viewModel.liveDataFinish.observe(viewLifecycleOwner) {
onBackPressed()
}
//返回按钮点击
binding.evaluationBar.setNavigationOnClickListener {
onBackPressed()
@ -59,7 +56,17 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
/**
* 读取元数据
*/
viewModel.loadMetadata()
if (arguments != null) {
val id = requireArguments().getString("QsId")
if (id != null) {
viewModel.loadData(id)
} else {
viewModel.initNewData()
}
} else {
viewModel.initNewData()
}
// //监听大分类数据变化
// viewModel.liveDataClassTypeList.observe(viewLifecycleOwner) {
// if (it == null || it.isEmpty()) {
@ -155,43 +162,12 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
//
// }
/**
* 监听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
}
/**

View File

@ -4,12 +4,12 @@ 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.collect.library.map.NIMapController
import com.navinfo.omqs.db.RoomAppDatabase
import dagger.hilt.android.lifecycle.HiltViewModel
import io.realm.Realm
import io.realm.kotlin.where
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.*
@ -28,63 +28,34 @@ class EvaluationResultViewModel @Inject constructor(
val liveDataFinish = MutableLiveData<Boolean>()
/**
* 问题分类 liveData[PhenomenonLeftAdapter]展示的数据
* 问题分类 liveData[LeftAdapter]展示的数据
*/
val liveDataClassTypeList = MutableLiveData<List<String>>()
val liveDataLeftTypeList = MutableLiveData<List<String>>()
/**
* 问题类型 liveData [PhenomenonMiddleAdapter]展示的数据
* 问题类型 liveData [MiddleAdapter]展示的数据
*/
val liveDataProblemTypeList = MutableLiveData<List<String>>()
val liveDataMiddleTypeList = MutableLiveData<List<String>>()
/**
* 问题现象 liveData [PhenomenonRightGroupHeaderAdapter]展示的数据
* 问题现象 liveData [RightGroupHeaderAdapter]展示的数据
*/
val liveDataPhenomenonRightList = MutableLiveData<List<PhenomenonMiddleBean>>()
val liveDataRightTypeList = MutableLiveData<List<RightBean>>()
/**
* 当前选择问题分类 [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
var liveDataQsRecordBean = MutableLiveData<QsRecordBean>()
var oldBean: QsRecordBean? = null
init {
liveDataQsRecordBean.value = QsRecordBean(id = UUID.randomUUID().toString())
Log.e("jingo", "EvaluationResultViewModel 创建了 ${hashCode()}")
mapController.markerHandle.apply {
setOnMapClickListener {
currentGeoPoint = it
liveDataQsRecordBean.value!!.geometry = it.toGeometry()
addMarker(it, markerTitle)
}
}
val geoPoint = mapController.locationLayerHandler.getCurrentGeoPoint()
geoPoint?.let {
currentGeoPoint = it
mapController.markerHandle.addMarker(geoPoint, markerTitle)
}
}
@ -99,144 +70,181 @@ class EvaluationResultViewModel @Inject constructor(
/**
* 查询数据库获取问题分类
*/
fun loadMetadata() {
fun initNewData() {
viewModelScope.launch(Dispatchers.IO) {
getClassTypeList()
getProblemLinkList()
}
val geoPoint = mapController.locationLayerHandler.getCurrentGeoPoint()
geoPoint?.let {
liveDataQsRecordBean.value!!.geometry = it.toGeometry()
mapController.markerHandle.addMarker(geoPoint, markerTitle)
}
}
/**
* //获取问题分类列表
*/
fun getClassTypeList() {
Log.e("jingo", "getClassTypeList S")
viewModelScope.launch(Dispatchers.IO) {
val list = roomAppDatabase.getScProblemTypeDao().findClassTypeList()
list?.let {
//通知页面更新
liveDataClassTypeList.postValue(it)
//如果右侧栏没数据,给个默认值
if (liveDataCurrentClassType.value == null) {
liveDataCurrentClassType.postValue(it[0])
if (list.isNotEmpty()) {
//通知页面更新
liveDataLeftTypeList.postValue(it)
val classType = it[0]
//如果右侧栏没数据,给个默认值
if (liveDataQsRecordBean.value!!.classType.isEmpty()) {
Log.e("jingo", "getClassTypeList $classType")
liveDataQsRecordBean.value!!.classType = classType
}
getProblemList(classType)
}
getProblemList(it[0])
}
}
Log.e("jingo", "getClassTypeList E")
}
/**
* 获取问题环节列表和初步问题
*/
fun getProblemLinkList() {
Log.e("jingo", "getProblemLinkList S")
viewModelScope.launch(Dispatchers.IO) {
val list = roomAppDatabase.getScRootCauseAnalysisDao().findAllData()
list?.let { tl ->
if (tl.isNotEmpty()) {
val typeTitleList = mutableListOf<String>()
val phenomenonRightList = mutableListOf<PhenomenonMiddleBean>()
val middleList = mutableListOf<String>()
val rightList = mutableListOf<RightBean>()
for (item in tl) {
if (!typeTitleList.contains(item.problemLink)) {
typeTitleList.add(item.problemLink)
if (!middleList.contains(item.problemLink)) {
middleList.add(item.problemLink)
}
phenomenonRightList.add(
PhenomenonMiddleBean(
rightList.add(
RightBean(
title = item.problemLink, text = item.problemCause, isSelect = false
)
)
}
if (liveDataCurrentProblemLink.value == null) {
liveDataCurrentProblemLink.postValue(phenomenonRightList[0].text)
if (liveDataQsRecordBean.value!!.problemLink.isEmpty()) {
liveDataQsRecordBean.value!!.problemLink = middleList[0]
Log.e("jingo", "getProblemLinkList ${middleList[0]}")
}
if (liveDataCurrentCause.value == null) {
liveDataCurrentCause.postValue(typeTitleList[0])
if (liveDataQsRecordBean.value!!.cause.isEmpty()) {
liveDataQsRecordBean.value!!.cause = rightList[0].text
Log.e("jingo", "getProblemLinkList ${rightList[0].text}")
}
liveDataProblemTypeList.postValue(typeTitleList)
liveDataPhenomenonRightList.postValue(phenomenonRightList)
liveDataQsRecordBean.postValue(liveDataQsRecordBean.value)
liveDataMiddleTypeList.postValue(middleList)
liveDataRightTypeList.postValue(rightList)
}
}
}
Log.e("jingo", "getProblemLinkList E")
}
/**
* 获取问题类型列表和问题现象
*/
private suspend fun getProblemList(classType: String) {
Log.e("jingo", "getProblemList S")
val typeList = roomAppDatabase.getScProblemTypeDao().findProblemTypeList(classType)
typeList?.let { tl ->
if (tl.isNotEmpty()) {
val typeTitleList = mutableListOf<String>()
val phenomenonRightList = mutableListOf<PhenomenonMiddleBean>()
val phenomenonRightList = mutableListOf<RightBean>()
for (item in tl) {
if (!typeTitleList.contains(item.problemType)) {
typeTitleList.add(item.problemType)
}
phenomenonRightList.add(
PhenomenonMiddleBean(
RightBean(
title = item.problemType, text = item.phenomenon, isSelect = false
)
)
}
if (liveDataCurrentPhenomenon.value == null) {
liveDataCurrentPhenomenon.postValue(phenomenonRightList[0].text)
if (liveDataQsRecordBean.value!!.problemType.isEmpty()) {
liveDataQsRecordBean.value!!.problemType = typeTitleList[0]
Log.e("jingo", "getProblemList ${typeTitleList[0]}")
}
if (liveDataCurrentProblemType.value == null) {
liveDataCurrentProblemType.postValue(typeTitleList[0])
liveDataMiddleTypeList.postValue(typeTitleList)
if (liveDataQsRecordBean.value!!.phenomenon.isEmpty()) {
liveDataQsRecordBean.value!!.phenomenon = phenomenonRightList[0].text
Log.e("jingo", "getProblemList ${phenomenonRightList[0].text}")
}
liveDataProblemTypeList.postValue(typeTitleList)
liveDataPhenomenonRightList.postValue(phenomenonRightList)
liveDataQsRecordBean.postValue(liveDataQsRecordBean.value)
liveDataRightTypeList.postValue(phenomenonRightList)
}
}
Log.e("jingo", "getProblemList E")
}
/**
* 查询问题类型
* 查询问题类型列表
*/
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 setPhenomenonMiddleBean(adapterBean: RightBean) {
liveDataQsRecordBean.value!!.phenomenon = adapterBean.text
liveDataQsRecordBean.value!!.problemType = adapterBean.title
liveDataQsRecordBean.postValue(liveDataQsRecordBean.value)
}
fun setProblemLinkMiddleBean(bean: PhenomenonMiddleBean) {
if (liveDataCurrentProblemLink.value != bean.text) liveDataCurrentProblemLink.value =
bean.text
if (liveDataCurrentCause.value != bean.title) liveDataCurrentCause.value = bean.title
fun setProblemLinkMiddleBean(adapterBean: RightBean) {
liveDataQsRecordBean.value!!.cause = adapterBean.text
liveDataQsRecordBean.value!!.problemLink = adapterBean.title
liveDataQsRecordBean.postValue(liveDataQsRecordBean.value)
}
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()
Log.e("jingo","realm hashCOde ${realm.hashCode()}")
realm.executeTransaction {
it.copyToRealmOrUpdate(qsRecord)
it.copyToRealmOrUpdate(liveDataQsRecordBean.value)
}
realm.close()
mapController.mMapView.updateMap()
// realm.close()
mapController.layerManagerHandler.addOrUpdateQsRecordMark(liveDataQsRecordBean.value!!)
liveDataFinish.postValue(true)
}
}
fun deleteData() {
viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
Log.e("jingo","realm hashCOde ${realm.hashCode()}")
realm.executeTransaction {
val objects = it.where(QsRecordBean::class.java)
.equalTo("id", liveDataQsRecordBean.value?.id).findFirst()
objects?.deleteFromRealm()
}
// realm.close()
mapController.layerManagerHandler.removeQsRecordMark(liveDataQsRecordBean.value!!)
liveDataFinish.postValue(true)
}
}
/**
* 根据数据id查询数据
*/
fun loadData(id: String) {
viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
val objects = realm.where<QsRecordBean>().equalTo("id", id).findFirst()
if (objects != null) {
oldBean = realm.copyFromRealm(objects)
liveDataQsRecordBean.postValue(oldBean!!.copy())
}
}
}
}

View File

@ -7,7 +7,7 @@ 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) :
class LeftAdapter(private var itemListener: ((Int, String) -> Unit?)? = null) :
BaseRecyclerViewAdapter<String>() {
private var selectTitle = ""

View File

@ -7,7 +7,7 @@ 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) :
class MiddleAdapter(private var itemListener: ((Int, String) -> Unit?)? = null) :
BaseRecyclerViewAdapter<String>() {
private var selectTitle = ""

View File

@ -5,13 +5,9 @@ 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
@ -41,12 +37,15 @@ class PhenomenonFragment :
//左侧菜单
binding.phenomenonLeftRecyclerview.setHasFixedSize(true)
binding.phenomenonLeftRecyclerview.layoutManager = LinearLayoutManager(requireContext())
val leftAdapter = PhenomenonLeftAdapter { _, text ->
/**
* 监听左侧栏的点击事件
*/
val leftAdapter = LeftAdapter { _, text ->
viewModel.getProblemTypeList(text)
}
binding.phenomenonLeftRecyclerview.adapter = leftAdapter
//左侧菜单查询结果监听
viewModel.liveDataClassTypeList.observe(viewLifecycleOwner) {
viewModel.liveDataLeftTypeList.observe(viewLifecycleOwner) {
leftAdapter.refreshData(it)
}
@ -55,26 +54,34 @@ class PhenomenonFragment :
var rightLayoutManager = LinearLayoutManager(requireContext())
binding.phenomenonRightRecyclerview.layoutManager = rightLayoutManager
val rightAdapter = PhenomenonRightGroupHeaderAdapter { _, bean ->
/**
* 监听右侧栏的点击事件
*/
val rightAdapter = RightGroupHeaderAdapter { _, bean ->
viewModel.setPhenomenonMiddleBean(bean)
}
binding.phenomenonRightRecyclerview.adapter = rightAdapter
//右侧菜单增加组标题
binding.phenomenonRightRecyclerview.addItemDecoration(
PhenomenonRightGroupHeaderDecoration(
RightGroupHeaderDecoration(
requireContext()
)
)
//右侧菜单查询数据监听
viewModel.liveDataPhenomenonRightList.observe(viewLifecycleOwner) {
viewModel.liveDataRightTypeList.observe(viewLifecycleOwner) {
rightAdapter.refreshData(it)
}
val middleAdapter = PhenomenonMiddleAdapter { _, title ->
/**
* 监听中间栏的点击事件
*/
val middleAdapter = MiddleAdapter { _, title ->
rightLayoutManager.scrollToPositionWithOffset(rightAdapter.getGroupTopIndex(title), 0)
}
/**
* 监控右侧滚动更新左侧
*/
binding.phenomenonRightRecyclerview.addOnScrollListener(object :
OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
@ -98,7 +105,7 @@ class PhenomenonFragment :
binding.phenomenonMiddleRecyclerview.layoutManager = LinearLayoutManager(requireContext())
binding.phenomenonMiddleRecyclerview.adapter = middleAdapter
//中间侧菜单查询结果监听
viewModel.liveDataProblemTypeList.observe(viewLifecycleOwner) {
viewModel.liveDataMiddleTypeList.observe(viewLifecycleOwner) {
middleAdapter.refreshData(it)
}
binding.phenomenonDrawer.setOnClickListener {

View File

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

View File

@ -35,22 +35,22 @@ class ProblemLinkFragment : BaseFragment() {
var rightLayoutManager = LinearLayoutManager(requireContext())
binding.linkRightRecyclerview.layoutManager = rightLayoutManager
val rightAdapter = PhenomenonRightGroupHeaderAdapter { _, bean ->
val rightAdapter = RightGroupHeaderAdapter { _, bean ->
viewModel.setProblemLinkMiddleBean(bean)
}
binding.linkRightRecyclerview.adapter = rightAdapter
//右侧菜单增加组标题
binding.linkRightRecyclerview.addItemDecoration(
PhenomenonRightGroupHeaderDecoration(
RightGroupHeaderDecoration(
requireContext()
)
)
//右侧菜单查询数据监听
viewModel.liveDataPhenomenonRightList.observe(viewLifecycleOwner) {
viewModel.liveDataRightTypeList.observe(viewLifecycleOwner) {
rightAdapter.refreshData(it)
}
val middleAdapter = PhenomenonMiddleAdapter { _, title ->
val middleAdapter = MiddleAdapter { _, title ->
rightLayoutManager.scrollToPositionWithOffset(rightAdapter.getGroupTopIndex(title), 0)
}
@ -72,7 +72,7 @@ class ProblemLinkFragment : BaseFragment() {
binding.linkMiddleRecyclerview.layoutManager = LinearLayoutManager(requireContext())
binding.linkMiddleRecyclerview.adapter = middleAdapter
//中间侧菜单查询结果监听
viewModel.liveDataProblemTypeList.observe(viewLifecycleOwner) {
viewModel.liveDataMiddleTypeList.observe(viewLifecycleOwner) {
middleAdapter.refreshData(it)
}
binding.linkDrawer.setOnClickListener {

View File

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

View File

@ -7,8 +7,8 @@ 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>() {
class RightGroupHeaderAdapter(private var itemListener: ((Int, RightBean) -> Unit?)? = null) :
BaseRecyclerViewAdapter<RightBean>() {
private var groupTitleList = mutableListOf<String>()
override fun getItemViewRes(position: Int): Int {
return R.layout.text_item_select
@ -85,7 +85,7 @@ class PhenomenonRightGroupHeaderAdapter(private var itemListener: ((Int, Phenome
return 0
}
override fun refreshData(newData: List<PhenomenonMiddleBean>) {
override fun refreshData(newData: List<RightBean>) {
super.refreshData(newData)
groupTitleList.clear()
for (item in newData) {

View File

@ -5,7 +5,6 @@ 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
@ -15,7 +14,7 @@ import androidx.recyclerview.widget.RecyclerView.ItemDecoration
/**
* 自定义装饰器实现分组+吸顶效果
*/
class PhenomenonRightGroupHeaderDecoration(context: Context) : ItemDecoration() {
class RightGroupHeaderDecoration(context: Context) : ItemDecoration() {
//头部的高
private val mItemHeaderHeight: Int
private val mTextPaddingLeft: Int
@ -48,8 +47,8 @@ class PhenomenonRightGroupHeaderDecoration(context: Context) : ItemDecoration()
* @param state
*/
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
if (parent.adapter is PhenomenonRightGroupHeaderAdapter) {
val adapter = parent.adapter as PhenomenonRightGroupHeaderAdapter
if (parent.adapter is RightGroupHeaderAdapter) {
val adapter = parent.adapter as RightGroupHeaderAdapter
val count = parent.childCount //获取可见范围内Item的总数
for (i in 0 until count) {
val view: View = parent.getChildAt(i)
@ -99,8 +98,8 @@ class PhenomenonRightGroupHeaderDecoration(context: Context) : ItemDecoration()
* @param state
*/
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
if (parent.adapter is PhenomenonRightGroupHeaderAdapter) {
val adapter = parent.adapter as PhenomenonRightGroupHeaderAdapter
if (parent.adapter is RightGroupHeaderAdapter) {
val adapter = parent.adapter as RightGroupHeaderAdapter
val position =
(parent.layoutManager as LinearLayoutManager?)!!.findFirstVisibleItemPosition()
parent.findViewHolderForAdapterPosition(position)?.let {
@ -169,8 +168,8 @@ class PhenomenonRightGroupHeaderDecoration(context: Context) : ItemDecoration()
parent: RecyclerView,
state: RecyclerView.State
) {
if (parent.adapter is PhenomenonRightGroupHeaderAdapter) {
val adapter = parent.adapter as PhenomenonRightGroupHeaderAdapter
if (parent.adapter is RightGroupHeaderAdapter) {
val adapter = parent.adapter as RightGroupHeaderAdapter
//获取当前view在整个列表中的位置
val position = parent.getChildLayoutPosition(view)
//是不是改组的第一个
@ -180,7 +179,7 @@ class PhenomenonRightGroupHeaderDecoration(context: Context) : ItemDecoration()
if (adapter.isLastGroupTitle(position)) {
lastGroupView = view
}
} else if (position == (parent.adapter as PhenomenonRightGroupHeaderAdapter).itemCount - 1) {
} else if (position == (parent.adapter as RightGroupHeaderAdapter).itemCount - 1) {
//判断这条是不是最后一条
//如果是最后一个,找到他所在组的第一个
lastGroupView?.let {

View File

@ -10,6 +10,8 @@ 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.tools.FileManager
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder
import javax.inject.Inject
@ -31,11 +33,11 @@ class OfflineMapCityListAdapter(
if (it.tag != null) {
val cityBean = data[it.tag as Int]
when (cityBean.status) {
OfflineMapCityBean.NONE, OfflineMapCityBean.UPDATE, OfflineMapCityBean.PAUSE, OfflineMapCityBean.ERROR -> {
FileDownloadStatus.NONE, FileDownloadStatus.UPDATE, FileDownloadStatus.PAUSE, FileDownloadStatus.ERROR -> {
Log.e("jingo", "开始下载 ${cityBean.status}")
downloadManager.start(cityBean.id)
}
OfflineMapCityBean.LOADING, OfflineMapCityBean.WAITING -> {
FileDownloadStatus.LOADING, FileDownloadStatus.WAITING -> {
Log.e("jingo", "暂停 ${cityBean.status}")
downloadManager.pause(cityBean.id)
}
@ -88,37 +90,37 @@ class OfflineMapCityListAdapter(
binding.offlineMapProgress.progress =
(cityBean.currentSize * 100 / cityBean.fileSize).toInt()
when (cityBean.status) {
OfflineMapCityBean.NONE -> {
FileDownloadStatus.NONE -> {
if (binding.offlineMapProgress.visibility == View.VISIBLE) binding.offlineMapProgress.visibility =
View.INVISIBLE
binding.offlineMapDownloadBtn.text = "下载"
}
OfflineMapCityBean.WAITING -> {
FileDownloadStatus.WAITING -> {
if (binding.offlineMapProgress.visibility != View.VISIBLE) binding.offlineMapProgress.visibility =
View.VISIBLE
binding.offlineMapDownloadBtn.text = "等待中"
}
OfflineMapCityBean.LOADING -> {
FileDownloadStatus.LOADING -> {
if (binding.offlineMapProgress.visibility != View.VISIBLE) binding.offlineMapProgress.visibility =
View.VISIBLE
binding.offlineMapDownloadBtn.text = "暂停"
}
OfflineMapCityBean.PAUSE -> {
FileDownloadStatus.PAUSE -> {
if (binding.offlineMapProgress.visibility != View.VISIBLE) binding.offlineMapProgress.visibility =
View.VISIBLE
binding.offlineMapDownloadBtn.text = "继续"
}
OfflineMapCityBean.ERROR -> {
FileDownloadStatus.ERROR -> {
if (binding.offlineMapProgress.visibility != View.VISIBLE) binding.offlineMapProgress.visibility =
View.VISIBLE
binding.offlineMapDownloadBtn.text = "重试"
}
OfflineMapCityBean.DONE -> {
FileDownloadStatus.DONE -> {
if (binding.offlineMapProgress.visibility == View.VISIBLE) binding.offlineMapProgress.visibility =
View.INVISIBLE
binding.offlineMapDownloadBtn.text = "已完成"
}
OfflineMapCityBean.UPDATE -> {
FileDownloadStatus.UPDATE -> {
if (binding.offlineMapProgress.visibility == View.VISIBLE) binding.offlineMapProgress.visibility =
View.INVISIBLE
binding.offlineMapDownloadBtn.text = "更新"

View File

@ -8,11 +8,12 @@ import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.google.android.material.tabs.TabLayoutMediator
import com.navinfo.omqs.databinding.FragmentOfflineMapBinding
import com.navinfo.omqs.ui.fragment.BaseFragment
/**
* 离线地图总页面
*/
class OfflineMapFragment : Fragment() {
class OfflineMapFragment : BaseFragment() {
private var _binding: FragmentOfflineMapBinding? = null

View File

@ -24,6 +24,7 @@ import com.navinfo.omqs.db.ImportOMDBHelper
import com.navinfo.omqs.hilt.ImportOMDBHiltFactory
import com.navinfo.omqs.tools.CoroutineUtils
import com.navinfo.omqs.ui.activity.BaseActivity
import com.navinfo.omqs.ui.fragment.BaseFragment
import dagger.hilt.android.AndroidEntryPoint
import io.realm.Realm
import io.realm.RealmDictionary
@ -40,12 +41,13 @@ import javax.inject.Inject
* 个人中心
*/
@AndroidEntryPoint
class PersonalCenterFragment : Fragment(), FSAFActivityCallbacks {
class PersonalCenterFragment : BaseFragment(), FSAFActivityCallbacks {
private var _binding: FragmentPersonalCenterBinding? = null
private val binding get() = _binding!!
private val fileChooser by lazy { FileChooser(requireContext()) }
private val viewModel by lazy { viewModels<PersonalCenterViewModel>().value }
@Inject
lateinit var importOMDBHiltFactory: ImportOMDBHiltFactory
@Inject
@ -65,9 +67,9 @@ class PersonalCenterFragment : Fragment(), FSAFActivityCallbacks {
binding.root.setNavigationItemSelectedListener {
when (it.itemId) {
R.id.personal_center_menu_offline_map ->
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
findNavController().navigate(R.id.OfflineMapFragment)
R.id.personal_center_menu_obtain_data -> { // 生成数据根据sqlite文件生成对应的zip文件
fileChooser.openChooseFileDialog(object: FileChooserCallback() {
fileChooser.openChooseFileDialog(object : FileChooserCallback() {
override fun onCancel(reason: String) {
}
@ -75,31 +77,47 @@ class PersonalCenterFragment : Fragment(), FSAFActivityCallbacks {
val file = UriUtils.uri2File(uri)
// 开始导入数据
// 656e6372797000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
val job = CoroutineUtils.launchWithLoading(requireContext(), loadingMessage = "生成数据...") {
val importOMDBHelper: ImportOMDBHelper = importOMDBHiltFactory.obtainImportOMDBHelper(requireContext(), file, File(file.parentFile, "config.json"))
val job = CoroutineUtils.launchWithLoading(
requireContext(),
loadingMessage = "生成数据..."
) {
val importOMDBHelper: ImportOMDBHelper =
importOMDBHiltFactory.obtainImportOMDBHelper(
requireContext(),
file,
File(file.parentFile, "config.json")
)
viewModel.obtainOMDBZipData(importOMDBHelper)
}
}
})
}
R.id.personal_center_menu_import_data -> { // 导入zip数据
fileChooser.openChooseFileDialog(object: FileChooserCallback() {
fileChooser.openChooseFileDialog(object : FileChooserCallback() {
override fun onCancel(reason: String) {
}
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"))
CoroutineUtils.launchWithLoading(
requireContext(),
loadingMessage = "导入数据..."
) {
val importOMDBHelper: ImportOMDBHelper =
importOMDBHiltFactory.obtainImportOMDBHelper(
requireContext(),
file,
File(file.parentFile, "config.json")
)
viewModel.importOMDBData(importOMDBHelper)
}
}
})
}
R.id.personal_center_menu_import_yuan_data->{
R.id.personal_center_menu_import_yuan_data -> {
// 用户选中导入数据,打开文件选择器,用户选择导入的数据文件目录
fileChooser.openChooseFileDialog(object: FileChooserCallback() {
fileChooser.openChooseFileDialog(object : FileChooserCallback() {
override fun onCancel(reason: String) {
}
@ -114,6 +132,9 @@ class PersonalCenterFragment : Fragment(), FSAFActivityCallbacks {
// 定位到指定位置
niMapController.mMapView.vtmMap.animator().animateTo(GeoPoint(28.608398, 115.67901))
}
R.id.personal_center_menu_task_list -> {
findNavController().navigate(R.id.TaskListFragment)
}
}
true
}

View File

@ -185,15 +185,16 @@ class PersonalCenterViewModel @Inject constructor(
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())
}
// val cellCount: Int = row.physicalNumberOfCells // 获取列数
val bean = ScProblemTypeBean(
elementType = row.getCell(0).stringCellValue,
elementCode = row.getCell(1).numericCellValue.toString(),
classType = row.getCell(2).stringCellValue,
problemType = row.getCell(3).stringCellValue,
phenomenon = row.getCell(4).stringCellValue
)
list.add(bean)
Log.e("jingo", bean.toString())
}
roomAppDatabase.getScProblemTypeDao().insertOrUpdateList(list)
}

View File

@ -0,0 +1,132 @@
package com.navinfo.omqs.ui.fragment.tasklist
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Observer
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.Companion.FileDownloadStatus
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder
/**
* 离线地图城市列表 RecyclerView 适配器
*
* RecycleView ViewHolder 中监听 ViewModel LiveData然后此时传递的 lifecycleOwner 是对应的 Fragment由于 ViewHolder 的生命周期是比 Fragment 短的所以当 ViewHolder 销毁时由于 Fragment Lifecycle 还没有结束此时 ViewHolder 会发生内存泄露监听的 LiveData 没有解绑
* 这种场景下有两种解决办法
*使用 LiveData observeForever 然后在 ViewHolder 销毁前手动调用 removeObserver
*使用 LifecycleRegistry ViewHolder 分发生命周期(这里使用了这个)
*/
class TaskListAdapter(
private val downloadManager: TaskDownloadManager, private val context: Context
) : BaseRecyclerViewAdapter<TaskBean>() {
private val downloadBtnClick = View.OnClickListener() {
if (it.tag != null) {
val taskBean = data[it.tag as Int]
when (taskBean.status) {
FileDownloadStatus.NONE, FileDownloadStatus.UPDATE, FileDownloadStatus.PAUSE, FileDownloadStatus.ERROR -> {
Log.e("jingo", "开始下载 ${taskBean.status}")
downloadManager.start(taskBean.id)
}
FileDownloadStatus.LOADING, FileDownloadStatus.WAITING -> {
Log.e("jingo", "暂停 ${taskBean.status}")
downloadManager.pause(taskBean.id)
}
else -> {
Log.e("jingo", "暂停 ${taskBean.status}")
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
val viewBinding =
AdapterTaskListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return BaseViewHolder(viewBinding)
}
override fun onViewRecycled(holder: BaseViewHolder) {
super.onViewRecycled(holder)
//页面滑动时会用holder重构页面但是对进度条的监听回调会一直返回扰乱UI所以当当前holder去重构的时候移除监听
downloadManager.removeObserver(holder.tag.toInt())
}
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
val binding: AdapterTaskListBinding =
holder.viewBinding as AdapterTaskListBinding
val taskBean = data[position]
//tag 方便onclick里拿到数据
holder.tag = taskBean.id.toString()
changeViews(binding, taskBean)
downloadManager.addTask(taskBean)
downloadManager.observer(taskBean.id, holder, DownloadObserver(taskBean.id, binding))
binding.taskDownloadBtn.tag = position
binding.taskDownloadBtn.setOnClickListener(downloadBtnClick)
binding.taskName.text = taskBean.evaluationTaskName
// binding.offlineMapCitySize.text = cityBean.getFileSizeText()
}
inner class DownloadObserver(val id: Int, val binding: AdapterTaskListBinding) :
Observer<TaskBean> {
override fun onChanged(t: TaskBean?) {
if (id == t?.id)
changeViews(binding, t)
}
}
private fun changeViews(binding: AdapterTaskListBinding, cityBean: TaskBean) {
binding.taskProgress.progress =
(cityBean.currentSize * 100 / cityBean.fileSize).toInt()
when (cityBean.status) {
FileDownloadStatus.NONE -> {
if (binding.taskProgress.visibility == View.VISIBLE) binding.taskProgress.visibility =
View.INVISIBLE
binding.taskDownloadBtn.text = "下载"
}
FileDownloadStatus.WAITING -> {
if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
View.VISIBLE
binding.taskDownloadBtn.text = "等待中"
}
FileDownloadStatus.LOADING -> {
if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
View.VISIBLE
binding.taskDownloadBtn.text = "暂停"
}
FileDownloadStatus.PAUSE -> {
if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
View.VISIBLE
binding.taskDownloadBtn.text = "继续"
}
FileDownloadStatus.ERROR -> {
if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
View.VISIBLE
binding.taskDownloadBtn.text = "重试"
}
FileDownloadStatus.DONE -> {
if (binding.taskProgress.visibility == View.VISIBLE) binding.taskProgress.visibility =
View.INVISIBLE
binding.taskDownloadBtn.text = "已完成"
}
FileDownloadStatus.UPDATE -> {
if (binding.taskProgress.visibility == View.VISIBLE) binding.taskProgress.visibility =
View.INVISIBLE
binding.taskDownloadBtn.text = "更新"
}
}
}
override fun getItemViewRes(position: Int): Int {
return R.layout.adapter_offline_map_city
}
}

View File

@ -0,0 +1,55 @@
package com.navinfo.omqs.ui.fragment.tasklist
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import com.navinfo.omqs.databinding.FragmentTaskListBinding
import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
import com.navinfo.omqs.ui.fragment.BaseFragment
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class TaskListFragment : BaseFragment(){
@Inject
lateinit var downloadManager: TaskDownloadManager
private var _binding: FragmentTaskListBinding? = null
private val viewModel by viewModels<TaskListViewModel>()
private val binding get() = _binding!!
private val adapter: TaskListAdapter by lazy {
TaskListAdapter(
downloadManager,
requireContext()
)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentTaskListBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val layoutManager = LinearLayoutManager(context)
//// 设置 RecyclerView 的固定大小,避免在滚动时重新计算视图大小和布局,提高性能
binding.taskRecyclerview.setHasFixedSize(true)
binding.taskRecyclerview.layoutManager = layoutManager
binding.taskRecyclerview.adapter = adapter
viewModel.liveDataTaskList.observe(viewLifecycleOwner) {
adapter.refreshData(it)
}
viewModel.getTaskList(requireContext())
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@ -0,0 +1,61 @@
package com.navinfo.omqs.ui.fragment.tasklist
import android.content.Context
import android.util.Log
import android.widget.Toast
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.navinfo.omqs.bean.TaskBean
import com.navinfo.omqs.http.NetResult
import com.navinfo.omqs.http.NetworkService
import com.navinfo.omqs.tools.FileManager
import dagger.hilt.android.lifecycle.HiltViewModel
import io.realm.Realm
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
@HiltViewModel
class TaskListViewModel @Inject constructor(
private val networkService: NetworkService
) : ViewModel() {
val liveDataTaskList = MutableLiveData<List<TaskBean>>()
fun getTaskList(context: Context) {
viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
Log.e("jingo","realm hashCOde ${realm.hashCode()}")
when (val result = networkService.getTaskList("02911")) {
is NetResult.Success -> {
if (result.data != null) {
realm.executeTransaction {
realm.copyToRealmOrUpdate(result.data.obj)
}
}
}
is NetResult.Error -> {
withContext(Dispatchers.Main) {
Toast.makeText(context, "${result.exception.message}", Toast.LENGTH_SHORT)
.show()
}
}
is NetResult.Failure -> {
withContext(Dispatchers.Main) {
Toast.makeText(context, "${result.code}:${result.msg}", Toast.LENGTH_SHORT)
.show()
}
}
is NetResult.Loading -> {}
else -> {}
}
val objects = realm.where(TaskBean::class.java).findAll()
liveDataTaskList.postValue(realm.copyFromRealm(objects))
// realm.close()
}
}
}

View File

@ -0,0 +1,53 @@
package com.navinfo.omqs.ui.widget
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.widget.EditText
import androidx.appcompat.widget.AppCompatEditText
import com.navinfo.omqs.R
class MyEditeText @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = android.R.attr.editTextStyle //不这样写可能有些属性用不了
) : AppCompatEditText(context, attrs, defStyleAttr) {
init {
//Edittext通知父控件自己处理自己的滑动事件
setOnTouchListener { v, event ->
if (canVerticalScroll(this)) {
v.parent.requestDisallowInterceptTouchEvent(true)
if (event.action == MotionEvent.ACTION_UP) {
v.parent.requestDisallowInterceptTouchEvent(false)
}
}
false
}
}
/**
* EditText竖直方向是否可以滚动
*
* @param //editText需要判断的EditText
* @return true可以滚动 false不可以滚动
*/
private fun canVerticalScroll(contentEt: EditText): Boolean {
//滚动的距离
val scrollY = contentEt.scrollY
//控件内容的总高度
val scrollRange = contentEt.layout.height
//控件实际显示的高度
val scrollExtent =
contentEt.height - contentEt.compoundPaddingTop - contentEt.compoundPaddingBottom
//控件内容总高度与实际显示高度的差值
val scrollDifference = scrollRange - scrollExtent
if (scrollDifference == 0) {
return false
}
return (scrollY > 0) || (scrollY < scrollDifference - 1)
}
}

View File

@ -121,10 +121,9 @@
<fragment
android:id="@+id/main_activity_drawer_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="wrap_content"
android:layout_width="300dp"
android:layout_height="match_parent"
android:layout_gravity="left"
app:layout_constraintHorizontal_bias="0.3"
app:navGraph="@navigation/left_drawer_nav_graph" />
</androidx.drawerlayout.widget.DrawerLayout>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/cv_bg_color"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
tools:context="com.navinfo.omqs.ui.fragment.tasklist.TaskListAdapter">
<TextView
android:id="@+id/task_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="省市名称"
android:textColor="@color/white"
android:textSize="@dimen/default_font_size" />
<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_marginTop="5dp"
android:text="文件大小"
android:textSize="@dimen/card_title_font_3size" />
<TextView
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:shadowColor="@android:color/transparent"
android:text="下载"
android:textColor="@color/btn_blue_solid"
android:textSize="@dimen/card_title_font_2size" />
<TextView
android:id="@+id/task_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginBottom="10dp"
android:layout_toLeftOf="@id/task_download_btn"
android:clickable="true"
android:focusable="false"
android:shadowColor="@android:color/transparent"
android:textColor="@color/white"
android:textSize="@dimen/card_title_font_2size" />
<com.navinfo.omqs.ui.widget.MyProgressBar
android:id="@+id/task_progress"
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:paddingTop="10dp"
android:visibility="invisible" />
</RelativeLayout>

View File

@ -1,97 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".ui.fragment.evaluationresult.EvaluationResultFragment">
xmlns:tools="http://schemas.android.com/tools">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/evaluation_appbar_layout"
<data>
<variable
name="fragment"
type="com.navinfo.omqs.ui.fragment.evaluationresult.EvaluationResultFragment"
/>
<variable
name="viewModel"
type="com.navinfo.omqs.ui.fragment.evaluationresult.EvaluationResultViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".ui.fragment.evaluationresult.EvaluationResultFragment">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/evaluation_bar"
style="@style/Widget.MaterialComponents.Toolbar.Surface"
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/evaluation_appbar_layout"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/default_blue"
app:menu="@menu/evaluation_bar_mean"
app:navigationIcon="@drawable/btn_back_xml"
app:title="测评结果" />
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:padding="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/evaluation_appbar_layout">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="问题分类" />
<TextView
android:id="@+id/evaluation_class_type"
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/evaluation_bar"
style="@style/Widget.MaterialComponents.Toolbar.Surface"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@drawable/fm_card_map_down_status_bg" />
android:layout_height="?attr/actionBarSize"
android:background="@color/default_blue"
app:menu="@menu/evaluation_bar_mean"
app:navigationIcon="@drawable/btn_back_xml"
app:title="测评结果" />
<TextView
android:id="@+id/evaluation_problem_type"
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:padding="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/evaluation_appbar_layout">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@drawable/fm_card_map_down_status_bg" />
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/evaluation_phenomenon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@drawable/fm_card_map_down_status_bg" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="问题分类" />
<TextView
android:id="@+id/evaluation_link"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@drawable/fm_card_map_down_status_bg" />
<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:onClick="@{fragment.onClick}"
android:background="@drawable/fm_card_map_down_status_bg" />
<TextView
android:id="@+id/evaluation_cause"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@drawable/fm_card_map_down_status_bg" />
<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:onClick="@{fragment.onClick}"
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" />-->
<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:onClick="@{fragment.onClick}"
android:background="@drawable/fm_card_map_down_status_bg" />
<!-- <androidx.viewpager2.widget.ViewPager2-->
<!-- android:id="@+id/evaluation_viewpager"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent"-->
<!-- android:layout_marginTop="5dp" />-->
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<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:onClick="@{fragment.onClick}"
android:background="@drawable/fm_card_map_down_status_bg" />
</androidx.constraintlayout.widget.ConstraintLayout>
<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:onClick="@{fragment.onClick}"
android:background="@drawable/fm_card_map_down_status_bg" />
<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" />-->
<!-- <androidx.viewpager2.widget.ViewPager2-->
<!-- android:id="@+id/evaluation_viewpager"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent"-->
<!-- android:layout_marginTop="5dp" />-->
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -17,8 +17,10 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/offline_map_city_list_recyclerview"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/offline_map_search" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/offline_map_search"
app:layout_constraintVertical_bias="0.0"
tools:layout_editor_absoluteX="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".ui.fragment.tasklist.TaskListFragment">
<EditText
android:id="@+id/task_search"
style="@style/input_blue_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="搜索"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/task_recyclerview"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/task_search"
app:layout_constraintVertical_bias="0.0"
tools:layout_editor_absoluteX="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -32,6 +32,10 @@
android:checkableBehavior="single">
<item android:title="小标题">
<menu>
<item
android:id="@+id/personal_center_menu_task_list"
android:icon="@drawable/baseline_person_24"
android:title="任务列表" />
<item
android:id="@+id/personal_center_menu_offline_map3"
android:icon="@drawable/baseline_person_24"
@ -40,10 +44,7 @@
android:id="@+id/personal_center_menu_offline_map4"
android:icon="@drawable/baseline_person_24"
android:title="menu_gallery" />
<item
android:id="@+id/personal_center_menu_offline_map5"
android:icon="@drawable/baseline_person_24"
android:title="menu_slideshow" />
<item
android:id="@+id/personal_center_menu_test"
android:icon="@drawable/baseline_person_24"

View File

@ -13,16 +13,20 @@
<action
android:id="@+id/action_FirstFragment_to_SecondFragment"
app:destination="@id/SecondFragment" />
app:destination="@id/OfflineMapFragment" />
</fragment>
<fragment
android:id="@+id/SecondFragment"
android:id="@+id/OfflineMapFragment"
android:name="com.navinfo.omqs.ui.fragment.offlinemap.OfflineMapFragment"
android:label="@string/second_fragment_label"
android:label="离线地图"
tools:layout="@layout/fragment_offline_map">
<action
android:id="@+id/action_SecondFragment_to_FirstFragment"
app:destination="@id/PersonalCenterFragment" />
</fragment>
<fragment
android:id="@+id/TaskListFragment"
android:name="com.navinfo.omqs.ui.fragment.tasklist.TaskListFragment"
android:label="任务列表"
tools:layout="@layout/fragment_task_list">
</fragment>
</navigation>

View File

@ -15,5 +15,10 @@
android:id="@+id/EvaluationResultFragment"
android:name="com.navinfo.omqs.ui.fragment.evaluationresult.EvaluationResultFragment"
android:label="评测页面"
tools:layout="@layout/fragment_evaluation_result"></fragment>
tools:layout="@layout/fragment_evaluation_result">
<argument
android:name="QsId"
app:argType="string"
app:nullable="true" />
</fragment>
</navigation>

View File

@ -105,7 +105,7 @@ dependencies {
implementation "com.badlogicgames.gdx:gdx:1.11.0"
implementation "com.badlogicgames.gdx:gdx-backend-android:1.11.0"
implementation "com.caverock:androidsvg:1.4"
implementation "org.mapsforge:vtm-jts:$vtmVersion"
api "org.mapsforge:vtm-jts:$vtmVersion"
api 'org.locationtech.jts:jts-core:1.19.0'
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.11'
implementation 'com.squareup.okio:okio:3.3.0'

View File

@ -4,6 +4,7 @@ import com.navinfo.collect.library.utils.GeometryToolsKt
import io.realm.RealmObject
import io.realm.RealmSet
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
/**
@ -36,7 +37,7 @@ open class QsRecordBean @JvmOverloads constructor(
/**
* 问题类型
*/
var type: String = "",
var problemType: String = "",
/**
* 问题现象
@ -88,6 +89,27 @@ open class QsRecordBean @JvmOverloads constructor(
) : RealmObject() {
fun copy(): QsRecordBean {
val qs = QsRecordBean(
id = id,
elementId = elementId,
linkId = linkId,
classType = classType,
problemType = problemType,
phenomenon = phenomenon,
description = description,
problemLink = problemLink,
cause = cause,
checkUserId = checkUserId,
checkTime = checkTime,
confirmUserId = confirmUserId,
t_lifecycle = t_lifecycle,
t_status = t_status,
)
qs.geometry = geometry
return qs
}
private val tileX = RealmSet<Int>() // x方向的tile编码
private val tileY = RealmSet<Int>() // y方向的tile编码

View File

@ -10,15 +10,7 @@ import org.oscim.layers.marker.MarkerItem
*10:51
*说明
*/
class ClusterMarkerItem(uid: Any?, title: String?, description: String?, geoPoint: GeoPoint?) :
class ClusterMarkerItem(uid: Any, title: String?, description: String?, geoPoint: GeoPoint) :
MarkerItem(uid, title, description, geoPoint) {
var clusterList: List<Int> = ArrayList()
constructor(title: String?, description: String?, geoPoint: GeoPoint?) : this(
null,
title,
description,
geoPoint
) {
}
}

View File

@ -4,6 +4,7 @@ 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
@ -42,6 +43,7 @@ import org.oscim.layers.tile.vector.VectorTileLayer
import org.oscim.layers.tile.vector.labeling.LabelLayer
import org.oscim.layers.tile.vector.labeling.LabelTileLoaderHook
import org.oscim.map.Map
import org.oscim.map.Map.UpdateListener
import org.oscim.tiling.source.OkHttpEngine.OkHttpFactory
import org.oscim.tiling.source.mapfile.MapFileTileSource
import java.io.File
@ -69,7 +71,8 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
private lateinit var canvas: org.oscim.backend.canvas.Canvas
private lateinit var itemizedLayer: MyItemizedLayer
private lateinit var markerRendererFactory: MarkerRendererFactory
private val markerItemsNames = mutableListOf<MarkerInterface>()
private var resId = R.mipmap.map_icon_point_add
private var itemListener: OnQsRecordItemClickListener? = null
/**
* 轨迹渲染图层
@ -97,14 +100,6 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
init {
initMap()
mMapView.vtmMap.events.bind(Map.UpdateListener { e, mapPosition ->
val isOmdbZoom = mapPosition.zoomLevel>=Constant.OMDB_MIN_ZOOM
baseGroupLayer?.layers?.forEach {
it.isEnabled = !isOmdbZoom
}
omdbVectorTileLayer.isEnabled = isOmdbZoom
omdbLabelLayer.isEnabled = isOmdbZoom
})
}
/**
@ -113,6 +108,8 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
private fun initMap() {
loadBaseMap()
//初始化之间数据图层
initQsRecordDataLayer()
initOMDBVectorTileLayer()
@ -137,8 +134,23 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
//初始化之间数据图层
initQsRecordDataLayer()
mMapView.vtmMap.updateMap()
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() {
@ -210,7 +222,47 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
for (layer in it.layers) {
addLayer(layer, NIMapView.LAYER_GROUPS.BASE)
}
mMapView.updateMap()
}
}
mMapView.switchTileVectorLayerTheme(NIMapView.MAP_THEME.DEFAULT)
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
}
}
}
}
@ -219,6 +271,7 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
* 初始话质检数据图层
*/
private fun initQsRecordDataLayer() {
canvas = CanvasAdapter.newCanvas()
paint = CanvasAdapter.newPaint()
paint.setTypeface(Paint.FontFamily.DEFAULT, Paint.FontStyle.NORMAL)
@ -248,50 +301,68 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
}
}
var resId = R.mipmap.map_icon_point_add
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()
itemizedLayer =
MyItemizedLayer(
mMapView.vtmMap,
mutableListOf(),
markerRendererFactory,
object : MyItemizedLayer.OnItemGestureListener {
override fun onItemSingleTapUp(
layer: MyItemizedLayer?,
list: MutableList<Int>?,
nearest: Int
): Boolean {
return true
}
override fun onItemLongPress(
layer: MyItemizedLayer?,
list: MutableList<Int>?,
nearest: Int
): Boolean {
return true
}
})
// realm.close()
for (item in list) {
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)
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) {
@ -320,14 +391,14 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
// dataVectorLayer.add(drawablePolygon)
// }
// }
}
}
if (geoPoint != null) {
var geoMarkerItem: MarkerItem
}
}
if (geoPoint != null) {
var geoMarkerItem: MarkerItem
// if (item.getType() === 1) {
geoMarkerItem = ClusterMarkerItem(
1, item.id, item.description, geoPoint
)
geoMarkerItem = ClusterMarkerItem(
1, item.id, item.description, geoPoint
)
// } else {
// geoMarkerItem = MarkerItem(
// ePointTemp.getType(),
@ -336,22 +407,17 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
// geoPoint
// )
// }
markerItemsNames.add(geoMarkerItem)
val markerSymbol =
MarkerSymbol(bitmap, MarkerSymbol.HotspotPlace.CENTER)
geoMarkerItem.marker = markerSymbol
}
}
val markerSymbol =
MarkerSymbol(bitmap, MarkerSymbol.HotspotPlace.CENTER)
geoMarkerItem.marker = markerSymbol
itemizedLayer.itemList.add(geoMarkerItem)
}
}
itemizedLayer.addItems(markerItemsNames)
addLayer(itemizedLayer, NIMapView.LAYER_GROUPS.OPERATE)
withContext(Dispatchers.Main) {
itemizedLayer.map().updateMap(true)
}
}
itemizedLayer.populate()
}
/**
* 文字和图片拼装文字换行
*
@ -573,8 +639,12 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
vectorNiLocationTileLayer.isEnabled = false
labelNiLocationLayer.isEnabled = false
}
}
interface OnQsRecordItemClickListener {
fun onQsRecordList(list: MutableList<String>)
}
/**
* 基础

View File

@ -50,7 +50,7 @@ public class MyItemizedLayer extends ItemizedLayer {
public boolean run(List list1, int nearest) {
if (mOnItemGestureListener != null) {
return mOnItemGestureListener.onItemSingleTapUp(MyItemizedLayer.this, list1, nearest);
return mOnItemGestureListener.onItemSingleTapUp(list1, nearest);
}
return false;
}
@ -62,7 +62,7 @@ public class MyItemizedLayer extends ItemizedLayer {
public boolean run(List list1, int nearest) {
if (mOnItemGestureListener != null) {
return mOnItemGestureListener.onItemLongPress(MyItemizedLayer.this, list1, nearest);
return mOnItemGestureListener.onItemLongPress(list1, nearest);
}
return false;
}
@ -155,8 +155,8 @@ public class MyItemizedLayer extends ItemizedLayer {
}
public interface OnItemGestureListener {
boolean onItemSingleTapUp(MyItemizedLayer layer, List<Integer> list, int nearest);
boolean onItemSingleTapUp(List<Integer> list, int nearest);
boolean onItemLongPress(MyItemizedLayer layer, List<Integer> list, int nearest);
boolean onItemLongPress(List<Integer> list, int nearest);
}
}