Merge branch 'master' of https://gitlab.navinfo.com/CollectVehicle/OneMapQS
Conflicts: app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt
This commit is contained in:
commit
e72cc87475
@ -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>
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
@ -25,12 +26,11 @@ class OMQSApplication : Application() {
|
||||
val password = "encryp".encodeToByteArray().copyInto(ByteArray(64))
|
||||
// 656e6372797000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
Log.d("OMQSApplication", "密码是: ${byteArrayToHexString(password)}")
|
||||
// 1110000011000010111001101110011011101110110111101110010011001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
val config = RealmConfiguration.Builder()
|
||||
.directory(File(Constant.DATA_PATH))
|
||||
.name("OMQS.realm")
|
||||
.encryptionKey(password)
|
||||
// .modules(Realm.getDefaultModule(), MyRealmModule())
|
||||
.modules(Realm.getDefaultModule(), MyRealmModule())
|
||||
.schemaVersion(1)
|
||||
.build()
|
||||
Realm.setDefaultConfiguration(config)
|
||||
|
21
app/src/main/java/com/navinfo/omqs/bean/HadLinkDvoBean.kt
Normal file
21
app/src/main/java/com/navinfo/omqs/bean/HadLinkDvoBean.kt
Normal 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()
|
@ -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() {
|
||||
|
@ -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
|
64
app/src/main/java/com/navinfo/omqs/bean/TaskBean.kt
Normal file
64
app/src/main/java/com/navinfo/omqs/bean/TaskBean.kt
Normal 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"
|
||||
}
|
||||
}
|
@ -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 {
|
||||
}
|
@ -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,无法检测生命周期,
|
||||
|
@ -0,0 +1,7 @@
|
||||
package com.navinfo.omqs.http
|
||||
|
||||
class DefaultTaskResponse<T> {
|
||||
var success: Boolean = false
|
||||
var msg: String = ""
|
||||
var obj: T? = null
|
||||
}
|
@ -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>>>
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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注解
|
||||
|
@ -112,6 +112,4 @@ class OfflineMapDownloadManager(
|
||||
scopeMap[id]!!.removeObserver()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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()
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
// }
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ open class PermissionsActivity : BaseActivity() {
|
||||
permissionList.add(Permission.ACCESS_COARSE_LOCATION)
|
||||
//android10
|
||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
|
||||
permissionList.add(Permission.ACCESS_BACKGROUND_LOCATION)
|
||||
// permissionList.add(Permission.ACCESS_BACKGROUND_LOCATION)
|
||||
}
|
||||
XXPermissions.with(this)
|
||||
// 申请单个权限
|
||||
|
@ -4,9 +4,10 @@ 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.blankj.utilcode.util.ToastUtils
|
||||
import com.navinfo.collect.library.map.NIMapController
|
||||
import com.navinfo.collect.library.map.handler.NiLocationListener
|
||||
import com.navinfo.omqs.Constant
|
||||
@ -15,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
|
||||
|
||||
@ -53,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() {
|
||||
@ -67,7 +74,11 @@ class MainActivity : BaseActivity() {
|
||||
ToastUtils.showLong("定位${it.longitude}")
|
||||
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()
|
||||
}
|
||||
|
||||
@ -110,7 +121,7 @@ class MainActivity : BaseActivity() {
|
||||
naviController.navigate(R.id.EvaluationResultFragment)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
super.onBackPressed()
|
||||
}
|
||||
// override fun onBackPressed() {
|
||||
// super.onBackPressed()
|
||||
// }
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 = ""
|
||||
|
@ -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 = ""
|
||||
|
@ -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 {
|
||||
|
@ -1,6 +0,0 @@
|
||||
package com.navinfo.omqs.ui.fragment.evaluationresult
|
||||
|
||||
/**
|
||||
* 问题现象列表
|
||||
*/
|
||||
data class PhenomenonMiddleBean(val title: String, val text: String, var isSelect: Boolean = false)
|
@ -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 {
|
||||
|
@ -0,0 +1,6 @@
|
||||
package com.navinfo.omqs.ui.fragment.evaluationresult
|
||||
|
||||
/**
|
||||
* 问题现象列表
|
||||
*/
|
||||
data class RightBean(val title: String, val text: String, var isSelect: Boolean = false)
|
@ -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) {
|
@ -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 {
|
@ -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 = "更新"
|
||||
|
@ -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
|
||||
|
||||
|
@ -23,6 +23,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
|
||||
@ -38,12 +39,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
|
||||
|
||||
@ -61,9 +63,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) {
|
||||
}
|
||||
|
||||
@ -71,31 +73,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) {
|
||||
}
|
||||
|
||||
@ -108,6 +126,9 @@ class PersonalCenterFragment : Fragment(), FSAFActivityCallbacks {
|
||||
R.id.personal_center_menu_test -> {
|
||||
viewModel.readRealmData()
|
||||
}
|
||||
R.id.personal_center_menu_task_list -> {
|
||||
findNavController().navigate(R.id.TaskListFragment)
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
@ -184,15 +184,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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
53
app/src/main/java/com/navinfo/omqs/ui/widget/MyEditeText.kt
Normal file
53
app/src/main/java/com/navinfo/omqs/ui/widget/MyEditeText.kt
Normal 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)
|
||||
}
|
||||
|
||||
}
|
@ -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>
|
||||
|
67
app/src/main/res/layout/adapter_task_list.xml
Normal file
67
app/src/main/res/layout/adapter_task_list.xml
Normal 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>
|
@ -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>
|
@ -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>
|
27
app/src/main/res/layout/fragment_task_list.xml
Normal file
27
app/src/main/res/layout/fragment_task_list.xml
Normal 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>
|
@ -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"
|
||||
|
@ -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>
|
@ -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>
|
@ -101,7 +101,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'
|
||||
|
@ -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编码
|
||||
|
@ -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
|
||||
) {
|
||||
}
|
||||
}
|
@ -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
|
||||
@ -31,11 +32,15 @@ import org.oscim.backend.canvas.Bitmap
|
||||
import org.oscim.backend.canvas.Paint
|
||||
import org.oscim.core.GeoPoint
|
||||
import org.oscim.layers.GroupLayer
|
||||
import org.oscim.layers.marker.*
|
||||
import org.oscim.layers.marker.MarkerInterface
|
||||
import org.oscim.layers.marker.MarkerItem
|
||||
import org.oscim.layers.marker.MarkerRendererFactory
|
||||
import org.oscim.layers.marker.MarkerSymbol
|
||||
import org.oscim.layers.tile.buildings.BuildingLayer
|
||||
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.UpdateListener
|
||||
import org.oscim.tiling.source.OkHttpEngine.OkHttpFactory
|
||||
import org.oscim.tiling.source.mapfile.MapFileTileSource
|
||||
import java.io.File
|
||||
@ -63,7 +68,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
|
||||
|
||||
/**
|
||||
* 轨迹渲染图层
|
||||
@ -95,6 +101,8 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
|
||||
private fun initMap() {
|
||||
|
||||
loadBaseMap()
|
||||
//初始化之间数据图层
|
||||
initQsRecordDataLayer()
|
||||
|
||||
mapLifeNiLocationTileSource = MapLifeNiLocationTileSource(mContext, mTracePath)
|
||||
|
||||
@ -114,12 +122,15 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
|
||||
|
||||
mMapView.switchTileVectorLayerTheme(NIMapView.MAP_THEME.DEFAULT)
|
||||
|
||||
//初始化之间数据图层
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -180,7 +191,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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -189,6 +240,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)
|
||||
@ -218,50 +270,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) {
|
||||
@ -290,14 +360,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(),
|
||||
@ -306,22 +376,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()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 文字和图片拼装,文字换行
|
||||
*
|
||||
@ -543,8 +608,12 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
|
||||
vectorNiLocationTileLayer.isEnabled = false
|
||||
labelNiLocationLayer.isEnabled = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface OnQsRecordItemClickListener {
|
||||
fun onQsRecordList(list: MutableList<String>)
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user