fix: 合并代码

This commit is contained in:
xiaoyan 2023-07-26 15:29:13 +08:00
commit 7ad3fcbbb4
133 changed files with 9118 additions and 2296 deletions

View File

@ -127,6 +127,14 @@ dependencies {
implementation "androidx.camera:camera-view:1.0.0-alpha24"
implementation 'com.google.mlkit:barcode-scanning:16.1.1'
//
implementation 'com.github.bumptech.glide:glide:4.15.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.15.1'
// implementation "io.realm:realm-kotlin-extensions:6.1.0"
//
implementation 'com.yanzhenjie.recyclerview:x:1.3.2'
}
//
kapt {

View File

@ -1,29 +1,46 @@
{
"tableMap" : {
"1012": {
"table": "OMDB_CHECKPOINT",
"code": 1012,
"name": "检查点",
"zoomMin": 18,
"zoomMax": 23
},
"2001": {
"table": "OMDB_RD_LINK",
"code": 2001,
"name": "道路线"
"name": "道路线",
"zoomMin": 18,
"zoomMax": 19
},
"2002": {
"table": "OMDB_RD_LINK_FUNCTION_CLASS",
"code": 2002,
"name": "道路功能等级"
"name": "道路功能等级",
"zoomMin": 18,
"zoomMax": 19
},
"2008": {
"table": "OMDB_RD_LINK_KIND",
"code": 2008,
"name": "道路种别"
"name": "道路种别",
"zoomMin": 18,
"zoomMax": 19
},
"2010": {
"table": "OMDB_LINK_DIRECT",
"code": 2010,
"name": "道路方向"
"name": "道路方向",
"zoomMin": 18,
"zoomMax": 19
},
"2011": {
"table": "OMDB_LINK_NAME",
"code": 2011,
"name": "道路名",
"zoomMin": 18,
"zoomMax": 19,
"transformer": [
{
"k": "geometry",
@ -37,6 +54,8 @@
"table": "OMDB_LANE_MARK_BOUNDARYTYPE",
"code": 2013,
"name": "车道边界类型",
"zoomMin": 20,
"zoomMax": 23,
"transformer": [
{
"k": "geometry",
@ -49,17 +68,23 @@
"2019": {
"table": "OMDB_LINK_SPEEDLIMIT",
"code": 2019,
"name": "常规线限速"
"name": "常规线限速",
"zoomMin": 18,
"zoomMax": 19
},
"2020": {
"table": "OMDB_LINK_SPEEDLIMIT_COND",
"code": 2020,
"name": "条件线限速"
"name": "条件线限速",
"zoomMin": 18,
"zoomMax": 19
},
"2021": {
"table": "OMDB_LINK_SPEEDLIMIT_VAR",
"code": 2021,
"name": "可变线限速"
"name": "可变线限速",
"zoomMin": 18,
"zoomMax": 19
},
"2022": {
"table": "OMDB_CON_ACCESS",
@ -84,7 +109,9 @@
"2083":{
"table": "OMDB_RDBOUND_BOUNDARYTYPE",
"code": 2083,
"name": "道路边界类型"
"name": "道路边界类型",
"zoomMin": 20,
"zoomMax": 23
},
"2201":{
"table": "OMDB_BRIDGE",
@ -94,12 +121,24 @@
"2202":{
"table": "OMDB_TUNNEL",
"code": 2202,
"name": "隧道"
"name": "隧道",
"zoomMin": 18,
"zoomMax": 23,
"transformer": [
{
"k": "geometry",
"v": "~",
"klib": "geometry",
"vlib": "generateS2EReferencePoint()"
}
]
},
"4001": {
"table": "OMDB_INTERSECTION",
"code": 4001,
"name": "路口",
"zoomMin": 18,
"zoomMax": 19,
"transformer": [
{
"k": "geometry",
@ -113,6 +152,8 @@
"table": "OMDB_SPEEDLIMIT",
"code": 4002,
"name": "常规点限速",
"zoomMin": 18,
"zoomMax": 23,
"transformer": [
{
"k": "maxSpeed",
@ -132,6 +173,8 @@
"table": "OMDB_SPEEDLIMIT_COND",
"code": 4003,
"name": "条件点限速",
"zoomMin": 18,
"zoomMax": 23,
"transformer": [
{
"k": "maxSpeed",
@ -145,6 +188,8 @@
"table": "OMDB_SPEEDLIMIT_VAR",
"code": 4004,
"name": "可变点限速",
"zoomMin": 18,
"zoomMax": 23,
"transformer": [
{
"k": "location",
@ -170,6 +215,8 @@
"table": "OMDB_RESTRICTION",
"code": 4006,
"name": "普通交限",
"zoomMin": 18,
"zoomMax": 23,
"transformer": [
{
"k": "geometry",
@ -207,6 +254,8 @@
"table": "OMDB_ELECTRONICEYE",
"code": 4010,
"name": "电子眼",
"zoomMin": 18,
"zoomMax": 23,
"transformer": [
{
"k": "geometry",
@ -238,6 +287,8 @@
"table": "OMDB_TRAFFICLIGHT",
"code": 4022,
"name": "交通灯",
"zoomMin": 18,
"zoomMax": 23,
"transformer": [
]
},
@ -245,6 +296,8 @@
"table": "OMDB_LANEINFO",
"code": 4601,
"name": "车信",
"zoomMin": 18,
"zoomMax": 19,
"transformer": [
{
"k": "geometry",
@ -269,7 +322,17 @@
"5001":{
"table": "OMDB_LANE_LINK_LG",
"code": 5001,
"name": "车道中心线"
"name": "车道中心线",
"zoomMin": 20,
"zoomMax": 23,
"transformer": [
{
"k": "geometry",
"v": "~",
"klib": "geometry",
"vlib": "generateAddWidthLine()"
}
]
},
"5002":{
"table": "OMDB_AREA",

View File

@ -24,6 +24,11 @@ class Constant {
*/
lateinit var USER_ID: String
/**
* 当前用户名称
*/
lateinit var USER_REAL_NAME: String
//数据版本
lateinit var VERSION_ID: String
@ -55,10 +60,20 @@ class Constant {
/**
* 室内整理工具IP
*/
lateinit var INDOOR_IP: String
var INDOOR_IP: String = ""
const val DEBUG = true
/**
* 地图最多缩放级别23
*/
const val MAX_ZOOM = 23
/**
* 是否自动定位
*/
var AUTO_LOCATION = false
var IS_VIDEO_SPEED by kotlin.properties.Delegates.notNull<Boolean>()
const val message_status_late = "预约,待发送"
@ -92,6 +107,10 @@ class Constant {
val OMDB_LAYER_VISIBLE_LIST: MutableList<String> = mutableListOf() // 记录OMDB数据显示的图层名称列表
const val EVENT_LAYER_MANAGER_CHANGE = "EVENT_LAYER_MANAGER_CHANGE" // 图层管理中的配置修改
const val SELECT_TASK_ID = "select_task_id" //选中的任务ID
const val SHARED_SYNC_TASK_LINK_ID = "shared_sync_task_link_id"//利用shared通知任务页面更新
}

View File

@ -51,10 +51,10 @@ data class EvaluationInfo(
val evaluationWay: Int = 2,//测评方式 1生产测评 2现场测评 服务字段定义为Integer使用包装类对应无值情况为空
@SerializedName("roadClassfcation")
val roadClassfcation: String = "",//道路种别
val roadClassfcation: Int = 1,//道路种别
@SerializedName("roadFunctionGrade")
val roadFunctionGrade: String = "",//道路功能等级
val roadFunctionGrade: Int = 1,//道路功能等级
@SerializedName("noEvaluationreason")
val noEvaluationreason: String = "",//未测评原因
@ -63,7 +63,7 @@ data class EvaluationInfo(
val linkLength: Double = 0.0,//link长度(m 保留3位小数)
@SerializedName("dataLevel")
val dataLevel: String = "",//数据级别
val dataLevel: Int = 1,//数据级别
@SerializedName("linstringLength")
val linstringLength: Double = 0.0,//错误要素长度m

View File

@ -115,6 +115,8 @@ class ImportConfig {
class TableInfo {
val table: String = ""
val code: Int = 0
val zoomMin: Int = 18
val zoomMax: Int = 23
val name: String = ""
var checked : Boolean = true
var transformer: MutableList<Transform> = mutableListOf()

View File

@ -2,5 +2,5 @@ package com.navinfo.omqs.bean
data class QRCodeBean(
var errcode: Int = -1,
var msg: String = ""
var errmsg: String = ""
)

View File

@ -0,0 +1,8 @@
package com.navinfo.omqs.bean
data class TraceVideoBean(
var userid: String = "",
var playMode: String = "",
var time: String = "",
var command: String = "",
)

View File

@ -5,23 +5,19 @@ import android.database.Cursor.*
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.database.getBlobOrNull
import androidx.core.database.getFloatOrNull
import androidx.core.database.getIntOrNull
import androidx.core.database.getStringOrNull
import com.blankj.utilcode.util.FileIOUtils
import com.blankj.utilcode.util.ZipUtils
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.navinfo.collect.library.data.entity.ReferenceEntity
import com.navinfo.collect.library.data.entity.RenderEntity
import com.navinfo.omqs.Constant
import com.navinfo.omqs.bean.ImportConfig
import com.navinfo.omqs.bean.Transform
import com.navinfo.omqs.hilt.ImportOMDBHiltFactory
import com.navinfo.omqs.hilt.OMDBDataBaseHiltFactory
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.realm.Realm
import io.realm.RealmQuery
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
@ -127,7 +123,7 @@ class ImportOMDBHelper @AssistedInject constructor(
* @param omdbZipFile omdb数据抽取生成的Zip文件
* @param configFile 对应的配置文件
* */
suspend fun importOmdbZipFile(omdbZipFile: File): Flow<String> = withContext(Dispatchers.IO) {
suspend fun importOmdbZipFile(omdbZipFile: File, taskId: Int): Flow<String> = withContext(Dispatchers.IO) {
val unZipFolder = File(omdbZipFile.parentFile, "result")
flow {
if (unZipFolder.exists()) {
@ -137,8 +133,9 @@ class ImportOMDBHelper @AssistedInject constructor(
// 开始解压zip文件
val unZipFiles = ZipUtils.unzipFile(omdbZipFile, unZipFolder)
// 将listResult数据插入到Realm数据库中
val realm = Realm.getDefaultInstance()
realm.beginTransaction()
try {
Realm.getDefaultInstance().beginTransaction()
// 遍历解压后的文件,读取该数据返回
for ((index, currentEntry) in importConfig.tableMap.entries.withIndex()) {
val currentConfig = currentEntry.value
@ -161,7 +158,11 @@ class ImportOMDBHelper @AssistedInject constructor(
.toMutableMap()
map["qi_table"] = currentConfig.table
map["qi_name"] = currentConfig.name
map["qi_code"] =
if (currentConfig.code == 0) currentConfig.code else currentEntry.key
map["qi_code"] = if (currentConfig.code == 0) currentConfig.code else currentEntry.key
map["qi_zoomMin"] = currentConfig.zoomMin
map["qi_zoomMax"] = currentConfig.zoomMax
// 先查询这个mesh下有没有数据如果有则跳过即可
// val meshEntity = Realm.getDefaultInstance().where(RenderEntity::class.java).equalTo("properties['mesh']", map["mesh"].toString()).findFirst()
@ -169,21 +170,31 @@ class ImportOMDBHelper @AssistedInject constructor(
renderEntity.code = map["qi_code"].toString().toInt()
renderEntity.name = map["qi_name"].toString()
renderEntity.table = map["qi_table"].toString()
renderEntity.taskId = taskId
renderEntity.zoomMin = map["qi_zoomMin"].toString().toInt()
renderEntity.zoomMax = map["qi_zoomMax"].toString().toInt()
// 其他数据插入到Properties中
renderEntity.geometry = map["geometry"].toString()
for ((key, value) in map) {
when (value) {
is String -> renderEntity.properties.put(key, value)
is Int -> renderEntity.properties.put(key, value.toInt().toString())
is Double -> renderEntity.properties.put(key, value.toDouble().toString())
is Int -> renderEntity.properties.put(
key,
value.toInt().toString()
)
is Double -> renderEntity.properties.put(
key,
value.toDouble().toString()
)
else -> renderEntity.properties.put(key, value.toString())
}
}
listResult.add(renderEntity)
// 对renderEntity做预处理后再保存
val resultEntity = importConfig.transformProperties(renderEntity)
if (resultEntity!=null) {
Realm.getDefaultInstance().insert(renderEntity)
if (resultEntity != null) {
realm.insert(renderEntity)
}
}
}
@ -192,12 +203,14 @@ class ImportOMDBHelper @AssistedInject constructor(
emit("${index + 1}/${importConfig.tableMap.size}")
// 如果当前解析的是OMDB_RD_LINK数据将其缓存在预处理类中以便后续处理其他要素时使用
if (currentConfig.table == "OMDB_RD_LINK") {
importConfig.preProcess.cacheRdLink = listResult.associateBy { it.properties["linkPid"] }
importConfig.preProcess.cacheRdLink =
listResult.associateBy { it.properties["linkPid"] }
}
}
Realm.getDefaultInstance().commitTransaction()
realm.commitTransaction()
realm.close()
} catch (e: Exception) {
Realm.getDefaultInstance().cancelTransaction()
realm.cancelTransaction()
throw e
}
emit("finish")

View File

@ -158,6 +158,10 @@ class ImportPreProcess {
startEndReference.renderEntityId = renderEntity.id
startEndReference.name = "${renderEntity.name}参考线"
startEndReference.table = renderEntity.table
startEndReference.zoomMin = renderEntity.zoomMin
startEndReference.zoomMax = renderEntity.zoomMax
startEndReference.taskId = renderEntity.taskId
// 起终点坐标组成的线
startEndReference.geometry = GeometryTools.createLineString(arrayOf<Coordinate>(pointStart, pointEnd)).toString()
startEndReference.properties["qi_table"] = renderEntity.table
@ -165,6 +169,42 @@ class ImportPreProcess {
Realm.getDefaultInstance().insert(startEndReference)
}
fun generateS2EReferencePoint(renderEntity: RenderEntity) {
val geometry = GeometryTools.createGeometry(renderEntity.properties["geometry"])
val pointEnd = geometry!!.coordinates[geometry.numPoints-1] // 获取这个geometry对应的结束点坐标
val pointStart = geometry!!.coordinates[0] // 获取这个geometry对应的起点
// 将这个起终点的线记录在数据中
val startReference = ReferenceEntity()
startReference.renderEntityId = renderEntity.id
startReference.name = "${renderEntity.name}参考线"
startReference.table = renderEntity.table
startReference.zoomMin = renderEntity.zoomMin
startReference.zoomMax = renderEntity.zoomMax
startReference.taskId = renderEntity.taskId
// 起点坐标
startReference.geometry = GeometryTools.createGeometry(GeoPoint(pointStart.y,pointStart.x)).toString()
startReference.properties["qi_table"] = renderEntity.table
startReference.properties["type"] = "s_2_p"
Realm.getDefaultInstance().insert(startReference)
val endReference = ReferenceEntity()
endReference.renderEntityId = renderEntity.id
endReference.name = "${renderEntity.name}参考线"
endReference.table = renderEntity.table
endReference.zoomMin = renderEntity.zoomMin
endReference.zoomMax = renderEntity.zoomMax
endReference.taskId = renderEntity.taskId
// 终点坐标
endReference.geometry = GeometryTools.createGeometry(GeoPoint(pointEnd.y,pointEnd.x)).toString()
endReference.properties["qi_table"] = renderEntity.table
endReference.properties["type"] = "e_2_p"
Realm.getDefaultInstance().insert(endReference)
}
/**
* 生成与对应方向相同的方向线用以绘制方向箭头
* */
@ -211,6 +251,9 @@ class ImportPreProcess {
angleReference.renderEntityId = renderEntity.id
angleReference.name = "${renderEntity.name}参考方向"
angleReference.table = renderEntity.table
angleReference.zoomMin = renderEntity.zoomMin
angleReference.zoomMax = renderEntity.zoomMax
angleReference.taskId = renderEntity.taskId
// 与原有方向指向平行的线
angleReference.geometry = GeometryTools.createLineString(arrayOf(point, coorEnd)).toString()
angleReference.properties["qi_table"] = renderEntity.table
@ -299,7 +342,6 @@ class ImportPreProcess {
}
/**
* 生成默认道路名数据
* */
@ -343,6 +385,25 @@ class ImportPreProcess {
}
}
/**
* 生成车道中心线面宽度
* */
fun generateAddWidthLine(renderEntity: RenderEntity) {
// 添加车道中心面渲染原则,根据车道宽度进行渲染
val angleReference = ReferenceEntity()
angleReference.renderEntityId = renderEntity.id
angleReference.name = "${renderEntity.name}车道中线面"
angleReference.table = renderEntity.table
angleReference.geometry = renderEntity.geometry
angleReference.properties["qi_table"] = renderEntity.table
angleReference.properties["width"] = "3"
angleReference.zoomMin = renderEntity.zoomMin
angleReference.zoomMax = renderEntity.zoomMax
angleReference.taskId = renderEntity.taskId
Realm.getDefaultInstance().insert(angleReference)
}
/**
* 生成默认路口数据的参考数据
* */
@ -356,6 +417,9 @@ class ImportPreProcess {
intersectionReference.renderEntityId = renderEntity.id
intersectionReference.name = "${renderEntity.name}参考点"
intersectionReference.table = renderEntity.table
intersectionReference.zoomMin = renderEntity.zoomMin
intersectionReference.zoomMax = renderEntity.zoomMax
intersectionReference.taskId = renderEntity.taskId
// 与原有方向指向平行的线
intersectionReference.geometry = GeometryTools.createGeometry(nodeJSONObject["geometry"].toString()).toString()
intersectionReference.properties["qi_table"] = renderEntity.table

View File

@ -3,6 +3,7 @@ package com.navinfo.omqs.db
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.navinfo.collect.library.data.entity.HadLinkDvoBean
import com.navinfo.collect.library.data.entity.RenderEntity
import com.navinfo.collect.library.data.entity.RenderEntity.Companion.LinkTable
import com.navinfo.collect.library.map.NIMapController
@ -85,6 +86,39 @@ class RealmOperateHelper() {
}
suspend fun captureTaskLink(
taskId: Int,
point: GeoPoint,
buffer: Double = DEFAULT_BUFFER,
bufferType: BUFFER_TYPE = DEFAULT_BUFFER_TYPE,
): HadLinkDvoBean? {
val polygon = getPolygonFromPoint(
GeometryTools.createPoint(point.longitude, point.latitude),
buffer,
bufferType
)
val realm = Realm.getDefaultInstance()
val realmList = realm.where(HadLinkDvoBean::class.java)
.equalTo("taskId", taskId)
.findAll()
var linkBean: HadLinkDvoBean? = null
var nearLast: Double = 99999.99
for (link in realmList) {
if (polygon.intersects(GeometryTools.createGeometry(link.geometry))) {
val near = point.distance(GeometryTools.createGeoPoint(link.geometry))
if (near < nearLast) {
nearLast = near
linkBean = link
}
}
}
if (linkBean != null)
return realm.copyFromRealm(linkBean)
return null
}
suspend fun queryLink(linkPid: String): RenderEntity? {
var link: RenderEntity? = null
withContext(Dispatchers.IO) {
@ -237,6 +271,8 @@ class RealmOperateHelper() {
Log.d("queryLink", wkt.toString())
return wkt
}
}
enum class BUFFER_TYPE(val index: Int) {

View File

@ -1,6 +1,8 @@
package com.navinfo.omqs.hilt
import android.app.Application
import android.content.Context
import android.content.SharedPreferences
import android.util.Log
import androidx.room.Room
import com.google.gson.Gson
@ -25,7 +27,6 @@ import io.realm.Realm
import kotlinx.coroutines.*
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
@ -38,6 +39,7 @@ import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
class GlobalModule {
@Singleton
@Provides
fun provideApplication(@ApplicationContext application: Application): OMQSApplication {
@ -166,4 +168,10 @@ class GlobalModule {
fun provideRealmDefaultInstance(): Realm {
return Realm.getDefaultInstance()
}
@Singleton
@Provides
fun provideSharedPreferences(context: Application): SharedPreferences {
return context.getSharedPreferences("Shared" + Constant.USER_ID, Context.MODE_PRIVATE)
}
}

View File

@ -6,8 +6,7 @@ import com.navinfo.omqs.bean.IndoorConnectionInfoBean
import com.navinfo.omqs.bean.LoginUserBean
import com.navinfo.omqs.bean.QRCodeBean
import com.navinfo.omqs.bean.SysUserBean
import okhttp3.ResponseBody
import retrofit2.Response
import com.navinfo.omqs.bean.TraceVideoBean
/**
@ -38,4 +37,9 @@ interface NetworkService {
* 更新用户信息
*/
suspend fun updateServerInfo(url: String,indoorConnectionInfoBean: IndoorConnectionInfoBean): NetResult<QRCodeBean>
/**
* 设置轨迹对应的视频
*/
suspend fun sendServerCommand(url: String,traceVideoBean: TraceVideoBean): NetResult<QRCodeBean>
}

View File

@ -6,6 +6,7 @@ import com.navinfo.omqs.bean.IndoorConnectionInfoBean
import com.navinfo.omqs.bean.LoginUserBean
import com.navinfo.omqs.bean.QRCodeBean
import com.navinfo.omqs.bean.SysUserBean
import com.navinfo.omqs.bean.TraceVideoBean
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.ResponseBody
@ -101,7 +102,43 @@ class NetworkServiceImpl @Inject constructor(
//在IO线程中运行
withContext(Dispatchers.IO) {
return@withContext try {
val result = netApi.retrofitUpdateServerInfo(url,indoorConnectionInfoBean)
val map: MutableMap<String, String> = HashMap()
map["username"] = indoorConnectionInfoBean.username
map["uname"] = indoorConnectionInfoBean.uname
map["userid"] = indoorConnectionInfoBean.userid
map["plate"] = indoorConnectionInfoBean.plate
map["token"] = indoorConnectionInfoBean.token
map["baseurl"] = indoorConnectionInfoBean.baseurl
map["platform"] = indoorConnectionInfoBean.platform
val result = netApi.retrofitUpdateServerInfo(url,map)
if (result.isSuccessful) {
if (result.code() == 200) {
NetResult.Success(result.body())
} else {
NetResult.Failure<Any>(result.code(), result.message())
}
} else {
NetResult.Failure<Any>(result.code(), result.message())
}
} catch (e: Exception) {
NetResult.Error<Any>(e)
}
}
override suspend fun sendServerCommand(
url: String,
traceVideoBean: TraceVideoBean
): NetResult<QRCodeBean> =
//在IO线程中运行
withContext(Dispatchers.IO) {
return@withContext try {
val map: MutableMap<String, String> = HashMap()
map["userid"] = traceVideoBean.userid
map["playMode"] = traceVideoBean.playMode
map["time"] = traceVideoBean.time
val result = netApi.retrofitUpdateServerInfo(url,map)
if (result.isSuccessful) {
if (result.code() == 200) {
NetResult.Success(result.body())

View File

@ -78,9 +78,9 @@ interface RetrofitNetworkServiceAPI {
/**
* 登录接口
*/
@Headers("Content-Type: application/json")
@FormUrlEncoded
@POST
suspend fun retrofitUpdateServerInfo(@Url url: String,@Body indoorConnectionInfoBean: IndoorConnectionInfoBean): Response<QRCodeBean>
suspend fun retrofitUpdateServerInfo(@Url url: String,@FieldMap map: Map<String,String>): Response<QRCodeBean>
@Headers("Content-Type: application/json")
@POST("/devcp/uploadSceneProblem")

View File

@ -1,6 +1,7 @@
package com.navinfo.omqs.http.taskdownload
import android.content.Context
import android.util.Log
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import com.navinfo.collect.library.map.NIMapController
@ -17,7 +18,7 @@ import java.util.concurrent.ConcurrentHashMap
class TaskDownloadManager constructor(
val importFactory: ImportOMDBHiltFactory,
val netApi: RetrofitNetworkServiceAPI,
val mapController:NIMapController
val mapController: NIMapController
) {
lateinit var context: Context
@ -41,6 +42,7 @@ class TaskDownloadManager constructor(
ConcurrentHashMap<Int, TaskDownloadScope>()
}
fun init(context: Context) {
this.context = context
}
@ -102,8 +104,9 @@ class TaskDownloadManager constructor(
fun addTask(taskBean: TaskBean) {
Log.e("jingo", "下载线程 ${taskBean.id}")
if (!scopeMap.containsKey(taskBean.id)) {
scopeMap[taskBean.id] = TaskDownloadScope( this, taskBean)
scopeMap[taskBean.id] = TaskDownloadScope(this, taskBean)
}
}
@ -111,6 +114,7 @@ class TaskDownloadManager constructor(
fun observer(
id: Int, lifecycleOwner: LifecycleOwner, observer: Observer<TaskBean>
) {
Log.e("jingo", "监听线程 ${id}")
if (scopeMap.containsKey(id)) {
scopeMap[id]!!.observer(lifecycleOwner, observer)
}

View File

@ -1,14 +1,16 @@
package com.navinfo.omqs.http.taskdownload
import android.util.Log
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import com.navinfo.omqs.Constant
import com.navinfo.collect.library.data.entity.TaskBean
import com.navinfo.omqs.Constant
import com.navinfo.omqs.db.ImportOMDBHelper
import com.navinfo.omqs.tools.FileManager
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
import com.navinfo.omqs.ui.other.BaseViewHolder
import com.navinfo.omqs.util.DateTimeUtil
import io.realm.Realm
import kotlinx.coroutines.*
@ -21,7 +23,7 @@ class TaskDownloadScope(
private val downloadManager: TaskDownloadManager,
val taskBean: TaskBean,
) :
CoroutineScope by CoroutineScope(Dispatchers.IO + CoroutineName("OfflineMapDownLoad")) {
CoroutineScope by CoroutineScope(Dispatchers.IO + CoroutineName("TaskMapDownLoad")) {
/**
*下载任务用来取消的
@ -31,8 +33,8 @@ class TaskDownloadScope(
/**
* 管理观察者同时只有一个就行了
*/
private val observer = Observer<Any> {}
// private var lifecycleOwner: LifecycleOwner? = null
// private val observer = Observer<Any> {}
private var lifecycleOwner: LifecycleOwner? = null
/**
*通知UI更新
@ -71,7 +73,7 @@ class TaskDownloadScope(
downloadJob = launch() {
FileManager.checkOMDBFileInfo(taskBean)
if (taskBean.status == FileDownloadStatus.IMPORT) {
importData()
importData(taskId = taskBean.id)
} else {
download()
}
@ -92,6 +94,7 @@ class TaskDownloadScope(
* @param status [OfflineMapCityBean.Status]
*/
private suspend fun change(status: Int, message: String = "") {
if (taskBean.status != status || status == FileDownloadStatus.LOADING || status == FileDownloadStatus.IMPORTING) {
taskBean.status = status
taskBean.message = message
@ -111,15 +114,16 @@ class TaskDownloadScope(
* 添加下载任务观察者
*/
fun observer(owner: LifecycleOwner, ob: Observer<TaskBean>) {
removeObserver()
// this.lifecycleOwner = owner
this.lifecycleOwner = owner
downloadData.observe(owner, ob)
}
/**
* 导入数据
*/
private suspend fun importData(file: File? = null) {
private suspend fun importData(file: File? = null, taskId: Int?=0) {
try {
Log.e("jingo", "importData SSS")
change(FileDownloadStatus.IMPORTING)
@ -130,15 +134,17 @@ class TaskDownloadScope(
downloadManager.context,
fileNew
)
importOMDBHelper.importOmdbZipFile(importOMDBHelper.omdbFile).collect {
Log.e("jingo", "数据安装 $it")
if (it == "finish") {
change(FileDownloadStatus.DONE)
withContext(Dispatchers.Main) {
downloadManager.mapController.mMapView.updateMap(true)
if (taskId != null) {
importOMDBHelper.importOmdbZipFile(importOMDBHelper.omdbFile,taskId).collect {
Log.e("jingo", "数据安装 $it")
if (it == "finish") {
change(FileDownloadStatus.DONE)
withContext(Dispatchers.Main) {
downloadManager.mapController.mMapView.updateMap(true)
}
} else {
change(FileDownloadStatus.IMPORTING, it)
}
} else {
change(FileDownloadStatus.IMPORTING, it)
}
}
} catch (e: Exception) {
@ -177,7 +183,7 @@ class TaskDownloadScope(
startPosition = 0
}
if (fileTemp.length() > 0 && taskBean.fileSize > 0 && fileTemp.length() == taskBean.fileSize) {
importData(fileTemp)
importData(fileTemp,taskBean.id)
return
}
@ -218,7 +224,7 @@ class TaskDownloadScope(
randomAccessFile?.close()
inputStream = null
randomAccessFile = null
importData()
importData(taskId = taskBean.id)
} else {
change(FileDownloadStatus.PAUSE)
}
@ -232,10 +238,17 @@ class TaskDownloadScope(
}
fun removeObserver() {
downloadData.observeForever(observer)
// lifecycleOwner?.let {
downloadData.removeObserver(observer)
// null
// }
// downloadData.observeForever(observer)
//// lifecycleOwner?.let {
// downloadData.removeObserver(observer)
//// null
//// }
if (lifecycleOwner != null) {
Log.e(
"jingo",
"移除的上一个监听者 ${lifecycleOwner.hashCode()} ${(lifecycleOwner as BaseViewHolder).tag}"
)
downloadData.removeObservers(lifecycleOwner!!)
}
}
}

View File

@ -77,7 +77,7 @@ class TaskUploadScope(
taskBean.operationTime = DateTimeUtil.getNowDate().time
uploadData.postValue(taskBean)
//同步中不进行状态记录,只做界面变更显示
if(status!=FileUploadStatus.UPLOADING){
if (status != FileUploadStatus.UPLOADING) {
launch {
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
@ -118,59 +118,18 @@ class TaskUploadScope(
val bodyList: MutableList<EvaluationInfo> = ArrayList()
if (taskBean.syncStatus == FileUploadStatus.WAITING){
if (taskBean.syncStatus == FileUploadStatus.WAITING) {
change(FileUploadStatus.UPLOADING)
}
taskBean.hadLinkDvoList.forEach { hadLinkDvoBean ->
val objects = realm.where(QsRecordBean::class.java)
.equalTo("linkId", /*"84207223282277331"*/hadLinkDvoBean.linkPid).findAll()
if (objects != null&&objects.size>0) {
val copyList = realm.copyFromRealm(objects)
copyList.forEach {
var problemType = 0
if(it.problemType=="错误"){
problemType = 0
}else if(it.problemType=="多余"){
problemType = 1
}else if(it.problemType=="遗漏"){
problemType = 2
}
var evaluationWay = 2
val evaluationInfo = EvaluationInfo(
evaluationTaskId = taskBean.id.toString(),
linkPid = hadLinkDvoBean.linkPid,//"84207223282277331"
linkStatus = 1,
markId = hadLinkDvoBean.mesh,//"20065597"
trackPhotoNumber = "",
markGeometry = it.geometry,
featureName = it.classCode,
problemType = problemType,
problemPhenomenon = it.phenomenon,
problemDesc = it.description,
problemLink = it.problemLink,
preliminaryAnalysis = it.cause,
evaluatorName = it.checkUserId,
evaluationDate = it.checkTime,
evaluationWay = evaluationWay,
roadClassfcation = "",
roadFunctionGrade = "",
noEvaluationreason = "",
linkLength = 0.0,
dataLevel = "",
linstringLength = 0.0,
)
bodyList.add(evaluationInfo)
}
}else{
val linkStatus = 1
//存在原因标记未测评
if(hadLinkDvoBean.reason.isNotEmpty()){
val linkStatus = 0
}else{
val linkStatus = 1
}
val linkStatus = 1
//存在原因标记未测评
if (hadLinkDvoBean.reason.isNotEmpty()) {
//未测评
val linkStatus = 0
val evaluationInfo = EvaluationInfo(
evaluationTaskId = taskBean.id.toString(),
linkPid = hadLinkDvoBean.linkPid,//"84207223282277331"
@ -187,27 +146,92 @@ class TaskUploadScope(
evaluatorName = "",
evaluationDate = "",
evaluationWay = 2,
roadClassfcation = "",
roadFunctionGrade = "",
roadClassfcation = 1,
roadFunctionGrade = 0,
noEvaluationreason = hadLinkDvoBean.reason,
linkLength = 0.0,
dataLevel = "",
dataLevel = 0,
linstringLength = 0.0,
)
bodyList.add(evaluationInfo)
} else {
val linkStatus = hadLinkDvoBean.linkStatus
var s: String = "%.3f".format(hadLinkDvoBean.length)//保留一位小数(且支持四舍五入)
val objects = realm.where(QsRecordBean::class.java)
.equalTo("linkId", /*"84207223282277331"*/hadLinkDvoBean.linkPid).and()
.equalTo("taskId", hadLinkDvoBean.taskId).findAll()
if (objects != null && objects.size > 0) {
val copyList = realm.copyFromRealm(objects)
copyList.forEach {
var problemType = 0
if (it.problemType == "错误") {
problemType = 0
} else if (it.problemType == "多余") {
problemType = 1
} else if (it.problemType == "遗漏") {
problemType = 2
}
var roadClassfcation = 0
var roadFunctionGrade = 0
var dataLevel = 0
if (hadLinkDvoBean.linkInfo != null) {
roadClassfcation = hadLinkDvoBean.linkInfo!!.kind
roadFunctionGrade = hadLinkDvoBean.linkInfo!!.functionLevel
dataLevel = hadLinkDvoBean.linkInfo!!.dataLevel
}
var evaluationWay = 2
val evaluationInfo = EvaluationInfo(
evaluationTaskId = taskBean.id.toString(),
linkPid = hadLinkDvoBean.linkPid,//"84207223282277331"
linkStatus = linkStatus,
markId = hadLinkDvoBean.mesh,//"20065597"
trackPhotoNumber = "",
markGeometry = it.geometry,
featureName = it.classCode,
problemType = problemType,
problemPhenomenon = it.phenomenon,
problemDesc = it.description,
problemLink = it.problemLink,
preliminaryAnalysis = it.cause,
evaluatorName = it.checkUserId,
evaluationDate = it.checkTime,
evaluationWay = evaluationWay,
roadClassfcation = roadClassfcation,
roadFunctionGrade = roadFunctionGrade,
noEvaluationreason = "",
linkLength = s.toDouble(),
dataLevel = dataLevel,
linstringLength = 0.0,
)
bodyList.add(evaluationInfo)
}
}
}
}
if(bodyList.size>0){
if (bodyList.size > 0) {
val result = uploadManager.netApi.postRequest(bodyList)// .enqueue(object :
// Callback<ResponseBody> {
if (result.isSuccessful) {
if (result.code() == 200&&result.body()!=null) {
if (result.code() == 200 && result.body() != null) {
val defaultUserResponse = result.body() as DefaultResponse<*>
if(defaultUserResponse.success){
change(FileUploadStatus.DONE,"上传成功")
}else{
change(FileUploadStatus.ERROR,"${defaultUserResponse.msg}")
if (defaultUserResponse.success) {
change(FileUploadStatus.DONE, "上传成功")
} else {
change(FileUploadStatus.ERROR, "${defaultUserResponse.msg}")
}
} else {
// handle the failure
@ -216,7 +240,7 @@ class TaskUploadScope(
} else {
change(FileUploadStatus.ERROR)
}
}else{
} else {
change(FileUploadStatus.NONE)
}
} catch (e: Throwable) {

View File

@ -1,6 +1,7 @@
package com.navinfo.omqs.ui.activity.login
import android.content.Context
import android.content.SharedPreferences
import android.util.Log
import android.view.View
import android.widget.Toast
@ -16,11 +17,11 @@ import com.navinfo.omqs.http.DefaultResponse
import com.navinfo.omqs.http.NetResult
import com.navinfo.omqs.http.NetworkService
import com.navinfo.omqs.tools.FileManager
import com.navinfo.omqs.util.NetUtils
import dagger.hilt.android.lifecycle.HiltViewModel
import io.realm.Realm
import io.realm.RealmConfiguration
import kotlinx.coroutines.*
import retrofit2.Response
import java.io.File
import java.io.IOException
import javax.inject.Inject
@ -73,7 +74,9 @@ class LoginViewModel @Inject constructor(
//是不是登录成功
val loginStatus: MutableLiveData<LoginStatus> = MutableLiveData()
var jobLogin: Job? = null;
var jobLogin: Job? = null
var sharedPreferences: SharedPreferences? = null
init {
loginUser.value = LoginUserBean(userCode = "haofuyue00213", passWord = "123456")
@ -98,10 +101,27 @@ class LoginViewModel @Inject constructor(
if (password.isEmpty()) {
Toast.makeText(context, "请输入密码", Toast.LENGTH_SHORT).show()
}
sharedPreferences =
context.getSharedPreferences("USER_SHAREDPREFERENCES", Context.MODE_PRIVATE)
val userNameCache = sharedPreferences?.getString("userName", null)
val passwordCache = sharedPreferences?.getString("passWord", null)
val userCodeCache = sharedPreferences?.getString("userCode", null)
val userRealName = sharedPreferences?.getString("userRealName", null)
//增加缓存记录,不用每次连接网络登录
if (userNameCache != null && passwordCache != null && userCodeCache != null&&userRealName!=null) {
if (userNameCache == userName && passwordCache == password) {
viewModelScope.launch(Dispatchers.IO) {
createUserFolder(context, userCodeCache,userRealName)
loginStatus.postValue(LoginStatus.LOGIN_STATUS_SUCCESS)
}
return
}
}
//不指定IO会在主线程里运行
jobLogin = viewModelScope.launch(Dispatchers.IO) {
loginCheck(context, userName, password)
}
}
/**
@ -114,26 +134,36 @@ class LoginViewModel @Inject constructor(
//网络访问
loginStatus.postValue(LoginStatus.LOGIN_STATUS_NET_LOADING)
var userCode = "99999";
var userRealName = "";
//登录访问
when (val result = networkService.loginUser(LoginUserBean(userName,password))) {
is NetResult.Success<*> ->{
if (result.data!=null) {
when (val result = networkService.loginUser(LoginUserBean(userName, password))) {
is NetResult.Success<*> -> {
if (result.data != null) {
try {
val defaultUserResponse = result.data as DefaultResponse<SysUserBean>
if(defaultUserResponse.success){
if(defaultUserResponse.obj==null|| defaultUserResponse.obj!!.userCode==null){
if (defaultUserResponse.success) {
if (defaultUserResponse.obj == null || defaultUserResponse.obj!!.userCode == null) {
withContext(Dispatchers.Main) {
Toast.makeText(context, "服务返回用户Code信息错误", Toast.LENGTH_SHORT)
Toast.makeText(
context,
"服务返回用户Code信息错误",
Toast.LENGTH_SHORT
)
.show()
}
loginStatus.postValue(LoginStatus.LOGIN_STATUS_CANCEL)
return
}else{
} else {
userCode = defaultUserResponse.obj?.userCode.toString()
userRealName = defaultUserResponse.obj?.userName.toString()
}
}else{
} else {
withContext(Dispatchers.Main) {
Toast.makeText(context, "${defaultUserResponse.msg}", Toast.LENGTH_SHORT)
Toast.makeText(
context,
"${defaultUserResponse.msg}",
Toast.LENGTH_SHORT
)
.show()
}
loginStatus.postValue(LoginStatus.LOGIN_STATUS_CANCEL)
@ -145,7 +175,8 @@ class LoginViewModel @Inject constructor(
}
}
}
is NetResult.Error<*> ->{
is NetResult.Error<*> -> {
withContext(Dispatchers.Main) {
Toast.makeText(context, "${result.exception.message}", Toast.LENGTH_SHORT)
.show()
@ -153,7 +184,8 @@ class LoginViewModel @Inject constructor(
loginStatus.postValue(LoginStatus.LOGIN_STATUS_CANCEL)
return
}
is NetResult.Failure<*> ->{
is NetResult.Failure<*> -> {
withContext(Dispatchers.Main) {
Toast.makeText(context, "${result.code}:${result.msg}", Toast.LENGTH_SHORT)
.show()
@ -161,13 +193,19 @@ class LoginViewModel @Inject constructor(
loginStatus.postValue(LoginStatus.LOGIN_STATUS_CANCEL)
return
}
else -> {}
}
//文件夹初始化
try {
loginStatus.postValue(LoginStatus.LOGIN_STATUS_FOLDER_INIT)
createUserFolder(context, userCode)
sharedPreferences?.edit()?.putString("userName", userName)?.commit()
sharedPreferences?.edit()?.putString("passWord", password)?.commit()
sharedPreferences?.edit()?.putString("userCode", userCode)?.commit()
sharedPreferences?.edit()?.putString("userRealName", userRealName)?.commit()
createUserFolder(context, userCode,userRealName)
} catch (e: IOException) {
loginStatus.postValue(LoginStatus.LOGIN_STATUS_FOLDER_FAILURE)
}
@ -185,18 +223,21 @@ class LoginViewModel @Inject constructor(
roomAppDatabase.getOfflineMapDao().insertOrUpdate(result.data)
}
}
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 -> {}
}
@ -206,9 +247,10 @@ class LoginViewModel @Inject constructor(
/**
* 创建用户目录
*/
private fun createUserFolder(context: Context, userId: String) {
private fun createUserFolder(context: Context, userId: String,userRealName:String) {
Constant.IS_VIDEO_SPEED = false
Constant.USER_ID = userId
Constant.USER_REAL_NAME = userRealName
Constant.VERSION_ID = userId
Constant.USER_DATA_PATH = Constant.DATA_PATH + Constant.USER_ID + "/" + Constant.VERSION_ID
Constant.USER_DATA_ATTACHEMNT_PATH = Constant.USER_DATA_PATH + "/attachment/"
@ -234,7 +276,7 @@ class LoginViewModel @Inject constructor(
// 拷贝配置文件到用户目录下
val omdbConfigFile = File(userFolder.absolutePath, Constant.OMDB_CONFIG);
// if (!omdbConfigFile.exists()) {
ResourceUtils.copyFileFromAssets(Constant.OMDB_CONFIG, omdbConfigFile.absolutePath)
ResourceUtils.copyFileFromAssets(Constant.OMDB_CONFIG, omdbConfigFile.absolutePath)
// }
}

View File

@ -20,10 +20,12 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.collect.library.map.NIMapOptions
import com.navinfo.omqs.Constant
import com.navinfo.omqs.R
import com.navinfo.omqs.bean.ImportConfig
import com.navinfo.omqs.bean.SignBean
import com.navinfo.omqs.bean.TraceVideoBean
import com.navinfo.omqs.databinding.ActivityMainBinding
import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager
import com.navinfo.omqs.tools.LayerConfigUtils
@ -33,11 +35,14 @@ import com.navinfo.omqs.ui.fragment.offlinemap.OfflineMapFragment
import com.navinfo.omqs.ui.fragment.qsrecordlist.QsRecordListFragment
import com.navinfo.omqs.ui.fragment.signMoreInfo.SignMoreInfoFragment
import com.navinfo.omqs.ui.fragment.tasklist.TaskManagerFragment
import com.navinfo.omqs.ui.other.BaseToast
import com.navinfo.omqs.ui.widget.RecyclerViewSpacesItemDecoration
import com.navinfo.omqs.util.FlowEventBus
import com.navinfo.omqs.util.SpeakMode
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.oscim.core.GeoPoint
import org.oscim.renderer.GLViewport
import org.videolan.vlc.Util
import java.math.BigDecimal
import java.math.RoundingMode
@ -163,8 +168,7 @@ class MainActivity : BaseActivity() {
viewModel.speakMode = SpeakMode(this)
// 在mapController初始化前获取当前OMDB图层显隐
viewModel.refreshOMDBLayer(LayerConfigUtils.getLayerConfigList())
mapController.mMapView.vtmMap.viewport().maxZoomLevel = 25
mapController.mMapView.vtmMap.viewport().maxTilt = 85f
mapController.mMapView.vtmMap.viewport().maxZoomLevel = Constant.MAX_ZOOM
//关联生命周期
binding.lifecycleOwner = this
//给xml转递对象
@ -177,6 +181,7 @@ class MainActivity : BaseActivity() {
MotionEvent.ACTION_DOWN -> {
voiceOnTouchStart()//Do Something
}
MotionEvent.ACTION_UP -> {
voiceOnTouchStop()//Do Something
}
@ -185,9 +190,62 @@ class MainActivity : BaseActivity() {
}
//捕捉列表变化回调
viewModel.liveDataQsRecordIdList.observe(this) {
//处理页面跳转
viewModel.navigationRightFragment(this, it)
//跳转到质检数据页面
//获取右侧fragment容器
val naviController = findNavController(R.id.main_activity_right_fragment)
naviController.currentDestination?.let { navDestination ->
when (navDestination.id) {
R.id.RightEmptyFragment -> {
if (it.size == 1) {
val bundle = Bundle()
bundle.putString("QsId", it[0])
naviController.navigate(R.id.EvaluationResultFragment, bundle)
}
}
}
}
}
//捕捉列表变化回调
viewModel.liveDataNoteId.observe(this) {
//跳转到质检数据页面
//获取右侧fragment容器
val naviController = findNavController(R.id.main_activity_right_fragment)
naviController.currentDestination?.let { navDestination ->
when (navDestination.id) {
R.id.RightEmptyFragment -> {
val bundle = Bundle()
bundle.putString("NoteId", it)
naviController.navigate(R.id.NoteFragment, bundle)
}
}
}
}
viewModel.liveDataTaskLink.observe(this) {
val bundle = Bundle()
bundle.putString("TaskLinkId", it)
findNavController(R.id.main_activity_right_fragment).navigate(
R.id.TaskLinkFragment, bundle
)
}
//捕捉轨迹点
viewModel.liveDataNILocationList.observe(this) {
if (viewModel.isSelectTrace()) {
//Toast.makeText(this,"轨迹被点击了",Toast.LENGTH_LONG).show()
viewModel.showMarker(this, it)
viewModel.setCurrentIndexNiLocation(it)
val traceVideoBean = TraceVideoBean(
command = "videotime?",
userid = Constant.USER_ID,
time = "${it.time}:000"
)
viewModel.sendServerCommand(this, traceVideoBean, IndoorToolsCommand.SELECT_POINT)
}
}
//右上角菜单是否被点击
viewModel.liveDataMenuState.observe(this) {
binding.mainActivityMenu.isSelected = it
@ -254,7 +312,7 @@ class MainActivity : BaseActivity() {
}
}
viewModel.liveDataSignMoreInfo.observe(this){
viewModel.liveDataSignMoreInfo.observe(this) {
val fragment =
supportFragmentManager.findFragmentById(R.id.main_activity_sign_more_info_fragment)
if (fragment == null) {
@ -264,6 +322,55 @@ class MainActivity : BaseActivity() {
}
}
viewModel.liveIndoorToolsResp.observe(this) {
when (it) {
IndoorToolsResp.QR_CODE_STATUS_UPDATE_VIDEO_INFO_SUCCESS -> {
if (viewModel.indoorToolsCommand == IndoorToolsCommand.SELECT_POINT) {
selectPointFinish(true)
}
//启动自动播放
if (viewModel.indoorToolsCommand == IndoorToolsCommand.PLAY) {
viewModel.startTimer()
}
}
IndoorToolsResp.QR_CODE_STATUS_UPDATE_VIDEO_INFO_FAILURE -> {
if (viewModel.indoorToolsCommand == IndoorToolsCommand.SELECT_POINT) {
selectPointFinish(false)
}
}
}
}
//室内整理工具反向控制
viewModel.liveIndoorToolsCommand.observe(this) {
when (it) {
IndoorToolsCommand.PLAY -> {
setPlayStatus()
}
IndoorToolsCommand.INDEXING -> {
pausePlayTrace()
}
IndoorToolsCommand.SELECT_POINT -> {
}
IndoorToolsCommand.NEXT -> {
}
IndoorToolsCommand.REWIND -> {
}
IndoorToolsCommand.STOP -> {
//切换为暂停状态
pausePlayTrace()
}
}
}
lifecycleScope.launch {
// 初始化地图图层控制接收器
FlowEventBus.subscribe<List<ImportConfig>>(
@ -283,8 +390,13 @@ class MainActivity : BaseActivity() {
}
}
supportFragmentManager.beginTransaction()
.add(R.id.console_fragment_layout, ConsoleFragment()).commit()
//自动连接相机
if (viewModel.isAutoCamera()) {
viewModel.autoCamera()
} else {
supportFragmentManager.beginTransaction()
.add(R.id.console_fragment_layout, ConsoleFragment()).commit()
}
}
//根据输入的经纬度跳转坐标
@ -293,7 +405,7 @@ class MainActivity : BaseActivity() {
val inputDialog = MaterialAlertDialogBuilder(
this
).setTitle("坐标定位").setView(view)
var editText = view.findViewById<EditText>(R.id.dialog_edittext)
val editText = view.findViewById<EditText>(R.id.dialog_edittext)
editText.hint = "请输入经纬度例如:\n116.1234567,39.1234567\n116.1234567 39.1234567"
inputDialog.setNegativeButton("取消") { dialog, _ ->
dialog.dismiss()
@ -430,13 +542,42 @@ class MainActivity : BaseActivity() {
}
}
/**
* 准星的显隐控制
*/
fun setHomeCenterVisibility(visible: Int) {
binding.mainActivityHomeCenter.visibility = visible
binding.mainActivityHomeCenterText.visibility = visible
if (visible != View.VISIBLE) {
binding.mainActivityHomeCenterText.text = ""
}
}
/**
* 设置屏幕中心文字内容
*/
fun setHomeCenterText(str: String) {
binding.mainActivityHomeCenterText.text = str
}
/**
* 隐藏或显示右侧展开按钮
*/
fun setRightSwitchButton(visibility: Int) {
fun setRightSwitchButtonVisibility(visibility: Int) {
binding.mainActivityFragmentSwitch.visibility = visibility
}
/**
* 顶部菜单按钮
*/
fun setTopMenuButtonVisibility(visibility: Int) {
binding.mainActivityMenu.visibility = visibility
if (visibility != View.VISIBLE) {
binding.mainActivityMenuGroup.visibility = View.INVISIBLE
binding.mainActivityMenu.isSelected = false
}
}
/**
* 点击录音按钮
*/
@ -453,6 +594,167 @@ class MainActivity : BaseActivity() {
binding.mainActivitySelectLine.isSelected = viewModel.isSelectRoad()
}
/**
* 点击线选择
*/
fun tracePointsOnclick() {
viewModel.setSelectTrace(!viewModel.isSelectTrace())
binding.mainActivityTraceSnapshotPoints.isSelected = viewModel.isSelectTrace()
if (viewModel.isSelectTrace()) {
Toast.makeText(this, "请选择轨迹点!", Toast.LENGTH_LONG).show()
//调用撤销自动播放
setViewEnable(false)
viewModel.cancelTrace()
}
}
/**
* 点击结束轨迹操作
*/
fun finishTraceOnclick() {
setIndoorGroupEnable(false)
viewModel.setSelectTrace(false)
viewModel.setMediaFlag(false)
viewModel.setSelectPauseTrace(false)
binding.mainActivityMenuIndoorGroup.visibility = View.GONE
binding.mainActivityTraceSnapshotPoints.isSelected = viewModel.isSelectTrace()
//binding.mainActivitySnapshotMediaFlag.isSelected = viewModel.isMediaFlag()
binding.mainActivitySnapshotPause.isSelected = viewModel.isSelectPauseTrace()
}
/**
* 点击结束轨迹操作
*/
fun mediaFlagOnclick() {
/* viewModel.setMediaFlag(!viewModel.isMediaFlag())
binding.mainActivitySnapshotMediaFlag.isSelected = viewModel.isMediaFlag()*/
}
/**
* 点击上一个轨迹点播放操作
*/
fun rewindTraceOnclick() {
pausePlayTrace()
val item =
mapController.markerHandle.getNILocation(viewModel.getCurrentNiLocationIndex() - 1)
if (item != null) {
viewModel.setCurrentIndexLoction(viewModel.getCurrentNiLocationIndex() - 1)
viewModel.showMarker(this, item)
val traceVideoBean = TraceVideoBean(
command = "videotime?",
userid = Constant.USER_ID,
time = "${item.time}:000"
)
viewModel.sendServerCommand(this, traceVideoBean, IndoorToolsCommand.REWIND)
} else {
dealNoData()
}
}
/**
* 点击暂停播放轨迹操作
*/
fun pauseTraceOnclick() {
viewModel.setSelectPauseTrace(!viewModel.isSelectPauseTrace())
binding.mainActivitySnapshotPause.isSelected = viewModel.isSelectPauseTrace()
viewModel.setSelectTrace(false)
binding.mainActivityTraceSnapshotPoints.isSelected = viewModel.isSelectTrace()
if (viewModel.isSelectPauseTrace()) {
playVideo()
} else {
pauseVideo()
viewModel.cancelTrace()
}
}
private fun playVideo() {
if (mapController.markerHandle.getCurrentMark() == null) {
BaseToast.makeText(this, "请先选择轨迹点!", BaseToast.LENGTH_SHORT).show()
return
}
viewModel.setSelectTrace(false)
binding.mainActivityTraceSnapshotPoints.isSelected = viewModel.isSelectTrace()
val traceVideoBean = TraceVideoBean(command = "playVideo?", userid = Constant.USER_ID)
viewModel.sendServerCommand(this, traceVideoBean, IndoorToolsCommand.PLAY)
}
/**
* 设置为播放状态
*/
private fun setPlayStatus() {
//切换为播放
viewModel.setSelectPauseTrace(true)
binding.mainActivitySnapshotPause.isSelected = viewModel.isSelectPauseTrace()
playVideo()
}
private fun pauseVideo() {
val traceVideoBean = TraceVideoBean(command = "pauseVideo?", userid = Constant.USER_ID)
viewModel.sendServerCommand(this, traceVideoBean, IndoorToolsCommand.STOP)
}
/**
* 点击下一个轨迹点
*/
fun nextTraceOnclick() {
pausePlayTrace()
val item =
mapController.markerHandle.getNILocation(viewModel.getCurrentNiLocationIndex() + 1)
if (item != null) {
viewModel.setCurrentIndexLoction(viewModel.getCurrentNiLocationIndex() + 1)
viewModel.showMarker(this, item)
val traceVideoBean = TraceVideoBean(
command = "videotime?",
userid = Constant.USER_ID,
time = "${item.time}:000"
)
viewModel.sendServerCommand(this, traceVideoBean, IndoorToolsCommand.NEXT)
} else {
dealNoData()
}
}
private fun dealNoData() {
BaseToast.makeText(this, "无数据了!", Toast.LENGTH_SHORT).show()
//无数据时自动暂停播放,并停止轨迹
if (viewModel.isSelectPauseTrace()) {
pauseVideo()
viewModel.cancelTrace()
viewModel.setSelectPauseTrace(false)
binding.mainActivitySnapshotPause.isSelected = viewModel.isSelectPauseTrace()
}
}
fun pausePlayTrace() {
viewModel.setSelectTrace(false)
binding.mainActivityTraceSnapshotPoints.isSelected = viewModel.isSelectTrace()
viewModel.setSelectPauseTrace(false)
binding.mainActivitySnapshotPause.isSelected = viewModel.isSelectPauseTrace()
viewModel.cancelTrace()
}
/**
* 选点结束
* @param value true 选点成功 false 选点失败
*/
private fun selectPointFinish(value: Boolean) {
if (value) {
setViewEnable(true)
viewModel.setSelectPauseTrace(false)
binding.mainActivitySnapshotPause.isSelected = viewModel.isSelectPauseTrace()
}
}
private fun setViewEnable(value: Boolean) {
binding.mainActivitySnapshotRewind.isEnabled = value
binding.mainActivitySnapshotNext.isEnabled = value
binding.mainActivitySnapshotPause.isEnabled = value
binding.mainActivitySnapshotFinish.isEnabled = value
viewModel.cancelTrace()
}
/**
* 打开或关闭底部导航栏
@ -466,9 +768,18 @@ class MainActivity : BaseActivity() {
}
binding.mainActivityBottomSheetGroup.visibility = View.GONE
mapController.mMapView.setScaleBarLayer(GLViewport.Position.BOTTOM_CENTER, 128, 5)
} else {
binding.mainActivityBottomSheetGroup.visibility = View.VISIBLE
mapController.mMapView.setScaleBarLayer(GLViewport.Position.BOTTOM_CENTER, 128, 65)
}
mapController.mMapView.vtmMap.animator().animateTo(
GeoPoint(
mapController.mMapView.vtmMap.mapPosition.geoPoint.latitude,
mapController.mMapView.vtmMap.mapPosition.geoPoint.longitude
)
)
}
private fun voiceOnTouchStart() {
@ -523,6 +834,27 @@ class MainActivity : BaseActivity() {
}
}
/**
* 显示轨迹回放布局
*/
fun showIndoorDataLayout() {
binding.mainActivityMenuIndoorGroup.visibility = View.VISIBLE
if (Constant.INDOOR_IP.isNotEmpty()) {
setIndoorGroupEnable(true)
} else {
setIndoorGroupEnable(false)
}
}
private fun setIndoorGroupEnable(enable: Boolean) {
binding.mainActivitySnapshotFinish.isEnabled = enable
binding.mainActivityTraceSnapshotPoints.isEnabled = enable
//binding.mainActivitySnapshotMediaFlag.isEnabled = enable
binding.mainActivitySnapshotRewind.isEnabled = enable
binding.mainActivitySnapshotPause.isEnabled = enable
binding.mainActivitySnapshotNext.isEnabled = enable
}
/**
* 路径规划
*/
@ -558,4 +890,25 @@ class MainActivity : BaseActivity() {
viewModel.showSignMoreInfo(viewModel.liveDataRoadName.value!!)
}
}
/**
* 新增便签,打开便签fragment
*/
fun onClickNewNote() {
rightController.navigate(R.id.NoteFragment)
}
/**
* 新增评测link
*/
fun onClickTaskLink() {
rightController.navigate(R.id.TaskLinkFragment)
}
/**
* 右侧按钮+经纬度按钮
*/
fun setRightButtonsVisible(visible: Int) {
binding.mainActivityRightVisibilityButtonsGroup2.visibility = visible
}
}

View File

@ -0,0 +1,606 @@
package com.navinfo.omqs.ui.activity.map
import android.app.Service
import android.content.Intent
import android.content.SharedPreferences
import android.os.Binder
import android.os.Handler
import android.os.IBinder
import android.os.Message
import android.text.TextUtils
import android.util.Log
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.omqs.Constant
import com.navinfo.omqs.util.DateTimeUtil
import org.json.JSONObject
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.io.Serializable
import java.net.Socket
import java.util.Collections
import kotlin.math.abs
enum class IndoorToolsCommand {
PLAY,
SELECT_POINT,
INDEXING,
NEXT,
REWIND,
STOP
}
enum class IndoorToolsResp{
/**
* 信息更新轨迹成功
*/
QR_CODE_STATUS_UPDATE_VIDEO_INFO_SUCCESS,
/**
* 信息更新轨迹失败
*/
QR_CODE_STATUS_UPDATE_VIDEO_INFO_FAILURE,
}
/**
* @author qj
* @version V1.0
* @Date 2018/4/18.
* @Description: 轨迹反向控制服务
*/
class SocketServer(
private val mapController: NIMapController,
private val traceDataBase: TraceDataBase,
private val sharedPreferences: SharedPreferences
) : Service() {
//类标识
private val TAG = "SocketServer"
//线程池
private val threadConnect = ThreadLocal<Socket>()
//读的线程
private var tRecv: RecvThread? = null
//解析线程
private var tParse: ParseThread? = null
//输出流
private var outStr: OutputStream? = null
//输入流
private var inStr: InputStream? = null
//状态
var connectstatus = false
//socket
private var client: Socket? = null
//接收缓存
private val sData = ByteArray(512)
//反馈接口
private var mListener: OnConnectSinsListener? = null
//服务
private val mBinder: MyBinder = MyBinder()
//接收集合
private val mTaskList = Collections.synchronizedList(ArrayList<String>())
//连接线程
private var connectThread: Thread? = null
//缓存ip
private var lastIp = ""
private val mHandler: Handler = object : Handler() {
override fun handleMessage(msg: Message) {
when (msg.what) {
0x11 -> if (mListener != null) {
if (msg.obj != null && msg.obj is NiLocation) {
mListener!!.onReceiveLocation(msg.obj as NiLocation)
} else {
mListener!!.onReceiveLocation(null)
}
}
0x22 -> //索引定位中
if (mListener != null) {
mListener!!.onIndexing()
}
0x33 -> if (mListener != null) {
mListener!!.onConnect(true)
}
0x44 -> if (mListener != null) {
mListener!!.onConnect(false)
}
0x55 -> if (mListener != null) {
mListener!!.onPlay()
}
0x66 -> if (mListener != null) {
mListener!!.onStop()
}
0x99 -> if (mListener != null) {
mListener!!.onParseEnd()
}
0x999 -> if (mListener != null) {
mListener!!.onConnect(false)
disconnect()
}
}
}
}
override fun onCreate() {
super.onCreate()
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
}
override fun onBind(intent: Intent): IBinder? {
return mBinder
}
inner class MyBinder : Binder() {
// 返回Activity所关联的Service对象这样在Activity里就可调用Service里的一些公用方法 和公用属性
val service: SocketServer
get() =// 返回Activity所关联的Service对象这样在Activity里就可调用Service里的一些公用方法 和公用属性
this@SocketServer
}
/**
* 启动sock连接
*
* @param ip
* @param listener 结果回调
*/
fun connect(ip: String, listener: OnConnectSinsListener?) {
if (connectThread != null && connectThread!!.isAlive && TextUtils.equals(lastIp, ip)) {
return
}
mListener = listener
lastIp = ip
connectThread = object : Thread() {
override fun run() {
try {
client = threadConnect.get()
if (client == null) {
client = Socket(ip, 8010)
client!!.soTimeout = 3000000
client!!.keepAlive = true
threadConnect.set(client)
}
outStr = client!!.getOutputStream()
inStr = client!!.getInputStream()
if (tRecv != null) {
tRecv!!.cancel()
}
tRecv = RecvThread()
val thread = Thread(tRecv)
thread.start()
//解析线程
if (tParse != null) {
tParse!!.cancel()
}
tParse = ParseThread()
val parsethread = Thread(tParse)
parsethread.start()
//socket启动成功
val msg = Message()
msg.what = 0x33
mHandler.sendMessage(msg)
if (!connectstatus) {
connectstatus = true // 更改连接状态
}
} catch (e: Exception) {
e.printStackTrace()
//启动失败
val msg = Message()
msg.what = 0x44
mHandler.sendMessage(msg)
}
}
}
(connectThread as Thread).start()
}
/**
* sock是否启动
*
* @return true 启动 false停止
*/
val isStart: Boolean
get() = if (connectThread != null && connectThread!!.isAlive) {
true
} else false
/**
* 销毁连接
*/
fun disconnect() {
try {
//销毁线程
if (tRecv != null) {
tRecv!!.cancel()
}
//销毁线程
if (tParse != null) {
tParse!!.cancel()
}
} catch (e: Exception) {
}
try {
if (outStr != null) outStr!!.close()
if (inStr != null) inStr!!.close()
if (client != null) client!!.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
/**
* 解析接收到得线程
*/
private inner class ParseThread : Runnable {
private var runFlag = true
//轨迹时间buffer
private val traceTimeBuffer = 1500
private var timeIndex = 0
fun cancel() {
runFlag = false
}
override fun run() {
try {
while (runFlag) {
if (mTaskList.size > 0) {
timeIndex = mTaskList.size - 1
val result = parseResult(mTaskList[timeIndex])
var resultNiLocation: NiLocation? = null
var index: Int = -1
if (result != null) {
when (result.type) {
1 -> {
//先暂停播放
val msg = Message()
msg.what = 0x22
mHandler.sendMessage(msg)
val currentTime: Long = DateTimeUtil.getTimePointSSS(
result.data
)
val currentTimeStr: String = DateTimeUtil.TimePointSSSToTime(
result.data
)
Log.e(TAG, "反向"+result.data)
val startTime = currentTime - traceTimeBuffer
val endTme = currentTime + traceTimeBuffer
//转换为数据库时间
val startTimeStr: String =
DateTimeUtil.getDateSimpleTime(startTime)
//转换为数据库时间
val endTimeStr: String =
DateTimeUtil.getDateSimpleTime(endTme)
if (!TextUtils.isEmpty(startTimeStr) && !TextUtils.isEmpty(
endTimeStr
)
) {
Log.e(TAG, "getTraceData开始")
val list: List<NiLocation>? = getTrackList(startTimeStr, endTimeStr, currentTimeStr)
Log.e(TAG, "getTraceData结束")
if (list != null && list.size > 0) {
var disTime: Long = 0
//只有一个点不进行判断直接返回结果
if (list.size == 1) {
resultNiLocation = list[0]
} else {
//遍历集合取最近时间的轨迹点
b@ for (nilocation in list) {
if (!TextUtils.isEmpty(nilocation.time)) {
//只获取到秒的常量
val time: Long =
nilocation.timeStamp.toLong()
val disTimeTemp = abs(time - currentTime)
//如果时间相同直接返回该点
if (disTimeTemp == 0L) {
resultNiLocation = nilocation
break@b
} else {
//第一次不对比,取当前值
if (disTime == 0L) {
disTime = disTimeTemp
resultNiLocation = nilocation
} else {
//前一个差值大于当前差值则取当前相对小的值
if (disTime - disTimeTemp > 0) {
disTime = disTimeTemp
resultNiLocation = nilocation
}
}
}
}
}
}
}
}
val msg1 = Message()
msg1.what = 0x11
msg1.obj = resultNiLocation
if (resultNiLocation != null) {
Log.e(TAG, "反向app"+resultNiLocation.time)
}
mHandler.sendMessage(msg1)
}
2 -> {
val msg4 = Message()
msg4.what = 0x55
mHandler.sendMessage(msg4)
}
3 -> {
val msg5 = Message()
msg5.what = 0x66
mHandler.sendMessage(msg5)
}
}
}
//解析时索引与集合索引对比,如果不相同代表有新命令,需要继续解析最后一条,否则清空集合不在解析
try {
if (timeIndex == mTaskList.size - 1) {
mTaskList.clear()
}
} catch (e: Exception) {
}
val msg2 = Message()
msg2.what = 0x99
mHandler.sendMessage(msg2)
}
}
Thread.sleep(10)
} catch (e: Exception) {
e.printStackTrace()
val msg = Message()
msg.what = 0x99
mHandler.sendMessage(msg)
}
}
}
/**
* 获取轨迹数据
*
* @param startTimeStr 起始时间
* @param endTimeStr 结束时间
* @param currentTimeStr 当前点时间如果存在便直接获取一个点
* @return list 数据集合
*/
private fun getTrackList(
startTimeStr: String,
endTimeStr: String,
currentTimeStr: String
): List<NiLocation>? {
if (!TextUtils.isEmpty(startTimeStr) && !TextUtils.isEmpty(endTimeStr)) {
var startTime: Long = 0
var endTime: Long = 0
try {
startTime = startTimeStr.toLong()
endTime = endTimeStr.toLong()
} catch (e: java.lang.Exception) {
}
if (startTime != 0L && endTime != 0L) {
val id = sharedPreferences.getInt(Constant.SELECT_TASK_ID, -1)
val list: MutableList<NiLocation> = traceDataBase.niLocationDao.findToTaskIdAll(id.toString())
if (list.size > 0) return list
}
}
return null
}
/**
* 接收管道数据
*/
private inner class RecvThread : Runnable {
private var runFlag = true
fun cancel() {
runFlag = false
}
override fun run() {
var rlRead: Int
try {
while (runFlag) {
var line: String = ""
if (!isServerClose) {
rlRead = inStr!!.read(sData) //对方断开返回-1
if (rlRead > 0) {
Log.e(TAG, sData.toString() + "")
line = String(sData, 0, rlRead)
mTaskList.add(line)
} else {
connectFaild("连接断开")
}
} else {
connectFaild("连接断开")
}
}
Thread.sleep(10)
} catch (e: IOException) {
connectFaild(e.toString())
e.printStackTrace()
}
}
}
/**
* 连接失败
* @param e 原因
*/
private fun connectFaild(e: String) {
val msg2 = Message()
msg2.what = 0x999
mHandler.sendMessage(msg2)
}
/**
* 判断是否断开连接断开返回true,没有返回false
* @return
*/
val isServerClose: Boolean
get() {
return try {
client!!.sendUrgentData(0) //发送1个字节的紧急数据默认情况下服务器端没有开启紧急数据处理不影响正常通信
false
} catch (se: Exception) {
true
}
}
/**
* 停止接收管道数据
*/
fun stop() {
Log.e(TAG, "stop!")
connectstatus = false
if (tRecv != null) {
tRecv!!.cancel()
}
if (tParse != null) {
tParse!!.cancel()
}
}
/**
* 开始接收管道数据
*/
fun start() {
Log.e(TAG, "start!")
if (tRecv != null) {
tRecv!!.cancel()
}
tRecv = RecvThread()
val thread = Thread(tRecv)
thread.start()
//解析线程
if (tParse != null) {
tParse!!.cancel()
}
tParse = ParseThread()
val parsethread = Thread(tParse)
parsethread.start()
}
fun setTraceMap() {
}
/**
* 轨迹反向控制回调接口
*/
interface OnConnectSinsListener {
/**
* 连接状态
*
* @param success true 连接成功 false 连接失败
*/
fun onConnect(success: Boolean)
/**
* 索引中
*/
fun onIndexing()
/**
* 暂停
*/
fun onStop()
/**
* 播放
*/
fun onPlay()
/**
* 结束完成
*/
fun onParseEnd()
/**
* 轨迹点
*
* @param mNiLocation
*/
fun onReceiveLocation(mNiLocation: NiLocation?)
}
/**
* 解析返回值
*
* @return 时间信息
*/
private fun parseResult(data: String): Result? {
var data = data
if (!TextUtils.isEmpty(data)) {
try {
data = data.replace("\n".toRegex(), "")
val json = JSONObject(data)
val type = json.optInt("type")
val mResult: Result = Result()
mResult.type = type
if (type == 1) {
mResult.data = json.optString("data", "")
}
return mResult
} catch (e: Exception) {
}
}
return null
}
//结果类对象
internal inner class Result : Serializable {
var type = 0
var data: String? = null
}
}

View File

@ -9,14 +9,10 @@ import androidx.lifecycle.viewModelScope
import com.navinfo.omqs.Constant
import com.navinfo.omqs.bean.IndoorConnectionInfoBean
import com.navinfo.omqs.bean.QRCodeBean
import com.navinfo.omqs.bean.SysUserBean
import com.navinfo.omqs.http.DefaultResponse
import com.navinfo.omqs.http.NetResult
import com.navinfo.omqs.http.NetworkService
import com.navinfo.omqs.ui.activity.login.LoginStatus
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.IOException
@ -37,6 +33,7 @@ enum class QrCodeStatus {
* 信息更新成功
*/
QR_CODE_STATUS_SERVER_INFO_SUCCESS,
}
@HiltViewModel
@ -99,11 +96,14 @@ class QrCodeViewModel @Inject constructor(
Toast.LENGTH_LONG
).show()
}
updateServerInfo(context)
} else {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
"${defaultUserResponse.msg}",
"${defaultUserResponse.errmsg}",
Toast.LENGTH_SHORT
)
.show()
@ -165,17 +165,20 @@ class QrCodeViewModel @Inject constructor(
viewModelScope.launch(Dispatchers.Default) {
val url = "http://${Constant.INDOOR_IP}:8080/sensor/service/connection"
val indoorConnectionInfoBean = IndoorConnectionInfoBean(
Constant.USER_ID,
Constant.USER_ID,
Constant.USER_ID,
"eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2ODk2MjI5MjQsInVzZXJJZCI6IjEwNCIsImlhdCI6MTY4OTU3MjUyNCwidXNlcm5hbWUiOiJ3ZWl3ZWlsaW4wMDEwNCJ9.9WUqOhme8Yi_2xRBKMMe0ihb_yR1uwTqWTdZfZ7dMtE",
"http://fastmap.navinfo.com/onemap",
Constant.USER_ID,
"Android"
)
when (val result = networkService.updateServerInfo(
url = url,
indoorConnectionInfoBean = IndoorConnectionInfoBean(
Constant.USER_ID,
Constant.USER_ID,
Constant.USER_ID,
Constant.USER_ID,
com.navinfo.collect.library.system.Constant.SERVER_ADDRESS,
Constant.USER_ID,
"Android"
)
indoorConnectionInfoBean = indoorConnectionInfoBean
)) {
is NetResult.Success<*> -> {
@ -198,7 +201,7 @@ class QrCodeViewModel @Inject constructor(
withContext(Dispatchers.Main) {
Toast.makeText(
context,
"${defaultUserResponse.msg}",
"${defaultUserResponse.errmsg}",
Toast.LENGTH_SHORT
)
.show()

View File

@ -676,6 +676,7 @@ public class CommonDialog extends Dialog implements SurfaceHolder.Callback, IVid
//当前为连接时启动已有的状态
if (connectstate) {
mOneBtConnect.setPressed(true);
mOneBtConnect.setBackgroundResource(R.drawable.shape_btn_red_disconnect_bg);
@ -1525,7 +1526,7 @@ public class CommonDialog extends Dialog implements SurfaceHolder.Callback, IVid
}
//连接
private void connection(HostBean hostBean) {
public void connection(HostBean hostBean) {
if (hostBean != null) {
SensorParams params = new SensorParams();

View File

@ -193,14 +193,29 @@ class ConsoleFragment : BaseFragment(), OnClickListener {
R.id.console_personal_center_bg, R.id.console_personal_center_icon_bg -> {
if (sceneFlag) {
mFragment = PersonalCenterFragment {
TransitionManager.go(aScene, aTransition)
if(it){
activity?.let { a ->
a.supportFragmentManager.beginTransaction().remove(this).commit()
(a as MainActivity).showIndoorDataLayout()
}
}else{
TransitionManager.go(aScene, aTransition)
}
}
sceneFlag = false
TransitionManager.go(bScene, bTransition)
} else {
if (mFragment !is PersonalCenterFragment) {
mFragment = PersonalCenterFragment {
TransitionManager.go(aScene, aTransition)
if(it){
activity?.let { a ->
a.supportFragmentManager.beginTransaction().remove(this).commit()
(a as MainActivity).showIndoorDataLayout()
}
}else{
TransitionManager.go(aScene, aTransition)
}
}
childFragmentManager.beginTransaction().replace(fragmentId, mFragment!!)
.commit()

View File

@ -32,18 +32,27 @@ class EmptyFragment : Fragment() {
override fun onStart() {
super.onStart()
val currentDestination = findNavController().currentDestination
//有右侧面板的时候
if (currentDestination?.label == "右侧空页面") {
currentDestinationLabel = "右侧空页面"
(activity as MainActivity).setRightSwitchButton(View.GONE)
currentDestination?.let {
//有右侧面板的时候
currentDestinationLabel = it.label.toString()
if (it.label == "右侧空页面") {
(activity as MainActivity).setRightSwitchButtonVisibility(View.GONE)
(activity as MainActivity).setTopMenuButtonVisibility(View.VISIBLE)
} else if (it.label == "中间空页面") {
(activity as MainActivity).setRightButtonsVisible(View.VISIBLE)
}
}
}
override fun onStop() {
super.onStop()
//没有有右侧面板的时候
if (currentDestinationLabel == "右侧空页面") {
(activity as MainActivity).setRightSwitchButton(View.VISIBLE)
(activity as MainActivity).setRightSwitchButtonVisibility(View.VISIBLE)
(activity as MainActivity).setTopMenuButtonVisibility(View.GONE)
} else if (currentDestinationLabel == "中间空页面") {
(activity as MainActivity).setRightButtonsVisible(View.GONE)
}
}

View File

@ -1,12 +1,17 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.*
import android.widget.Toast
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.databinding.DataBindingUtil
import androidx.navigation.NavOptions
import androidx.navigation.findNavController
@ -21,12 +26,12 @@ import com.navinfo.omqs.ui.dialog.FirstDialog
import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.other.shareViewModels
import dagger.hilt.android.AndroidEntryPoint
import org.videolan.vlc.Util
@AndroidEntryPoint
class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
private lateinit var binding: FragmentEvaluationResultBinding
private var mCameraLauncher: ActivityResultLauncher<Intent>? = null
/**
* [PhenomenonFragment],[ProblemLinkFragment],[EvaluationResultFragment]共用同一个viewModel
@ -37,6 +42,23 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
PictureAdapter()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mCameraLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
// 处理相机返回的结果
val extras = result.data!!.extras
val imageBitmap: Bitmap? = extras!!["data"] as Bitmap?
// 在这里处理图片数据
if (imageBitmap != null)
viewModel.savePhoto(imageBitmap)
}
}
}
// private val args:EmptyFragmentArgs by navArgs()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
@ -44,37 +66,28 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
binding =
DataBindingUtil.inflate(inflater, R.layout.fragment_evaluation_result, container, false)
binding.fragment = this
val layoutManager = LinearLayoutManager(context)
binding.viewModel = viewModel
binding.lifecycleOwner = this
//// 设置 RecyclerView 的固定大小,避免在滚动时重新计算视图大小和布局,提高性能
binding.evaluationVoiceRecyclerview.setHasFixedSize(true)
binding.evaluationVoiceRecyclerview.layoutManager = layoutManager
/**
* 监听左侧栏的点击事件
*/
val adapter = SoundtListAdapter { _, view ->
}
binding.evaluationVoiceRecyclerview.adapter = adapter
viewModel.listDataChatMsgEntityList.observe(viewLifecycleOwner) {
adapter.refreshData(it)
}
binding.evaluationPictureViewpager
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//监听是否退出当前页面
viewModel.liveDataFinish.observe(viewLifecycleOwner) {
onBackPressed()
//// 设置 RecyclerView 的固定大小,避免在滚动时重新计算视图大小和布局,提高性能
binding.evaluationVoiceRecyclerview.setHasFixedSize(true)
val layoutManager = LinearLayoutManager(context)
binding.evaluationVoiceRecyclerview.layoutManager = layoutManager
/**
* 监听左侧栏的点击事件
*/
val adapter = SoundtListAdapter { _, _ ->
}
binding.evaluationVoiceRecyclerview.adapter = adapter
//返回按钮点击
binding.evaluationBar.setOnClickListener() {
binding.evaluationBar.setOnClickListener {
val mDialog = FirstDialog(context)
mDialog.setTitle("提示?")
mDialog.setMessage("是否退出,请确认!")
@ -89,15 +102,13 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
}
//保存事件
binding.evaluationBarSave.setOnClickListener() {
binding.evaluationBarSave.setOnClickListener {
viewModel.saveData()
}
//删除事件
binding.evaluationBarDelete.setOnClickListener() {
binding.evaluationBarDelete.setOnClickListener {
viewModel.deleteData(requireContext())
}
/**
* 照片view
@ -106,15 +117,26 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
val list = mutableListOf("1", "2", "3")
pictureAdapter.refreshData(list)
//照片左右选择键点击监听
binding.evaluationPictureLeft.setOnClickListener(this)
binding.evaluationPictureRight.setOnClickListener(this)
binding.evaluationCamera.setOnClickListener(this)
//设置照片偏移量
val viewPager = binding.evaluationPictureViewpager
val vto = viewPager.viewTreeObserver
vto.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
val width = viewPager.width
// 处理View宽度
// 在回调完成后需要将监听器从View树中移除以避免重复调用
viewPager.viewTreeObserver.removeOnGlobalLayoutListener(this)
val recyclerView = viewPager.getChildAt(0) as RecyclerView
val recyclerView = binding.evaluationPictureViewpager.getChildAt(0) as RecyclerView
recyclerView.setPadding(0, 0, Util.convertDpToPx(requireContext(), 50), 0)
recyclerView.clipToPadding = false
recyclerView.setPadding(0, 0, width / 2 - 30, 0)
recyclerView.clipToPadding = false
}
})
binding.evaluationVoice.setOnTouchListener { _, event ->
Log.e("qj", event?.action.toString())
@ -123,11 +145,7 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
voiceOnTouchStart()//Do Something
}
MotionEvent.ACTION_UP -> {
voiceOnTouchStop()//Do Something
}
MotionEvent.ACTION_CANCEL -> {
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_OUTSIDE -> {
voiceOnTouchStop()//Do Something
}
}
@ -138,22 +156,21 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
/**
* 读取元数据
*/
// val id = args.qsId
var id = ""
var signBean: SignBean? = null
var autoSave: Boolean = false
var filePath: String = ""
var autoSave = false
var filePath = ""
arguments?.let {
id = it.getString("QsId", "")
filePath = it.getString("filePath", "")
try {
signBean = it.getParcelable("SignBean")
autoSave = it.getBoolean("AutoSave")
} catch (e: java.lang.Exception) {
} catch (_: java.lang.Exception) {
}
}
if (id == null || id.isEmpty()) {
if (id.isEmpty()) {
viewModel.initNewData(signBean, filePath)
//增加监听,联动列表自动保存
viewModel.liveDataRightTypeList.observe(viewLifecycleOwner) {
@ -164,102 +181,22 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
} else {
viewModel.initData(id)
}
// //监听大分类数据变化
// viewModel.liveDataClassTypeList.observe(viewLifecycleOwner) {
// if (it == null || it.isEmpty()) {
// Toast.makeText(requireContext(), "还没有导入元数据!", Toast.LENGTH_SHORT).show()
// } else {
// binding.evaluationClassType.adapter =
// ArrayAdapter(requireContext(), R.layout.text_item_select, it)
// }
// }
//
// viewModel.liveDataProblemTypeList.observe(viewLifecycleOwner){
// if (it == null || it.isEmpty()) {
// Toast.makeText(requireContext(), "还没有导入元数据!", Toast.LENGTH_SHORT).show()
// }else{
// binding.evaluationProblemType.adapter =
// ArrayAdapter(requireContext(), R.layout.text_item_select, it)
// }
// }
// //选择问题分类的回调
// binding.evaluationClassType.onItemSelectedListener =
// object : AdapterView.OnItemSelectedListener {
// override fun onItemSelected(
// parent: AdapterView<*>?, view: View?, position: Int, id: Long
// ) {
// viewModel.getProblemTypeList(position)
// }
//
// override fun onNothingSelected(parent: AdapterView<*>?) {}
// }
// /**
// * 监听联动选择的内容
// */
// viewModel.problemTypeListLiveData.observe(viewLifecycleOwner) {
// binding.evaluationClassTabLayout.let { tabLayout ->
// tabLayout.removeAllTabs()
// val fragmentList = mutableListOf<Fragment>()
// for (item in it) {
// val tab = tabLayout.newTab()
// tab.text = item
// tabLayout.addTab(tab)
// fragmentList.add(PhenomenonFragment(viewModel.currentClassType, item))
// }
// phenomenonFragmentAdapter =
// activity?.let { a -> EvaluationResultAdapter(a, fragmentList) }
// binding.evaluationViewpager.adapter = phenomenonFragmentAdapter
//
// TabLayoutMediator(
// binding.evaluationClassTabLayout,
// binding.evaluationViewpager
// ) { tab, position ->
// tab.text = it[position]
// }.attach()
// updateHeight(0)
// }
//
// }
viewModel.listDataChatMsgEntityList.observe(viewLifecycleOwner) {
adapter.refreshData(it)
}
//监听是否退出当前页面
viewModel.liveDataFinish.observe(viewLifecycleOwner) {
onBackPressed()
}
//监听要提示的信息
viewModel.liveDataToastMessage.observe(viewLifecycleOwner) {
Toast.makeText(requireContext(), it, Toast.LENGTH_SHORT).show()
}
// binding.evaluationViewpager.registerOnPageChangeCallback(object :
// ViewPager2.OnPageChangeCallback() {
// override fun onPageSelected(position: Int) {
// super.onPageSelected(position)
// updateHeight(position)
// }
// })
}
// private fun updateHeight(position: Int) {
// phenomenonFragmentAdapter?.let {
// if (it.fragmentList.size > position) {
// val fragment: Fragment = it.fragmentList[position]
// if (fragment.view != null) {
// val viewWidth = View.MeasureSpec.makeMeasureSpec(
// fragment.requireView().width, View.MeasureSpec.EXACTLY
// )
// val viewHeight =
// View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
// fragment.requireView().measure(viewWidth, viewHeight)
// binding.evaluationViewpager.let { viewpager ->
// if (viewpager.layoutParams.height != fragment.requireView().measuredHeight) {
// //必须要用对象去接收,然后修改该对象再采用该对象,否则无法生效...
// val layoutParams: ViewGroup.LayoutParams =
// viewpager.layoutParams
// layoutParams.height = fragment.requireView().measuredHeight
// viewpager.layoutParams = layoutParams
// }
// }
//
// }
// }
// }
//
// }
override fun onDestroyView() {
activity?.run {
findNavController(R.id.main_activity_middle_fragment).navigateUp()
@ -279,6 +216,7 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
if (currentItem > 0) {
binding.evaluationPictureViewpager.currentItem = currentItem - 1
} else {
return
}
}
@ -288,7 +226,7 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
if (currentItem < pictureAdapter.data.size - 1) {
binding.evaluationPictureViewpager.currentItem = currentItem + 1
} else {
return
}
}
//上三项,打开面板
@ -338,8 +276,12 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
}
}
else -> {}
R.id.evaluation_camera -> {
takePhoto()
}
else -> {
return
}
}
}
}
@ -362,4 +304,14 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener {
return true
}
private fun takePhoto() {
try {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent.resolveActivity(requireActivity().packageManager) != null) {
mCameraLauncher!!.launch(takePictureIntent)
}
} catch (e: Exception) {
Log.d("TTTT", e.toString())
}
}
}

View File

@ -3,6 +3,8 @@ package com.navinfo.omqs.ui.fragment.evaluationresult
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.SharedPreferences
import android.graphics.Bitmap
import android.graphics.drawable.AnimationDrawable
import android.graphics.drawable.BitmapDrawable
import android.os.Build
@ -19,9 +21,12 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.ToastUtils
import com.navinfo.collect.library.data.entity.AttachmentBean
import com.navinfo.collect.library.data.entity.HadLinkDvoBean
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.collect.library.data.entity.RenderEntity.Companion.LinkTable
import com.navinfo.collect.library.data.entity.TaskBean
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.collect.library.map.OnGeoPointClickListener
import com.navinfo.collect.library.utils.GeometryTools
import com.navinfo.omqs.Constant
import com.navinfo.omqs.R
@ -35,17 +40,14 @@ import com.navinfo.omqs.util.DateTimeUtil
import com.navinfo.omqs.util.SoundMeter
import com.navinfo.omqs.util.SpeakMode
import dagger.hilt.android.lifecycle.HiltViewModel
import io.realm.OrderedCollectionChangeSet
import io.realm.Realm
import io.realm.RealmList
import io.realm.RealmModel
import io.realm.RealmResults
import io.realm.kotlin.addChangeListener
import io.realm.kotlin.where
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.oscim.core.GeoPoint
import java.io.File
import java.io.FileOutputStream
import java.util.*
import javax.inject.Inject
@ -54,9 +56,11 @@ class EvaluationResultViewModel @Inject constructor(
private val roomAppDatabase: RoomAppDatabase,
private val mapController: NIMapController,
private val realmOperateHelper: RealmOperateHelper,
) : ViewModel() {
private val sharedPreferences: SharedPreferences
) : ViewModel(), SharedPreferences.OnSharedPreferenceChangeListener {
private val markerTitle = "点选marker"
private val TAG = "点选marker"
/**
* 操作结束销毁页面
@ -68,20 +72,40 @@ class EvaluationResultViewModel @Inject constructor(
*/
val liveDataLeftTypeList = MutableLiveData<List<ScProblemTypeBean>>()
/**
* 问题类型 liveData [MiddleAdapter]展示的数据
*/
// val liveDataMiddleTypeList = MutableLiveData<List<String>>()
/**
* 问题现象 liveData [RightGroupHeaderAdapter]展示的数据
*/
val liveDataRightTypeList = MutableLiveData<List<RightBean>>()
var liveDataQsRecordBean = MutableLiveData<QsRecordBean>()
/**
* 要保存的评测数据
*/
val liveDataQsRecordBean = MutableLiveData(QsRecordBean(id = UUID.randomUUID().toString()))
var listDataChatMsgEntityList = MutableLiveData<MutableList<ChatMsgEntity>>()
/**
* 语音列表
*/
val listDataChatMsgEntityList = MutableLiveData<MutableList<ChatMsgEntity>>()
/**
* 照片列表
*/
val liveDataPictureList = MutableLiveData<MutableList<String>>()
/**
* toast信息
*/
val liveDataToastMessage = MutableLiveData<String>()
/**
* 当前选择的任务
*/
val liveDataTaskBean = MutableLiveData<TaskBean>()
/**
* 编辑数据时用来差分数据
*/
var oldBean: QsRecordBean? = null
//语音窗体
@ -99,24 +123,27 @@ class EvaluationResultViewModel @Inject constructor(
var classCodeTemp: String = ""
init {
liveDataQsRecordBean.value = QsRecordBean(id = UUID.randomUUID().toString())
viewModelScope.launch {
mapController.onMapClickFlow.collect {
liveDataQsRecordBean.value!!.geometry = GeometryTools.createGeometry(it).toText()
mapController.markerHandle.addMarker(it, markerTitle)
viewModelScope.launch {
captureLink(it.longitude, it.latitude)
mapController.mMapView.addOnNIMapClickListener(TAG, object : OnGeoPointClickListener {
override fun onMapClick(tag: String, point: GeoPoint) {
if (tag == TAG) {
liveDataQsRecordBean.value!!.geometry =
GeometryTools.createGeometry(point).toText()
mapController.markerHandle.addMarker(point, TAG)
viewModelScope.launch {
captureLink(point)
}
}
}
}
})
sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}
override fun onCleared() {
super.onCleared()
mapController.markerHandle.removeMarker(markerTitle)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mapController.lineHandler.removeLine()
}
mapController.mMapView.removeOnNIMapClickListener(TAG)
mapController.markerHandle.removeMarker(TAG)
mapController.lineHandler.removeLine()
}
@ -124,42 +151,57 @@ class EvaluationResultViewModel @Inject constructor(
* 查询数据库获取问题分类
*/
fun initNewData(bean: SignBean?, filePath: String) {
//获取当前定位点
val geoPoint = mapController.locationLayerHandler.getCurrentGeoPoint()
//如果不是从面板进来的
if (bean == null) {
geoPoint?.let {
liveDataQsRecordBean.value!!.geometry = GeometryTools.createGeometry(it).toText()
mapController.markerHandle.addMarker(geoPoint, markerTitle)
mapController.animationHandler.animationByLatLon(
geoPoint.latitude, geoPoint.longitude
)
viewModelScope.launch {
captureLink(geoPoint.longitude, geoPoint.latitude)
}
//查询元数据
viewModelScope.launch(Dispatchers.IO) {
/**
* 获取当前所选的任务
*/
val taskId = sharedPreferences.getInt(Constant.SELECT_TASK_ID, -1)
val realm = Realm.getDefaultInstance()
val objects = realm.where(TaskBean::class.java).equalTo("id", taskId).findFirst()
if (objects != null) {
liveDataTaskBean.postValue(realm.copyFromRealm(objects))
}
} else {
liveDataQsRecordBean.value?.run {
elementId = bean.renderEntity.code.toString()
linkId = bean.linkId
if (linkId.isNotEmpty()) {
viewModelScope.launch {
val link = realmOperateHelper.queryLink(linkId)
link?.let { l ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//获取当前定位点
val geoPoint = mapController.locationLayerHandler.getCurrentGeoPoint()
//如果不是从面板进来的
if (bean == null) {
geoPoint?.let {
liveDataQsRecordBean.value!!.geometry =
GeometryTools.createGeometry(it).toText()
withContext(Dispatchers.Main) {
mapController.markerHandle.addMarker(geoPoint, TAG)
mapController.animationHandler.animationByLatLon(
geoPoint.latitude, geoPoint.longitude
)
}
captureLink(geoPoint)
}
} else {
liveDataQsRecordBean.value?.run {
elementId = bean.renderEntity.code.toString()
linkId = bean.linkId
if (linkId.isNotEmpty()) {
viewModelScope.launch {
val link = realmOperateHelper.queryLink(linkId)
link?.let { l ->
mapController.lineHandler.showLine(l.geometry)
}
}
}
val point = GeometryTools.createGeoPoint(bean.renderEntity.geometry)
this.geometry = GeometryTools.createGeometry(point).toText()
withContext(Dispatchers.Main) {
mapController.animationHandler.animationByLatLon(
point.latitude, point.longitude
)
mapController.markerHandle.addMarker(point, TAG)
}
}
val point = GeometryTools.createGeoPoint(bean.renderEntity.geometry)
this.geometry = GeometryTools.createGeometry(point).toText()
mapController.animationHandler.animationByLatLon(point.latitude, point.longitude)
mapController.markerHandle.addMarker(point, markerTitle)
}
}
//查询元数据
viewModelScope.launch(Dispatchers.IO) {
getClassTypeList(bean)
getProblemLinkList()
}
@ -167,23 +209,32 @@ class EvaluationResultViewModel @Inject constructor(
}
/**
* 捕捉道路
* 捕捉道路或新增评测link
*/
private suspend fun captureLink(longitude: Double, latitude: Double) {
private suspend fun captureLink(point: GeoPoint) {
if (liveDataTaskBean.value == null) {
liveDataToastMessage.postValue("请先选择所属任务!")
return
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val linkList = realmOperateHelper.queryLink(
point = GeoPoint(latitude, longitude),
)
liveDataQsRecordBean.value?.let {
if (linkList.isNotEmpty()) {
it.linkId = linkList[0].properties[LinkTable.linkPid] ?: ""
mapController.lineHandler.showLine(linkList[0].geometry)
Log.e("jingo", "捕捉到的linkId = ${it.linkId}")
val taskLink =
realmOperateHelper.captureTaskLink(liveDataTaskBean.value!!.id, point)
if (taskLink != null) {
it.linkId = taskLink.linkPid
mapController.lineHandler.showLine(taskLink.geometry)
return
} else {
it.linkId = ""
mapController.lineHandler.removeLine()
val linkList = realmOperateHelper.queryLink(point = point)
if (linkList.isNotEmpty()) {
it.linkId = linkList[0].properties[LinkTable.linkPid] ?: ""
mapController.lineHandler.showLine(linkList[0].geometry)
return
}
}
it.linkId = ""
mapController.lineHandler.removeLine()
}
}
}
@ -201,10 +252,12 @@ class EvaluationResultViewModel @Inject constructor(
var classCode = list[0].elementCode
liveDataLeftTypeList.postValue(it)
if (bean != null) {
val classType2 = roomAppDatabase.getScProblemTypeDao().findClassTypeByCode(bean.renderEntity.code)
val classType2 = roomAppDatabase.getScProblemTypeDao()
.findClassTypeByCode(bean.renderEntity.code)
if (classType2 != null) {
classType = classType2
}
classCode = bean.renderEntity.code.toString()
}
//如果右侧栏没数据,给个默认值
if (liveDataQsRecordBean.value!!.classType.isEmpty()) {
@ -291,11 +344,12 @@ class EvaluationResultViewModel @Inject constructor(
/**
* 查询问题类型列表
*/
fun getProblemTypeList(classType: String) {
fun getProblemTypeList(scProblemTypeBean: ScProblemTypeBean) {
viewModelScope.launch(Dispatchers.IO) {
getProblemList(classType)
getProblemList(scProblemTypeBean.classType)
}
classTypeTemp = classType
classTypeTemp = scProblemTypeBean.classType
classCodeTemp = scProblemTypeBean.elementCode
}
/**
@ -315,19 +369,52 @@ class EvaluationResultViewModel @Inject constructor(
liveDataQsRecordBean.postValue(liveDataQsRecordBean.value)
}
/**
* 保存数据
*/
fun saveData() {
viewModelScope.launch(Dispatchers.IO) {
val taskBean = liveDataQsRecordBean.value!!
if (liveDataTaskBean.value == null) {
liveDataToastMessage.postValue("请选择所属任务!")
return@launch
} else if (taskBean.classType.isEmpty()) {
liveDataToastMessage.postValue("请选择要素分类!")
return@launch
} else if (taskBean.problemType.isEmpty()) {
liveDataToastMessage.postValue("请选择问题类型!")
return@launch
} else if (taskBean.phenomenon.isEmpty()) {
liveDataToastMessage.postValue("请选择问题现象!")
return@launch
} else if (taskBean.problemLink.isEmpty()) {
liveDataToastMessage.postValue("请选择问题环节!")
return@launch
} else if (taskBean.classType.isEmpty()) {
liveDataToastMessage.postValue("请选择问题分类!")
return@launch
} else if (taskBean.cause.isEmpty()) {
liveDataToastMessage.postValue("请选择初步分析原因!")
return@launch
}
val realm = Realm.getDefaultInstance()
liveDataQsRecordBean.value!!.taskId = liveDataTaskBean.value!!.id
liveDataQsRecordBean.value!!.checkTime = DateTimeUtil.getDataTime()
liveDataQsRecordBean.value!!.checkUserId = Constant.USER_REAL_NAME
realm.executeTransaction {
it.copyToRealmOrUpdate(liveDataQsRecordBean.value)
}
// realm.close()
mapController.markerHandle.addOrUpdateQsRecordMark(liveDataQsRecordBean.value!!)
liveDataFinish.postValue(true)
}
}
/**
* 删除数据
*/
fun deleteData(context: Context) {
val mDialog = FirstDialog(context)
mDialog.setTitle("提示?")
@ -357,160 +444,222 @@ class EvaluationResultViewModel @Inject constructor(
*/
fun initData(id: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
viewModelScope.launch(Dispatchers.IO) {
viewModelScope.launch(Dispatchers.IO) {
Realm.getDefaultInstance().use { realm ->
realm.executeTransactionAsync { bgRealm ->
// find the item
val objects = bgRealm.where(QsRecordBean::class.java).equalTo("id", id).findFirst()
if (objects != null) {
oldBean = bgRealm.copyFromRealm(objects)
oldBean?.let {
liveDataQsRecordBean.postValue(it.copy())
val p = GeometryTools.createGeoPoint(it.geometry)
mapController.markerHandle.addMarker(GeoPoint(p.latitude, p.longitude), markerTitle)
val realm = Realm.getDefaultInstance()
val objects = realm.where(QsRecordBean::class.java).equalTo("id", id).findFirst()
Log.e("jingo", "查询数据 id= $id")
if (objects != null) {
oldBean = realm.copyFromRealm(objects)
oldBean?.let {
/**
* 获取当前所选的任务
*/
val objects =
realm.where(TaskBean::class.java).equalTo("id", it.taskId).findFirst()
if (objects != null) {
liveDataTaskBean.postValue(realm.copyFromRealm(objects))
}
//获取linkid
if (it.linkId.isNotEmpty()) {
viewModelScope.launch(Dispatchers.IO) {
val link = realmOperateHelper.queryLink(it.linkId)
link?.let { l ->
mapController.lineHandler.showLine(l.geometry)
}
}
}
liveDataQsRecordBean.value?.attachmentBeanList = it.attachmentBeanList
// 显示语音数据到界面
getChatMsgEntityList()
liveDataQsRecordBean.postValue(it.copy())
val p = GeometryTools.createGeoPoint(it.geometry)
mapController.markerHandle.addMarker(
GeoPoint(
p.latitude, p.longitude
), TAG, "", null
)
//获取linkid
if (it.linkId.isNotEmpty()) {
val link = realmOperateHelper.queryLink(it.linkId)
if (link != null) {
mapController.lineHandler.showLine(link.geometry)
} else {
val realmR = realm.where(HadLinkDvoBean::class.java)
.equalTo("linkPid", it.linkId).and().equalTo("taskId", it.taskId)
.findFirst()
if (realmR != null) {
mapController.lineHandler.showLine(realmR.geometry)
}
}
}
liveDataQsRecordBean.value?.attachmentBeanList = it.attachmentBeanList
// 显示语音数据到界面
getChatMsgEntityList()
}
} else {
liveDataToastMessage.postValue("数据读取失败")
}
}
}
/**
* 查询问题类型列表
*/
private suspend fun getChatMsgEntityList() {
val chatMsgEntityList: MutableList<ChatMsgEntity> = ArrayList()
liveDataQsRecordBean.value?.attachmentBeanList?.forEach {
//1 录音
if (it.type == 1) {
val chatMsgEntity = ChatMsgEntity()
chatMsgEntity.name = it.name
chatMsgEntity.voiceUri = Constant.USER_DATA_ATTACHEMNT_PATH
chatMsgEntityList.add(chatMsgEntity)
}
}
listDataChatMsgEntityList.postValue(chatMsgEntityList)
}
fun addChatMsgEntity(filePath: String) {
if (filePath.isNotEmpty()) {
var chatMsgEntityList: MutableList<ChatMsgEntity> = ArrayList()
if (listDataChatMsgEntityList.value?.isEmpty() == false) {
chatMsgEntityList = listDataChatMsgEntityList.value!!
}
val chatMsgEntity = ChatMsgEntity()
chatMsgEntity.name = filePath.replace(Constant.USER_DATA_ATTACHEMNT_PATH, "").toString()
chatMsgEntity.voiceUri = Constant.USER_DATA_ATTACHEMNT_PATH
chatMsgEntityList.add(chatMsgEntity)
var attachmentList: RealmList<AttachmentBean> = RealmList()
//赋值处理
if (liveDataQsRecordBean.value?.attachmentBeanList?.isEmpty() == false) {
attachmentList = liveDataQsRecordBean.value?.attachmentBeanList!!
}
val attachmentBean = AttachmentBean()
attachmentBean.name = chatMsgEntity.name!!
attachmentBean.type = 1
attachmentList.add(attachmentBean)
liveDataQsRecordBean.value?.attachmentBeanList = attachmentList
listDataChatMsgEntityList.postValue(chatMsgEntityList)
}
}
fun startSoundMetter(activity: Activity, v: View) {
if (mSpeakMode == null) {
mSpeakMode = SpeakMode(activity)
}
//语音识别动画
if (pop == null) {
pop = PopupWindow()
pop!!.width = ViewGroup.LayoutParams.MATCH_PARENT
pop!!.height = ViewGroup.LayoutParams.WRAP_CONTENT
pop!!.setBackgroundDrawable(BitmapDrawable())
val view =
View.inflate(activity as Context, R.layout.cv_card_voice_rcd_hint_window, null)
pop!!.contentView = view
volume = view.findViewById(R.id.volume)
}
pop!!.update()
Constant.IS_VIDEO_SPEED = true
//录音动画
if (pop != null) {
pop!!.showAtLocation(v, Gravity.CENTER, 0, 0)
}
volume!!.setBackgroundResource(R.drawable.pop_voice_img)
val animation = volume!!.background as AnimationDrawable
animation.start()
val name: String = DateTimeUtil.getTimeSSS().toString() + ".m4a"
if (mSoundMeter == null) {
mSoundMeter = SoundMeter()
}
mSoundMeter!!.setmListener(object : SoundMeter.OnSoundMeterListener {
@RequiresApi(Build.VERSION_CODES.Q)
override fun onSuccess(filePath: String?) {
if (!TextUtils.isEmpty(filePath) && File(filePath).exists()) {
if (File(filePath) == null || File(filePath).length() < 1600) {
ToastUtils.showLong("语音时间太短,无效!")
mSpeakMode!!.speakText("语音时间太短,无效")
stopSoundMeter()
return
}
}
mSpeakMode!!.speakText("结束录音")
addChatMsgEntity(filePath!!)
}
@RequiresApi(api = Build.VERSION_CODES.Q)
override fun onfaild(message: String?) {
ToastUtils.showLong("录制失败!")
mSpeakMode!!.speakText("录制失败")
stopSoundMeter()
}
})
mSoundMeter!!.start(Constant.USER_DATA_ATTACHEMNT_PATH + name)
ToastUtils.showLong("开始录音")
mSpeakMode!!.speakText("开始录音")
}
//停止语音录制
@RequiresApi(api = Build.VERSION_CODES.Q)
fun stopSoundMeter() {
//先重置标识,防止按钮抬起时触发语音结束
Constant.IS_VIDEO_SPEED = false
if (mSoundMeter != null && mSoundMeter!!.isStartSound) {
mSoundMeter!!.stop()
}
pop?.let {
if (it.isShowing) {
it.dismiss()
}
}
}
fun savePhoto(bitmap: Bitmap) {
viewModelScope.launch(Dispatchers.IO) {
// 创建一个名为 "MyApp" 的文件夹
val myAppDir = File(Constant.USER_DATA_ATTACHEMNT_PATH)
if (!myAppDir.exists()) myAppDir.mkdirs() // 确保文件夹已创建
// 创建一个名为 fileName 的文件
val file = File(myAppDir, "${UUID.randomUUID()}.png")
file.createNewFile() // 创建文件
// 将 Bitmap 压缩为 JPEG 格式,并将其写入文件中
val out = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out)
out.flush()
out.close()
var picList = mutableListOf<String>()
if (liveDataPictureList.value == null) {
picList.add(file.absolutePath)
} else {
picList.addAll(liveDataPictureList.value!!)
picList.add(file.absolutePath)
}
liveDataPictureList.postValue(picList)
}
}
/**
* 查询问题类型列表
* 监听任务选择变化
*/
@RequiresApi(Build.VERSION_CODES.N)
fun getChatMsgEntityList() {
val chatMsgEntityList: MutableList<ChatMsgEntity> = ArrayList()
liveDataQsRecordBean.value?.attachmentBeanList?.forEach {
//1 录音
if (it.type == 1) {
val chatMsgEntity = ChatMsgEntity()
chatMsgEntity.name = it.name
chatMsgEntity.voiceUri = Constant.USER_DATA_ATTACHEMNT_PATH
chatMsgEntityList.add(chatMsgEntity)
}
}
listDataChatMsgEntityList.postValue(chatMsgEntityList)
}
fun addChatMsgEntity(filePath: String) {
if (filePath.isNotEmpty()) {
var chatMsgEntityList: MutableList<ChatMsgEntity> = ArrayList()
if (listDataChatMsgEntityList.value?.isEmpty() == false) {
chatMsgEntityList = listDataChatMsgEntityList.value!!
}
val chatMsgEntity = ChatMsgEntity()
chatMsgEntity.name = filePath.replace(Constant.USER_DATA_ATTACHEMNT_PATH, "").toString()
chatMsgEntity.voiceUri = Constant.USER_DATA_ATTACHEMNT_PATH
chatMsgEntityList.add(chatMsgEntity)
var attachmentList: RealmList<AttachmentBean> = RealmList()
//赋值处理
if (liveDataQsRecordBean.value?.attachmentBeanList?.isEmpty() == false) {
attachmentList = liveDataQsRecordBean.value?.attachmentBeanList!!
}
val attachmentBean = AttachmentBean()
attachmentBean.name = chatMsgEntity.name!!
attachmentBean.type = 1
attachmentList.add(attachmentBean)
liveDataQsRecordBean.value?.attachmentBeanList = attachmentList
listDataChatMsgEntityList.postValue(chatMsgEntityList)
}
}
fun startSoundMetter(activity: Activity, v: View) {
if (mSpeakMode == null) {
mSpeakMode = SpeakMode(activity)
}
//语音识别动画
if (pop == null) {
pop = PopupWindow()
pop!!.width = ViewGroup.LayoutParams.MATCH_PARENT
pop!!.height = ViewGroup.LayoutParams.WRAP_CONTENT
pop!!.setBackgroundDrawable(BitmapDrawable())
val view =
View.inflate(activity as Context, R.layout.cv_card_voice_rcd_hint_window, null)
pop!!.contentView = view
volume = view.findViewById(R.id.volume)
}
pop!!.update()
Constant.IS_VIDEO_SPEED = true
//录音动画
if (pop != null) {
pop!!.showAtLocation(v, Gravity.CENTER, 0, 0)
}
volume!!.setBackgroundResource(R.drawable.pop_voice_img)
val animation = volume!!.background as AnimationDrawable
animation.start()
val name: String = DateTimeUtil.getTimeSSS().toString() + ".m4a"
if (mSoundMeter == null) {
mSoundMeter = SoundMeter()
}
mSoundMeter!!.setmListener(object : SoundMeter.OnSoundMeterListener {
@RequiresApi(Build.VERSION_CODES.Q)
override fun onSuccess(filePath: String?) {
if (!TextUtils.isEmpty(filePath) && File(filePath).exists()) {
if (File(filePath) == null || File(filePath).length() < 1600) {
ToastUtils.showLong("语音时间太短,无效!")
mSpeakMode!!.speakText("语音时间太短,无效")
stopSoundMeter()
return
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
if (key == Constant.SELECT_TASK_ID && oldBean == null) {
viewModelScope.launch(Dispatchers.IO) {
val taskId = sharedPreferences.getInt(Constant.SELECT_TASK_ID, -1)
val realm = Realm.getDefaultInstance()
val objects = realm.where(TaskBean::class.java).equalTo("id", taskId).findFirst()
if (objects != null) {
liveDataTaskBean.postValue(realm.copyFromRealm(objects))
}
mSpeakMode!!.speakText("结束录音")
addChatMsgEntity(filePath!!)
}
@RequiresApi(api = Build.VERSION_CODES.Q)
override fun onfaild(message: String?) {
ToastUtils.showLong("录制失败!")
mSpeakMode!!.speakText("录制失败")
stopSoundMeter()
}
})
mSoundMeter!!.start(Constant.USER_DATA_ATTACHEMNT_PATH + name)
ToastUtils.showLong("开始录音")
mSpeakMode!!.speakText("开始录音")
}
//停止语音录制
@RequiresApi(api = Build.VERSION_CODES.Q)
fun stopSoundMeter() {
//先重置标识,防止按钮抬起时触发语音结束
Constant.IS_VIDEO_SPEED = false
if (mSoundMeter != null && mSoundMeter!!.isStartSound()) {
mSoundMeter!!.stop()
}
if (pop != null && pop!!.isShowing) pop!!.dismiss()
}
}
}

View File

@ -1,16 +1,13 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
import android.os.Build
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import com.navinfo.omqs.R
import com.navinfo.omqs.bean.ScProblemTypeBean
import com.navinfo.omqs.databinding.TextItemSelectBinding
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder
class LeftAdapter(private var itemListener: ((Int, String) -> Unit?)? = null) :
class LeftAdapter(private var itemListener: ((Int, ScProblemTypeBean) -> Unit?)? = null) :
BaseRecyclerViewAdapter<ScProblemTypeBean>() {
private var selectTitle = ""
@ -21,7 +18,6 @@ class LeftAdapter(private var itemListener: ((Int, String) -> Unit?)? = null) :
return BaseViewHolder(viewBinding)
}
@RequiresApi(Build.VERSION_CODES.M)
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
val bd = holder.viewBinding as TextItemSelectBinding
val title = data[position]
@ -32,7 +28,7 @@ class LeftAdapter(private var itemListener: ((Int, String) -> Unit?)? = null) :
selectTitle = title.classType
notifyDataSetChanged()
}
itemListener?.invoke(position, title.classType)
itemListener?.invoke(position, title)
}
}

View File

@ -20,7 +20,6 @@ class MiddleAdapter(private var itemListener: ((Int, String) -> Unit?)? = null)
return BaseViewHolder(viewBinding)
}
@RequiresApi(Build.VERSION_CODES.M)
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
val bd = holder.viewBinding as TextItemSelectBinding
val title = data[position]
@ -30,10 +29,10 @@ class MiddleAdapter(private var itemListener: ((Int, String) -> Unit?)? = null)
bd.itemLayout.layoutParams = layoutParams
if (selectTitle == title) {
bd.itemId.setBackgroundResource(R.drawable.shape_bg_blue_bg_4_radius)
bd.itemId.setTextColor(holder.viewBinding.root.context.getColor(R.color.white))
bd.itemId.setTextColor(holder.viewBinding.root.context.resources.getColor(R.color.white))
} else {
bd.itemId.setBackgroundResource(R.drawable.shape_rect_white_2dp_bg)
bd.itemId.setTextColor(holder.viewBinding.root.context.getColor(R.color.black))
bd.itemId.setTextColor(holder.viewBinding.root.context.resources.getColor(R.color.black))
}
bd.root.setOnClickListener {
if (selectTitle != title) {

View File

@ -73,13 +73,11 @@ class PhenomenonFragment :
}
binding.phenomenonRightRecyclerview.adapter = rightAdapter
//右侧菜单增加组标题
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
binding.phenomenonRightRecyclerview.addItemDecoration(
RightGroupHeaderDecoration(
requireContext()
)
binding.phenomenonRightRecyclerview.addItemDecoration(
RightGroupHeaderDecoration(
requireContext()
)
}
)
//右侧菜单查询数据监听
viewModel.liveDataRightTypeList.observe(viewLifecycleOwner) {
rightAdapter.setSelectTitle(viewModel.liveDataQsRecordBean.value!!.phenomenon)

View File

@ -1,8 +1,6 @@
package com.navinfo.omqs.ui.fragment.evaluationresult
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -50,13 +48,11 @@ class ProblemLinkFragment : BaseFragment() {
}
binding.linkRightRecyclerview.adapter = rightAdapter
//右侧菜单增加组标题
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
binding.linkRightRecyclerview.addItemDecoration(
RightGroupHeaderDecoration(
requireContext()
)
binding.linkRightRecyclerview.addItemDecoration(
RightGroupHeaderDecoration(
requireContext()
)
}
)
//右侧菜单查询数据监听
viewModel.liveDataRightTypeList.observe(viewLifecycleOwner) {
rightAdapter.setSelectTitle(viewModel.liveDataQsRecordBean.value!!.cause)

View File

@ -5,9 +5,7 @@ import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.os.Build
import android.view.View
import androidx.annotation.RequiresApi
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
@ -17,7 +15,6 @@ import com.navinfo.omqs.R
/**
* 自定义装饰器实现分组+吸顶效果
*/
@RequiresApi(Build.VERSION_CODES.M)
class RightGroupHeaderDecoration(context: Context) : ItemDecoration() {
//头部的高
private val mItemHeaderHeight: Int
@ -35,7 +32,7 @@ class RightGroupHeaderDecoration(context: Context) : ItemDecoration() {
mTextPaddingLeft = dp2px(context, 6f)
mTextRect = Rect()
mItemHeaderPaint = Paint(Paint.ANTI_ALIAS_FLAG)
mItemHeaderPaint.color = context.getColor(R.color.btn_bg_blue)
mItemHeaderPaint.color = context.resources.getColor(R.color.btn_bg_blue)
mTextPaint = Paint(Paint.ANTI_ALIAS_FLAG)
mTextPaint.textSize = 46f
mTextPaint.color = Color.WHITE

View File

@ -0,0 +1,152 @@
package com.navinfo.omqs.ui.fragment.note
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.FragmentCanvasBinding
import com.navinfo.omqs.databinding.FragmentNoteBinding
import com.navinfo.omqs.databinding.FragmentProblemLinkBinding
import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.fragment.note.CanvasView.CanvasStyle
import com.navinfo.omqs.ui.fragment.note.CanvasView.OnCanvasChangeListener
import com.navinfo.omqs.ui.other.shareViewModels
/**
* @author zhjch
* @version V1.0
* @ClassName: CanvasFragment
* @Date 2016/5/10
* @Description: ${TODO}(绘制画布)
*/
class CanvasFragment : BaseFragment() {
/**
* 获取画布
*
* @return
*/
/**
* 画布
*/
private val canvasView by lazy { binding.canvasView }
/**
* 画笔线型
*/
private var mStyle = CanvasStyle.FREE_LINE
/**
* 画笔颜色
*/
private var mColor = -1
/**
* 画笔粗细
*/
private var width = 5
/**
* 画布回调接口
*/
private var listener: OnCanvasChangeListener? = null
private var _binding: FragmentCanvasBinding? = null
private val binding get() = _binding!!
private val viewModel by shareViewModels<NoteViewModel>("note")
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
_binding = FragmentCanvasBinding.inflate(inflater, container, false)
viewModel.initCanvasView(canvasView)
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
canvasView.setStyle(mStyle)
if (mColor == -1) {
mColor = resources.getColor(R.color.black)
}
canvasView.setPaintColor(mColor)
canvasView.setPaintWidth(width)
if (listener != null) {
canvasView.setOnCanvasChangeListener(listener)
}
// * 开关橡皮擦
// */
// viewModel.liveEraserData.observe(viewLifecycleOwner) {
// canvasView.setEraser(it)
// }
// /**
// * 清除
// */
// viewModel.liveClearData.observe(viewLifecycleOwner) {
// canvasView.removeAllPaint()
// }
// /**
// * 回退上一笔
// */
// viewModel.liveBackData.observe(viewLifecycleOwner) {
// canvasView.back()
// }
// /**
// * 撤销回退
// */
// viewModel.liveForward.observe(viewLifecycleOwner) {
// canvasView.forward()
// }
//
}
/**
* 将数据转化并绘制在画板上
*
* @param value
*/
fun setDrawPathList(value: MutableList<CanvasView.DrawPath>) {
if (value != null && value.isNotEmpty()) {
canvasView.setDrawPathList(value)
}
}
/**
* 设置草图画笔线型
*/
fun setStyle(style: CanvasStyle) {
mStyle = style
canvasView.setStyle(style)
}
/**
* 设置画笔颜色
*/
fun setPaintColor(color: Int) {
mColor = color
canvasView.setPaintColor(mColor)
}
/**
* 设置画笔粗细
*/
fun setPaintWidth(width: Int) {
this.width = width
canvasView.setPaintWidth(width)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,424 @@
package com.navinfo.omqs.ui.fragment.note
import android.graphics.Path
import android.graphics.Point
import android.graphics.Rect
import android.graphics.RectF
import android.text.TextUtils
import com.navinfo.collect.library.data.entity.NoteBean
import com.navinfo.collect.library.data.entity.SketchAttachContent
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.collect.library.utils.GeometryTools
import com.navinfo.omqs.ui.fragment.note.CanvasView.CanvasStyle
import io.realm.RealmList
import org.locationtech.jts.geom.Coordinate
import org.oscim.backend.canvas.Color
import org.oscim.core.GeoPoint
import java.util.UUID
import kotlin.math.abs
import kotlin.math.cos
import kotlin.math.sin
/**
* @author zhjch
* @version V1.0
* @ClassName: CanvasViewHelper
* @Date 2016/5/16
* @Description: ${TODO}(用一句话描述该文件做什么)
*/
object CanvasViewHelper {
private const val mD2I = 3600000
fun createNoteBean(
controller: NIMapController,
mCurrentPaths: List<CanvasView.DrawPath>,
): NoteBean {
val noteBean = NoteBean(UUID.randomUUID().toString())
if (mCurrentPaths.isNotEmpty()) {
val list: RealmList<SketchAttachContent> = RealmList<SketchAttachContent>()
noteBean.list = list
for (index in mCurrentPaths.indices) {
val dp: CanvasView.DrawPath = mCurrentPaths[index]
val geo = SketchAttachContent(UUID.randomUUID().toString())
val pointList = dp.pointList ?: continue
if (dp.style === CanvasStyle.GREENLAND_LINE || dp.style === CanvasStyle.WATER_LINE || dp.style === CanvasStyle.PARKING_LINE) {
val geoPointList = mutableListOf<GeoPoint>()
for (i in pointList.indices) {
val point = pointList[i]
val geoPoint: GeoPoint = controller.viewportHandler.fromScreenPoint(
point
)
geoPointList.add(geoPoint)
if (index == 0 && i == 0) {
noteBean.guideGeometry =
GeometryTools.createGeometry(geoPoint).toText()
}
}
geo.style = createLineStyle(dp.style, dp.width, dp.color)
geo.geometry = GeometryTools.createPolygon(geoPointList).toText()
} else if (dp.style === CanvasStyle.CIRCULAR_POINT) {
val point = pointList[0]
val geoPoint: GeoPoint = controller.viewportHandler.fromScreenPoint(point)
geo.style = createLineStyle(dp.style, dp.width, dp.color)
geo.geometry = GeometryTools.createGeometry(geoPoint).toText()
noteBean.guideGeometry = geo.geometry
} else if (dp.style === CanvasStyle.ELLIPSE_LINE) {
dp.rect?.let {
val pointLT = Point(it.left, it.top)
val pointRB = Point(it.right, it.bottom)
val geoPointLT: GeoPoint =
controller.viewportHandler.fromScreenPoint(pointLT)
val geoPointRB: GeoPoint =
controller.viewportHandler.fromScreenPoint(pointRB)
val minX: Double
val maxX: Double
val minY: Double
val maxY: Double
if (geoPointLT.longitude < geoPointRB.longitude) {
minX = (geoPointLT.longitude * mD2I)
maxX = (geoPointRB.longitude * mD2I)
} else {
minX = (geoPointRB.longitude * mD2I)
maxX = (geoPointLT.longitude * mD2I)
}
if (geoPointLT.latitude < geoPointRB.latitude) {
minY = (geoPointLT.latitude * mD2I)
maxY = (geoPointRB.latitude * mD2I)
} else {
minY = (geoPointRB.latitude * mD2I)
maxY = (geoPointLT.latitude * mD2I)
}
val xR = (maxX - minX) / 2
val yR = (maxY - minY) / 2
var a = 0.0
var tempX = xR * cos(a) + xR + minX
val tempY = yR * sin(a) + yR + minY
val firstX = tempX
val geoPointList = mutableListOf<GeoPoint>()
geoPointList.add(GeoPoint(tempX / mD2I, tempY / mD2I))
var bLeft = false
var bRight = false
var zeng = 0.1
if (controller.mMapView.mapLevel >= 20) {
zeng = 0.2
}
while (!bLeft || !bRight) {
a += zeng
val x1 = (xR * cos(a) + xR + minX).toInt().toDouble()
val y1 = (yR * sin(a) + yR + minY).toInt().toDouble()
if (!bLeft && x1 > tempX) {
bLeft = true
}
if (!bRight && bLeft && x1 <= tempX) {
bRight = true
geoPointList.add(
GeoPoint(
firstX / mD2I,
tempY / mD2I
)
)
} else {
tempX = x1
geoPointList.add(GeoPoint(x1 / mD2I, y1 / mD2I))
}
}
if (index == 0) {
noteBean.guideGeometry =
GeometryTools.createGeometry(geoPointList[0]).toText()
}
geo.style = createLineStyle(dp.style, dp.width, dp.color)
geo.geometry = GeometryTools.createLineString(geoPointList).toText()
}
} else {
val geoPointList = mutableListOf<GeoPoint>()
for (i in pointList.indices) {
val point = pointList[i]
val geoPoint: GeoPoint =
controller.viewportHandler.fromScreenPoint(point)
geoPointList.add(geoPoint)
if (index == 0 && i == 0) {
noteBean.guideGeometry =
GeometryTools.createGeometry(geoPoint).toText()
}
}
geo.style = createLineStyle(dp.style, dp.width, dp.color)
geo.geometry = GeometryTools.createLineString(geoPointList).toText()
}
list.add(geo)
}
}
return noteBean
}
fun createDrawPaths(
controller: NIMapController,
att: NoteBean
): MutableList<CanvasView.DrawPath> {
val contents: List<SketchAttachContent> = att.list
val drawPaths: MutableList<CanvasView.DrawPath> = mutableListOf()
var width = 5
var canvasStyle = CanvasStyle.FREE_LINE
var color = Color.BLACK
for (geo in contents) {
var max_x = 0
var max_y = 0
var min_x = 0
var min_y = 0
val style = geo.style
if (!TextUtils.isEmpty(style) && style.length > 3) {
try {
if (style.startsWith("4")) {
canvasStyle = CanvasStyle.RAILWAY_LINE
} else if (style.startsWith("5")) {
if (style.contains("cde3ac")) {
canvasStyle = CanvasStyle.GREENLAND_LINE
} else if (style.contains("abcaff")) {
canvasStyle = CanvasStyle.WATER_LINE
} else if (style.contains("fffe98")) {
canvasStyle = CanvasStyle.PARKING_LINE
}
} else {
val s = style.substring(0, 1)
if (TextUtils.equals(s, "2")) {
canvasStyle = CanvasStyle.STRAIGHT_LINE
} else if (TextUtils.equals(s, "3")) {
canvasStyle = CanvasStyle.RECT_LINE
} else if (TextUtils.equals(s, "6")) {
canvasStyle = CanvasStyle.POLY_LINE
} else if (TextUtils.equals(s, "7")) {
canvasStyle = CanvasStyle.ELLIPSE_LINE
} else if (TextUtils.equals(s, "9")) {
canvasStyle = CanvasStyle.CIRCULAR_POINT
} else if (TextUtils.equals(s, "1")) {
canvasStyle = CanvasStyle.FREE_LINE
}
width = style.substring(1, 3).toInt()
var colorStr = style.substring(3, style.length)
if (colorStr.length == 6) {
colorStr = "ff$colorStr"
} else if (colorStr.length == 8) {
} else {
colorStr = "ff000000"
}
color = colorStr.toLong(16).toInt()
}
} catch (e: Exception) {
e.printStackTrace()
}
val path = Path()
val pointList: MutableList<Point> = ArrayList()
if (canvasStyle === CanvasStyle.GREENLAND_LINE || canvasStyle === CanvasStyle.WATER_LINE || canvasStyle === CanvasStyle.PARKING_LINE) {
// val polygonGeometry: PolygonGeometry = geo.geo as PolygonGeometry
// if (polygonGeometry != null) {
// val xyz: Array<Array<DoubleArray>> = polygonGeometry.getCoordinates()
// if (xyz != null && xyz.isNotEmpty() && xyz[0].size > 1) {
// var geoPoint: GeoPoint? = GeoPoint(xyz[0][0][0], xyz[0][0][1])
// val movePoint: Point = .geoToScreen(geoPoint)
// max_x = movePoint.x
// max_y = movePoint.y
// min_x = movePoint.x
// min_y = movePoint.y
// path.reset()
// path.moveTo(movePoint.x.toFloat(), movePoint.y.toFloat())
// pointList.add(Point(movePoint.x, movePoint.y))
// for (i in 1 until xyz[0].size) {
// val x_y = xyz[0][i]
// if (x_y != null) {
// geoPoint = GeoPoint(x_y[0], x_y[1])
// val point: Point = projection.geoToScreen(geoPoint)
// if (point.x > max_x) {
// max_x = point.x
// }
// if (point.x < min_x) {
// min_x = point.x
// }
// if (point.y > max_y) {
// max_y = point.y
// }
// if (point.y < min_y) {
// min_y = point.y
// }
// path.lineTo(point.x.toFloat(), point.y.toFloat())
// pointList.add(point)
// }
// }
// path.close()
// }
// }
// val drawPath =
// CanvasView.DrawPath(pointList[0], path, width, color, canvasStyle)
// val rect = Rect(min_x, min_y, max_x, max_y)
// drawPath.rect = rect
// drawPath.pointList = pointList
// drawPaths.add(drawPath)
} else if (canvasStyle === CanvasStyle.CIRCULAR_POINT) {
// val pointGeometry: PointGeometry = geo.geo as PointGeometry
// if (pointGeometry != null && pointGeometry.getCoordinates() != null) {
// val geoPoint: GeoPoint = GeoPoint(
// pointGeometry.getCoordinates().get(0),
// pointGeometry.getCoordinates().get(1)
// )
// val movePoint: Point = projection.geoToScreen(geoPoint)
// pointList.add(movePoint)
// val drawPath = DrawPath(movePoint, path, width, color, canvasStyle)
// val rect = Rect(
// movePoint.x - width - 20,
// movePoint.y - width - 20,
// movePoint.x + width + 20,
// movePoint.y + width + 20
// )
// drawPath.rect = rect
// drawPath.pointList = pointList
// drawPaths.add(drawPath)
// }
} else if (canvasStyle === CanvasStyle.ELLIPSE_LINE) {
// val lineGeometry = GeometryTools.createGeometry(geo.geometry)
// if (lineGeometry != null) {
// val xys: Array<out Coordinate> = lineGeometry.coordinates
// if (xys != null && xys.size > 1) {
// var geoPoint: GeoPoint? = GeoPoint(xys[0].y, xys[0].x)
// val movePoint: Point = projection.geoToScreen(geoPoint)
// max_x = movePoint.x
// max_y = movePoint.y
// min_x = movePoint.x
// min_y = movePoint.y
// path.reset()
// path.moveTo(movePoint.x.toFloat(), movePoint.y.toFloat())
// pointList.add(Point(movePoint.x, movePoint.y))
// for (i in 1 until xys.size) {
// val x_y = xys[i]
// geoPoint = GeoPoint(x_y[0], x_y[1])
// val point: Point = projection.geoToScreen(geoPoint)
// if (point.x > max_x) {
// max_x = point.x
// }
// if (point.x < min_x) {
// min_x = point.x
// }
// if (point.y > max_y) {
// max_y = point.y
// }
// if (point.y < min_y) {
// min_y = point.y
// }
// pointList.add(point)
// }
// path.addOval(
// RectF(
// min_x.toFloat(),
// min_y.toFloat(),
// max_x.toFloat(),
// max_y.toFloat()
// ), Path.Direction.CW
// )
// }
// }
// val drawPath =
// CanvasView.DrawPath(pointList[0], path, width, color, canvasStyle)
// val rect = Rect(min_x, min_y, max_x, max_y)
// drawPath.rect = rect
// drawPath.pointList = pointList
// drawPaths.add(drawPath)
} else {
val lineGeometry = GeometryTools.createGeometry(geo.geometry)
if (lineGeometry != null) {
val xys: Array<out Coordinate> = lineGeometry.coordinates
if (xys.size > 1) {
var geoPoint = GeoPoint(xys[0].y, xys[0].x)
val movePoint: Point =
controller.viewportHandler.toScreenPoint(geoPoint)
max_x = movePoint.x
max_y = movePoint.y
min_x = movePoint.x
min_y = movePoint.y
path.reset()
path.moveTo(movePoint.x.toFloat(), movePoint.y.toFloat())
pointList.add(Point(movePoint.x, movePoint.y))
for (i in 1 until xys.size) {
val x_y = xys[i]
geoPoint = GeoPoint(x_y.y, x_y.x)
val point: Point =
controller.viewportHandler.toScreenPoint(geoPoint)
if (point.x > max_x) {
max_x = point.x
}
if (point.x < min_x) {
min_x = point.x
}
if (point.y > max_y) {
max_y = point.y
}
if (point.y < min_y) {
min_y = point.y
}
if (canvasStyle === CanvasStyle.FREE_LINE) {
val dx = abs(point.x - movePoint.x).toFloat()
val dy = abs(point.y - movePoint.y).toFloat()
if (dx >= 4 || dy >= 4) {
path.quadTo(
movePoint.x.toFloat(),
movePoint.y.toFloat(),
((point.x + movePoint.x) / 2).toFloat(),
((point.y + movePoint.y) / 2).toFloat()
) //源代码是这样写的,可是我没有弄明白,为什么要这样?
movePoint.x = point.x
movePoint.y = point.y
}
} else {
path.lineTo(point.x.toFloat(), point.y.toFloat())
}
pointList.add(point)
}
}
}
val drawPath =
CanvasView.DrawPath(pointList[0], path, width, color, canvasStyle)
val rect = Rect(min_x, min_y, max_x, max_y)
drawPath.rect = rect
drawPath.pointList = pointList
drawPaths.add(drawPath)
}
}
}
return drawPaths
}
private fun createLineStyle(canvasStyle: CanvasStyle, width: Int, color: Int): String {
val style = StringBuilder()
if (canvasStyle === CanvasStyle.RAILWAY_LINE) {
return "4060070c004ffffff16"
} else if (canvasStyle === CanvasStyle.GREENLAND_LINE) {
return "50200b050cde3ac"
} else if (canvasStyle === CanvasStyle.WATER_LINE) {
return "50200b050abcaff"
} else if (canvasStyle === CanvasStyle.PARKING_LINE) {
return "502a6a6a6fffe98"
}
if (canvasStyle === CanvasStyle.STRAIGHT_LINE) {
style.append("2")
} else if (canvasStyle === CanvasStyle.RECT_LINE) {
style.append("3")
} else if (canvasStyle === CanvasStyle.POLY_LINE) {
style.append("6")
} else if (canvasStyle === CanvasStyle.ELLIPSE_LINE) {
style.append("7")
} else if (canvasStyle === CanvasStyle.CIRCULAR_POINT) {
style.append("9")
} else {
style.append("1")
}
if (width < 10) {
style.append("0")
}
style.append(width.toString())
try {
var colorString = Integer.toHexString(color).toString()
if (colorString.length == 8) {
colorString = TextUtils.substring(colorString, 2, 8)
}
style.append(colorString)
} catch (e: Exception) {
e.printStackTrace()
}
return style.toString()
}
}

View File

@ -0,0 +1,135 @@
package com.navinfo.omqs.ui.fragment.note
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.FragmentNoteBinding
import com.navinfo.omqs.ui.dialog.FirstDialog
import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.other.shareViewModels
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class NoteFragment : BaseFragment(), View.OnClickListener {
private var _binding: FragmentNoteBinding? = null
private val binding get() = _binding!!
private val viewModel by shareViewModels<NoteViewModel>("note")
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
_binding = FragmentNoteBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.sketchEraser.setOnClickListener(this)
binding.sketchClear.setOnClickListener(this)
binding.sketchForward.setOnClickListener(this)
binding.sketchBack.setOnClickListener(this)
binding.noteBarSave.setOnClickListener(this)
binding.noteBarCancel.setOnClickListener(this)
binding.noteBarDelete.setOnClickListener(this)
binding.noteDescription.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
viewModel.noteBeanDescription = s.toString()
}
})
/**
* 数据操作结束
*/
viewModel.liveDataFinish.observe(viewLifecycleOwner) {
if (it)
onBackPressed()
}
/**
* 画布初始化完成
*/
viewModel.liveDataCanvasViewInitFinished.observe(viewLifecycleOwner) {
if (it)
arguments?.let { b ->
val id = b.getString("NoteId", "")
if (id.isNotEmpty()) {
viewModel.initData(id)
}
}
}
}
override fun onStart() {
super.onStart()
activity?.run {
findNavController(
R.id.main_activity_middle_fragment
).navigate(R.id.CanvasFragment)
}
}
override fun onStop() {
super.onStop()
activity?.run {
findNavController(
R.id.main_activity_middle_fragment
).navigateUp()
}
}
override fun onClick(v: View) {
when (v) {
binding.sketchEraser -> {
viewModel.onEraser()
binding.sketchEraser.isSelected = viewModel.isEraser
}
binding.sketchBack -> {
viewModel.onBack()
}
binding.sketchForward -> {
viewModel.onForward()
}
binding.sketchClear -> {
viewModel.onClear()
}
binding.noteBarSave -> {
viewModel.onSaveData()
}
binding.noteBarDelete -> {
viewModel.deleteData(requireContext())
}
binding.noteBarCancel -> {
//返回按钮点击
val mDialog = FirstDialog(context)
mDialog.setTitle("提示?")
mDialog.setMessage("是否退出,请确认!")
mDialog.setPositiveButton(
"确定"
) { _, _ ->
mDialog.dismiss()
onBackPressed()
}
mDialog.setNegativeButton("取消", null)
mDialog.show()
}
}
}
override fun onBackPressed(): Boolean {
findNavController().navigateUp()
return true
}
}

View File

@ -0,0 +1,171 @@
package com.navinfo.omqs.ui.fragment.note
import android.content.Context
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.navinfo.collect.library.data.entity.NoteBean
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.omqs.ui.dialog.FirstDialog
import dagger.hilt.android.lifecycle.HiltViewModel
import io.realm.Realm
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class NoteViewModel @Inject constructor(
val mapController: NIMapController
) : ViewModel() {
lateinit var canvasView: CanvasView
var mNoteBean: NoteBean? = null
var isEraser = false
var noteBeanDescription = ""
// /**
// * 橡皮擦开关
// */
// val liveEraserData = MutableLiveData(false)
//
// /**
// * 清除按钮
// */
// val liveClearData = MutableLiveData(false)
//
// /**
// * 回退按钮
// */
// val liveBackData = MutableLiveData(false)
//
// /**
// * 撤销按钮
// */
// val liveForward = MutableLiveData(false)
/**
* 处理结束关闭fragment
*/
val liveDataFinish = MutableLiveData(false)
/**
* 通知页面画布初始化完成
*/
val liveDataCanvasViewInitFinished = MutableLiveData(false)
fun initCanvasView(canvasView: CanvasView) {
this.canvasView = canvasView
liveDataCanvasViewInitFinished.value = true
}
/**
* 通知橡皮擦开关
*/
fun onEraser() {
isEraser = !isEraser
canvasView.setEraser(isEraser)
// liveEraserData.value = !liveEraserData.value!!
}
/**
* 通知清除
*/
fun onClear() {
canvasView.removeAllPaint()
// liveClearData.value = true
}
/**
* 通知回退
*/
fun onBack() {
canvasView.back()
// liveBackData.value = true
}
/**
* 通知撤销回退
*/
fun onForward() {
canvasView.forward()
// liveForward.value = true
}
/**
* 保存数据
*/
fun onSaveData() {
viewModelScope.launch(Dispatchers.IO) {
if (canvasView.paths != null && canvasView.paths!!.isNotEmpty()) {
var noteBean =
CanvasViewHelper.createNoteBean(mapController, canvasView.paths!!)
if (mNoteBean != null) {
noteBean.id = mNoteBean!!.id
noteBean.description = noteBeanDescription
}
mNoteBean = noteBean
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
it.copyToRealmOrUpdate(noteBean)
}
mapController.markerHandle.addOrUpdateNoteMark(mNoteBean!!)
liveDataFinish.postValue(true)
}
}
}
/**
* 删除数据
*/
fun deleteData(context: Context) {
if (mNoteBean == null) {
liveDataFinish.postValue(true)
return
} else {
val mDialog = FirstDialog(context)
mDialog.setTitle("提示?")
mDialog.setMessage("是否删除标签,请确认!")
mDialog.setPositiveButton(
"确定"
) { dialog, _ ->
dialog.dismiss()
viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
val objects = it.where(NoteBean::class.java)
.equalTo("id", mNoteBean!!.id).findFirst()
objects?.deleteFromRealm()
}
mapController.markerHandle.removeNoteMark(mNoteBean!!)
liveDataFinish.postValue(true)
}
}
mDialog.setNegativeButton("取消", null)
mDialog.show()
}
}
/**
* 初始化数据
*/
fun initData(id: String) {
viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
realm.executeTransaction { it ->
val objects = it.where(NoteBean::class.java)
.equalTo("id", id).findFirst()
mNoteBean = realm.copyFromRealm(objects)
mNoteBean?.let { bean ->
noteBeanDescription = bean.description
val list = CanvasViewHelper.createDrawPaths(mapController, bean)
canvasView.setDrawPathList(list)
}
}
}
}
}

View File

@ -15,14 +15,18 @@ import com.blankj.utilcode.util.UriUtils
import com.github.k1rakishou.fsaf.FileChooser
import com.github.k1rakishou.fsaf.callback.FSAFActivityCallbacks
import com.github.k1rakishou.fsaf.callback.FileChooserCallback
import com.navinfo.collect.library.data.entity.TaskBean
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.omqs.Constant
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.FragmentPersonalCenterBinding
import com.navinfo.omqs.db.ImportOMDBHelper
import com.navinfo.omqs.hilt.ImportOMDBHiltFactory
import com.navinfo.omqs.tools.CoroutineUtils
import com.navinfo.omqs.ui.activity.map.MainActivity
import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.activity.scan.QrCodeActivity
import com.navinfo.omqs.ui.fragment.console.ConsoleFragment
import com.permissionx.guolindev.PermissionX
import dagger.hilt.android.AndroidEntryPoint
import org.oscim.core.GeoPoint
@ -32,7 +36,7 @@ import javax.inject.Inject
* 个人中心
*/
@AndroidEntryPoint
class PersonalCenterFragment(private var backListener: (() -> Unit?)? = null) : BaseFragment(),
class PersonalCenterFragment(private var indoorDataListener: ((Boolean) -> Unit?)? = null) : BaseFragment(),
FSAFActivityCallbacks {
private var _binding: FragmentPersonalCenterBinding? = null
@ -111,8 +115,15 @@ class PersonalCenterFragment(private var backListener: (() -> Unit?)? = null) :
}
})
}
R.id.personal_center_menu_open_auto_location -> {
Constant.AUTO_LOCATION = true
}
R.id.personal_center_menu_close_auto_location -> {
Constant.AUTO_LOCATION = false
}
R.id.personal_center_menu_test -> {
viewModel.readRealmData()
//116.25017070328308 40.061730653134696
// 定位到指定位置
niMapController.mMapView.vtmMap.animator()
.animateTo(GeoPoint( 39.7991980627346,116.50936676873703 ))
@ -136,6 +147,9 @@ class PersonalCenterFragment(private var backListener: (() -> Unit?)? = null) :
//跳转二维码扫描界面
checkPermission()
}
R.id.personal_center_menu_scan_indoor_data -> {
indoorDataListener?.invoke(true)
}
}
true
}

View File

@ -1,8 +1,9 @@
package com.navinfo.omqs.ui.fragment.personalcenter
import android.net.Uri
import android.os.Build
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.annotation.RequiresApi
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@ -16,17 +17,13 @@ import com.navinfo.omqs.bean.ScRootCauseAnalysisBean
import com.navinfo.omqs.db.ImportOMDBHelper
import com.navinfo.omqs.db.RealmOperateHelper
import com.navinfo.omqs.db.RoomAppDatabase
import com.navinfo.omqs.tools.MetadataUtils
import com.navinfo.omqs.tools.MetadataUtils.Companion.ScProblemTypeTitle
import com.navinfo.omqs.tools.MetadataUtils.Companion.ScRootCauseAnalysisTitle
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.apache.commons.io.input.BOMInputStream
import java.io.*
import java.nio.charset.Charset
import java.text.Normalizer
import java.util.*
import javax.inject.Inject
@ -43,6 +40,7 @@ class PersonalCenterViewModel @Inject constructor(
/**
* 导入OMDB数据
* */
@RequiresApi(Build.VERSION_CODES.N)
suspend fun obtainOMDBZipData(importOMDBHelper: ImportOMDBHelper) {
Log.d("OMQSApplication", "开始生成数据")
// Realm.getDefaultInstance().beginTransaction()
@ -164,11 +162,13 @@ class PersonalCenterViewModel @Inject constructor(
/**
* 导入OMDB数据
* */
fun importOMDBData(importOMDBHelper: ImportOMDBHelper) {
fun importOMDBData(importOMDBHelper: ImportOMDBHelper,taskId:Int?=0) {
viewModelScope.launch(Dispatchers.IO) {
Log.d("OMQSApplication", "开始导入数据")
importOMDBHelper.importOmdbZipFile(importOMDBHelper.omdbFile).collect {
Log.d("importOMDBData", it)
if (taskId != null) {
importOMDBHelper.importOmdbZipFile(importOMDBHelper.omdbFile, taskId).collect {
Log.d("importOMDBData", it)
}
}
Log.d("OMQSApplication", "导入数据完成")
}

View File

@ -0,0 +1,185 @@
package com.navinfo.omqs.ui.fragment.tasklink
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.FragmentTaskLinkBinding
import com.navinfo.omqs.ui.activity.map.MainActivity
import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.other.shareViewModels
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class TaskLinkFragment : BaseFragment(), View.OnClickListener {
private var _binding: FragmentTaskLinkBinding? = null
private val binding get() = _binding!!
@Inject
lateinit var mapController: NIMapController
private val viewModel by shareViewModels<TaskLinkViewModel>("taskLink")
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
_binding = FragmentTaskLinkBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
arguments?.let {
val id = it.getString("TaskLinkId")
if (id != null && id.isNotEmpty()){
viewModel.initData(id)
}
}
binding.taskLinkAddPoint.setOnClickListener(this)
binding.taskLinkKind.setOnClickListener(this)
binding.taskLinkFunctionalLevel.setOnClickListener(this)
binding.taskLinkDataLevel.setOnClickListener(this)
binding.taskLinkBarCancel.setOnClickListener(this)
binding.taskLinkBarSave.setOnClickListener(this)
binding.taskLinkBack.setOnClickListener(this)
binding.taskLinkClear.setOnClickListener(this)
binding.taskLinkBarDelete.setOnClickListener(this)
/**
* 数据操作结束
*/
viewModel.liveDataFinish.observe(viewLifecycleOwner) {
if (it)
onBackPressed()
}
/**
* 种别
*/
viewModel.liveDataSelectKind.observe(viewLifecycleOwner) {
binding.taskLinkKind.text = it?.title
}
/**
* 功能等级
*/
viewModel.liveDataSelectFunctionLevel.observe(viewLifecycleOwner) {
binding.taskLinkFunctionalLevel.text = it?.title
}
/**
* 数据等级
*/
viewModel.liveDataSelectDataLevel.observe(viewLifecycleOwner) {
binding.taskLinkDataLevel.text = it?.title
}
/**
* 当前选中任务
*/
viewModel.liveDataTaskBean.observe(viewLifecycleOwner) {
binding.taskLinkTaskName.text = it?.evaluationTaskName
}
/**
* viewModel 返回的文字信息
*/
viewModel.liveDataToastMessage.observe(viewLifecycleOwner) {
Toast.makeText(requireContext(), it, Toast.LENGTH_SHORT).show()
}
/**
* 线长度
*/
mapController.measureLayerHandler.lineLengthLiveData.observe(viewLifecycleOwner) {
binding.taskLinkLength.text = "${it}"
}
mapController.measureLayerHandler.tempLineDistanceLiveData.observe(viewLifecycleOwner) {
(activity as MainActivity).setHomeCenterText(it)
}
}
override fun onStart() {
super.onStart()
/**
* 显示地图准星
*/
activity?.let {
(activity as MainActivity).setHomeCenterVisibility(View.VISIBLE)
}
}
override fun onDestroy() {
super.onDestroy()
}
override fun onStop() {
super.onStop()
/**
* 隐藏地图准星
*/
requireActivity().findNavController(R.id.main_activity_middle_fragment).navigateUp()
activity?.let {
(activity as MainActivity).setHomeCenterVisibility(View.GONE)
}
}
override fun onClick(v: View) {
when (v) {
binding.taskLinkAddPoint -> {
viewModel.addPoint()
}
binding.taskLinkKind -> {
showMiddleFragment()
viewModel.setAdapterList(1)
}
binding.taskLinkFunctionalLevel -> {
showMiddleFragment()
viewModel.setAdapterList(2)
}
binding.taskLinkDataLevel -> {
showMiddleFragment()
viewModel.setAdapterList(3)
}
binding.taskLinkBarCancel -> {
onBackPressed()
}
binding.taskLinkBarSave -> {
viewModel.saveData()
}
binding.taskLinkBack -> {
viewModel.removeLinkLastPoint()
}
binding.taskLinkClear -> {
viewModel.clearLink()
}
binding.taskLinkBarDelete ->{
viewModel.deleteData(requireContext())
}
}
}
/**
* 显示中间面板
*/
private fun showMiddleFragment() {
activity?.run {
val controller = findNavController(
R.id.main_activity_middle_fragment
)
if (controller.currentDestination?.id == R.id.MiddleEmptyFragment)
controller.navigate(R.id.TaskLinkMiddleFragment)
}
}
override fun onBackPressed(): Boolean {
findNavController().navigateUp()
return true
}
}

View File

@ -0,0 +1,48 @@
package com.navinfo.omqs.ui.fragment.tasklink
import android.os.Build
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.AdapterElectronicEyeBinding
import com.navinfo.omqs.databinding.AdapterTaskLinkInfoBinding
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder
data class TaskLinkInfoAdapterItem(
val title: String,
val type: Int
)
class TaskLinkMiddleAdapter(private var itemListener: ((Int, TaskLinkInfoAdapterItem) -> Unit?)? = null) :
BaseRecyclerViewAdapter<TaskLinkInfoAdapterItem>() {
private var selectTitle = ""
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
val viewBinding =
AdapterTaskLinkInfoBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return BaseViewHolder(viewBinding)
}
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
val binding = holder.viewBinding as AdapterTaskLinkInfoBinding
binding.title.text = data[position].title
if (selectTitle == binding.title.text) {
binding.title.setBackgroundResource(R.drawable.shape_bg_blue_bg_4_radius)
binding.title.setTextColor(holder.viewBinding.root.context.resources.getColor(R.color.white))
} else {
binding.title.setBackgroundResource(R.drawable.shape_rect_white_2dp_bg)
binding.title.setTextColor(holder.viewBinding.root.context.resources.getColor(R.color.black))
}
binding.root.setOnClickListener {
if (selectTitle != data[position].title) {
selectTitle = data[position].title
notifyDataSetChanged()
}
itemListener?.invoke(position, data[position])
}
}
}

View File

@ -0,0 +1,77 @@
package com.navinfo.omqs.ui.fragment.tasklink
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.FragmentTaskLinkBinding
import com.navinfo.omqs.databinding.FragmentTaskLinkMiddleBinding
import com.navinfo.omqs.ui.activity.map.MainActivity
import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.fragment.evaluationresult.LeftAdapter
import com.navinfo.omqs.ui.other.shareViewModels
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class TaskLinkMiddleFragment : BaseFragment(), View.OnClickListener {
private var _binding: FragmentTaskLinkMiddleBinding? = null
private val binding get() = _binding!!
@Inject
lateinit var mapController: NIMapController
private val viewModel by shareViewModels<TaskLinkViewModel>("taskLink")
/**
* 监听左侧栏的点击事件
*/
val adapter = TaskLinkMiddleAdapter { _, item ->
viewModel.setAdapterSelectValve(item)
if (activity != null) {
requireActivity().findNavController(R.id.main_activity_middle_fragment).navigateUp()
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
_binding = FragmentTaskLinkMiddleBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.taskLinkMiddleRecyclerview.layoutManager = LinearLayoutManager(requireContext())
binding.taskLinkMiddleRecyclerview.adapter = adapter
viewModel.liveDataLeftAdapterList.observe(viewLifecycleOwner) {
adapter.refreshData(it)
}
}
override fun onStart() {
super.onStart()
}
override fun onStop() {
super.onStop()
}
override fun onClick(v: View) {
when (v) {
}
}
override fun onBackPressed(): Boolean {
findNavController().navigateUp()
return true
}
}

View File

@ -0,0 +1,366 @@
package com.navinfo.omqs.ui.fragment.tasklink
import android.app.Dialog
import android.content.Context
import android.content.SharedPreferences
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.navinfo.collect.library.data.entity.HadLinkDvoBean
import com.navinfo.collect.library.data.entity.LinkInfoBean
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.collect.library.data.entity.TaskBean
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.collect.library.utils.GeometryTools
import com.navinfo.omqs.Constant
import com.navinfo.omqs.ui.dialog.FirstDialog
import dagger.hilt.android.lifecycle.HiltViewModel
import io.realm.Realm
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.bson.codecs.UuidCodec
import org.bson.internal.UuidHelper
import org.oscim.core.GeoPoint
import java.util.UUID
import javax.inject.Inject
@HiltViewModel
class TaskLinkViewModel @Inject constructor(
private val mapController: NIMapController,
private val sharedPreferences: SharedPreferences
) : ViewModel(), SharedPreferences.OnSharedPreferenceChangeListener {
/**
* 种别
*/
private val kindList = listOf(
TaskLinkInfoAdapterItem("高速道路", 1),
TaskLinkInfoAdapterItem("城市高速", 2),
TaskLinkInfoAdapterItem("国道", 3),
TaskLinkInfoAdapterItem("省道", 4),
TaskLinkInfoAdapterItem("县道", 6),
TaskLinkInfoAdapterItem("乡镇村道路", 7),
TaskLinkInfoAdapterItem("其他道路", 8),
TaskLinkInfoAdapterItem("非引导道路", 9),
TaskLinkInfoAdapterItem("步行道路", 10),
TaskLinkInfoAdapterItem("人渡", 11),
TaskLinkInfoAdapterItem("轮渡", 13),
TaskLinkInfoAdapterItem("自行车道路", 15),
)
/**
* FunctionGrade 功能等级
*/
private val functionLevelList = listOf(
TaskLinkInfoAdapterItem("等级1", 1),
TaskLinkInfoAdapterItem("等级2", 2),
TaskLinkInfoAdapterItem("等级3", 3),
TaskLinkInfoAdapterItem("等级4", 4),
TaskLinkInfoAdapterItem("等级5", 5),
)
/**
* 数据级别
*/
private val dataLevelList = listOf(
TaskLinkInfoAdapterItem("Pro lane model(有高精车道模型覆盖的高速和城高link)", 1),
TaskLinkInfoAdapterItem("Lite lane model(有高精车道模型覆盖的普通路link)", 2),
TaskLinkInfoAdapterItem("Standard road model(其他link)", 3),
)
/**
* 处理结束关闭fragment`
*/
val liveDataFinish = MutableLiveData(false)
/**
* 左侧面板展示内容
*/
val liveDataLeftAdapterList = MutableLiveData<List<TaskLinkInfoAdapterItem>>()
/**
* 选择的种别
*/
val liveDataSelectKind = MutableLiveData<TaskLinkInfoAdapterItem?>()
/**
* 选择的功能等级
*/
val liveDataSelectFunctionLevel = MutableLiveData<TaskLinkInfoAdapterItem?>()
/**
* 选择的数据等级
*/
val liveDataSelectDataLevel = MutableLiveData<TaskLinkInfoAdapterItem?>()
/**
* 要提示的错误信息
*/
val liveDataToastMessage = MutableLiveData<String>()
/**
* 当前选中的任务
*/
val liveDataTaskBean = MutableLiveData<TaskBean?>()
/**
* 当前正在编辑的线
*/
private var hadLinkDvoBean: HadLinkDvoBean? = null
/**
* 当前正在选择哪个数据 1种别 2功能等级 3数据等级
*/
private var selectType = 0
init {
getTaskBean()
sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}
private fun getTaskBean() {
viewModelScope.launch(Dispatchers.IO) {
val id = sharedPreferences.getInt(Constant.SELECT_TASK_ID, -1)
val realm = Realm.getDefaultInstance()
val res = realm.where(TaskBean::class.java).equalTo("id", id).findFirst()
liveDataTaskBean.postValue(res?.let { realm.copyFromRealm(it) })
}
}
/**
* 编辑点
*/
fun addPoint() {
mapController.measureLayerHandler.drawLineOrPolygon(false)
}
/**
* 设置左侧面板要显示的内容
*/
fun setAdapterList(type: Int) {
selectType = type
when (type) {
1 -> liveDataLeftAdapterList.value = kindList
2 -> liveDataLeftAdapterList.value = functionLevelList
3 -> liveDataLeftAdapterList.value = dataLevelList
}
}
/**
* 返回左侧面板选择的内容
*/
fun setAdapterSelectValve(item: TaskLinkInfoAdapterItem) {
when (selectType) {
1 -> liveDataSelectKind.value = item
2 -> liveDataSelectFunctionLevel.value = item
3 -> liveDataSelectDataLevel.value = item
}
}
override fun onCleared() {
mapController.measureLayerHandler.clear()
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
super.onCleared()
}
/**
* 保存数据
*/
fun saveData() {
viewModelScope.launch(Dispatchers.Default) {
if (liveDataTaskBean.value == null) {
liveDataToastMessage.postValue("还没有选择任何一条任务!")
return@launch
}
if (mapController.measureLayerHandler.mPathLayer.points.size < 2) {
liveDataToastMessage.postValue("道路点少于2个")
return@launch
}
if (liveDataSelectKind.value == null) {
liveDataToastMessage.postValue("请选择种别!")
return@launch
}
if (liveDataSelectFunctionLevel.value == null) {
liveDataToastMessage.postValue("请选择功能等级!")
return@launch
}
if (liveDataSelectDataLevel.value == null) {
liveDataToastMessage.postValue("请选择数据等级!")
return@launch
}
val task: TaskBean = liveDataTaskBean.value!!
if (hadLinkDvoBean != null) {
hadLinkDvoBean!!.taskId = liveDataTaskBean.value!!.id
hadLinkDvoBean!!.length =
mapController.measureLayerHandler.lineLengthLiveData.value!!
hadLinkDvoBean!!.geometry =
GeometryTools.getLineString(mapController.measureLayerHandler.mPathLayer.points)
hadLinkDvoBean!!.linkInfo = LinkInfoBean(
kind = liveDataSelectKind.value!!.type,
functionLevel = liveDataSelectFunctionLevel.value!!.type,
dataLevel = liveDataSelectDataLevel.value!!.type,
)
for (l in task.hadLinkDvoList) {
if (l.linkPid == hadLinkDvoBean!!.linkPid) {
task.hadLinkDvoList.remove(l)
task.hadLinkDvoList.add(hadLinkDvoBean)
break
}
}
} else {
hadLinkDvoBean = HadLinkDvoBean(
taskId = liveDataTaskBean.value!!.id,
linkPid = UUID.randomUUID().toString(),
linkStatus = 3,
length = mapController.measureLayerHandler.lineLengthLiveData.value!!,
geometry = GeometryTools.getLineString(mapController.measureLayerHandler.mPathLayer.points),
linkInfo = LinkInfoBean(
kind = liveDataSelectKind.value!!.type,
functionLevel = liveDataSelectFunctionLevel.value!!.type,
dataLevel = liveDataSelectDataLevel.value!!.type,
)
)
task.hadLinkDvoList.add(hadLinkDvoBean)
}
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
it.copyToRealmOrUpdate(hadLinkDvoBean)
it.copyToRealmOrUpdate(task)
}
mapController.lineHandler.addTaskLink(hadLinkDvoBean!!)
sharedPreferences.edit()
.putString(Constant.SHARED_SYNC_TASK_LINK_ID, hadLinkDvoBean!!.linkPid)
.apply()
liveDataFinish.postValue(true)
}
}
/**
* 监听shared变化
*/
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
if (key == Constant.SELECT_TASK_ID) {
getTaskBean()
}
}
/**
* 绘制线的时候回退点
*/
fun removeLinkLastPoint() {
mapController.measureLayerHandler.drawLineBackspace()
}
/**
* 清除重绘
*/
fun clearLink() {
mapController.measureLayerHandler.clear()
}
/**
* 初始化数据
*/
fun initData(id: String) {
viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
val objects =
realm.where(HadLinkDvoBean::class.java).equalTo("linkPid", id)
.findFirst()
objects?.linkInfo?.let {
for (kind in kindList) {
if (kind.type == it.kind) {
liveDataSelectKind.postValue(kind)
break
}
}
for (function in functionLevelList) {
if (function.type == it.functionLevel) {
liveDataSelectFunctionLevel.postValue(function)
break
}
}
for (data in dataLevelList) {
if (data.type == it.dataLevel) {
liveDataSelectDataLevel.postValue(data)
break
}
}
}
val task =
realm.where(TaskBean::class.java).equalTo("id", objects?.taskId)
.findFirst()
if (task != null) {
liveDataTaskBean.postValue(realm.copyFromRealm(task))
}
hadLinkDvoBean = realm.copyFromRealm(objects)
withContext(Dispatchers.Main) {
mapController.measureLayerHandler.initPathLine(hadLinkDvoBean?.geometry!!)
}
}
}
/**
* 删除数据
*/
fun deleteData(context: Context) {
if (hadLinkDvoBean == null) {
liveDataFinish.value = true
return
}
val mDialog = FirstDialog(context)
mDialog.setTitle("提示?")
mDialog.setMessage("是否删除Mark请确认")
mDialog.setPositiveButton(
"确定"
) { _, _ ->
mDialog.dismiss()
viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
//先找到对应的任务
val task = it.where(TaskBean::class.java).equalTo("id", hadLinkDvoBean!!.taskId)
.findFirst()
//维护任务删除当前link
if (task != null) {
for (h in task.hadLinkDvoList) {
if (h.linkPid == hadLinkDvoBean!!.linkPid)
task.hadLinkDvoList.remove(h)
break
}
realm.copyToRealmOrUpdate(task)
}
//删除link
val objects = it.where(HadLinkDvoBean::class.java)
.equalTo("linkPid", hadLinkDvoBean!!.linkPid).findFirst()
objects?.deleteFromRealm()
//删除相关联的评测任务
val qsRecordBeans = it.where(QsRecordBean::class.java)
.equalTo("linkId", hadLinkDvoBean!!.linkPid).and()
.equalTo("taskId", hadLinkDvoBean!!.taskId).findAll()
if (qsRecordBeans != null) {
for (b in qsRecordBeans) {
mapController.markerHandle.removeQsRecordMark(b)
}
qsRecordBeans.deleteAllFromRealm()
}
}
mapController.lineHandler.removeTaskLink(hadLinkDvoBean!!.linkPid)
mapController.mMapView.vtmMap.updateMap(true)
liveDataFinish.postValue(true)
}
}
mDialog.setNegativeButton("取消", null)
mDialog.show()
}
}

View File

@ -11,7 +11,7 @@ import com.navinfo.omqs.ui.other.BaseViewHolder
interface TaskAdapterCallback {
fun itemOnClick(bean: HadLinkDvoBean)
fun editOnclick(position: Int, bean: HadLinkDvoBean)
fun editOnClick(position: Int, bean: HadLinkDvoBean)
}
/**
@ -54,7 +54,7 @@ class TaskAdapter(
}
binding.taskEdit.isSelected = bean.reason != ""
binding.taskEdit.setOnClickListener {
callback.editOnclick(position, bean)
callback.editOnClick(position, bean)
}
}

View File

@ -1,7 +1,6 @@
package com.navinfo.omqs.ui.fragment.tasklist
import android.app.AlertDialog
import android.content.DialogInterface
import android.os.Build
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
@ -16,14 +15,14 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.navinfo.collect.library.data.entity.HadLinkDvoBean
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.FragmentTaskBinding
import com.navinfo.omqs.databinding.FragmentTaskListBinding
import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
import com.navinfo.omqs.http.taskupload.TaskUploadManager
import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.other.shareViewModels
import com.yanzhenjie.recyclerview.SwipeMenuBridge
import com.yanzhenjie.recyclerview.SwipeMenuCreator
import com.yanzhenjie.recyclerview.SwipeMenuItem
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject
import org.videolan.vlc.Util
/**
* 当前任务的道路列表
@ -41,14 +40,12 @@ class TaskFragment : BaseFragment() {
private val adapter: TaskAdapter by lazy {
TaskAdapter(object : TaskAdapterCallback {
override fun itemOnClick(bean: HadLinkDvoBean) {
if(bean!=null){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
viewModel.showCurrentLink(bean)
}else{
Toast.makeText(context, "数据错误,无法显示!", Toast.LENGTH_SHORT).show()
}
}
override fun editOnclick(position: Int, bean: HadLinkDvoBean) {
override fun editOnClick(position: Int, bean: HadLinkDvoBean) {
showLinkEditDialog(position, bean)
}
})
@ -66,11 +63,43 @@ class TaskFragment : BaseFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.taskAddLink.setOnClickListener {
viewModel.setSelectLink(!binding.taskAddLink.isSelected)
}
viewModel.liveDataSelectNewLink.observe(viewLifecycleOwner) {
binding.taskAddLink.isSelected = it
}
//注意:使用滑动菜单不能开启滑动删除,否则只有滑动删除没有滑动菜单
val mSwipeMenuCreator = SwipeMenuCreator { _, rightMenu, _ ->
//添加菜单自动添加至尾部
val deleteItem = SwipeMenuItem(context)
deleteItem.height = Util.convertDpToPx(requireContext(), 60)
deleteItem.width = Util.convertDpToPx(requireContext(), 80)
deleteItem.text = "删除"
deleteItem.background = requireContext().getDrawable(R.color.red)
deleteItem.setTextColor(requireContext().resources.getColor(R.color.white))
rightMenu.addMenuItem(deleteItem)
}
val layoutManager = LinearLayoutManager(context)
//// 设置 RecyclerView 的固定大小,避免在滚动时重新计算视图大小和布局,提高性能
binding.taskRecyclerview.setHasFixedSize(true)
binding.taskRecyclerview.layoutManager = layoutManager
//增加侧滑按钮
binding.taskRecyclerview.setSwipeMenuCreator(mSwipeMenuCreator)
//单项点击
binding.taskRecyclerview.setOnItemMenuClickListener { menuBridge, position ->
menuBridge.closeMenu()
viewModel.deleteTaskLink(requireContext(), adapter.data[position])
}
binding.taskRecyclerview.adapter = adapter
binding.taskSearchClear.setOnClickListener {
binding.taskSearch.setText("")
}
@ -93,6 +122,7 @@ class TaskFragment : BaseFragment() {
})
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null

View File

@ -1,16 +1,18 @@
package com.navinfo.omqs.ui.fragment.tasklist
import android.annotation.SuppressLint
import android.app.Dialog
import android.graphics.Color
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.collect.library.data.entity.TaskBean
import com.navinfo.omqs.R
import com.navinfo.omqs.databinding.AdapterTaskListBinding
@ -19,15 +21,10 @@ import com.navinfo.omqs.http.taskupload.TaskUploadManager
import com.navinfo.omqs.tools.FileManager
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
import com.navinfo.omqs.tools.FileManager.Companion.FileUploadStatus
import com.navinfo.omqs.ui.dialog.FirstDialog
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
import com.navinfo.omqs.ui.other.BaseViewHolder
import com.navinfo.omqs.ui.other.OnLifecycleStateListener
import com.navinfo.omqs.ui.widget.LeftDeleteView
import io.realm.Realm
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* 离线地图城市列表 RecyclerView 适配器
@ -51,8 +48,7 @@ class TaskListAdapter(
private var isShowDeleteView = false
private
val downloadBtnClick = View.OnClickListener() {
private val downloadBtnClick = View.OnClickListener() {
if (it.tag != null) {
val taskBean = data[it.tag as Int]
if (taskBean.hadLinkDvoList.isNotEmpty()) {
@ -124,6 +120,7 @@ class TaskListAdapter(
override fun onViewRecycled(holder: BaseViewHolder) {
super.onViewRecycled(holder)
//页面滑动时会用holder重构页面但是对进度条的监听回调会一直返回扰乱UI所以当当前holder去重构的时候移除监听
//这里 BaseViewHolder 的LifecycleOwner 状态很早就DESTROYED 了,这个回调比较晚,起到的作用很小
downloadManager.removeObserver(holder.tag.toInt())
}
@ -131,6 +128,7 @@ class TaskListAdapter(
holder: BaseViewHolder,
@SuppressLint("RecyclerView") position: Int
) {
val binding: AdapterTaskListBinding =
holder.viewBinding as AdapterTaskListBinding
val taskBean = data[position]
@ -149,8 +147,22 @@ class TaskListAdapter(
//tag 方便onclick里拿到数据
holder.tag = taskBean.id.toString()
changeViews(binding, taskBean)
holder.addObserver(object : OnLifecycleStateListener {
override fun onState(tag: String, state: Lifecycle.State) {
when (state) {
Lifecycle.State.STARTED ->
downloadManager.observer(
taskBean.id,
holder,
DownloadObserver(taskBean.id, holder)
)
Lifecycle.State.DESTROYED ->
downloadManager.removeObserver(tag.toInt())
else -> {}
}
}
})
downloadManager.addTask(taskBean)
downloadManager.observer(taskBean.id, holder, DownloadObserver(taskBean.id, holder))
uploadManager.addTask(taskBean)
uploadManager.observer(taskBean.id, holder, UploadObserver(taskBean.id, binding))
if (taskBean.status == FileDownloadStatus.NONE) {
@ -203,7 +215,12 @@ class TaskListAdapter(
binding.taskDeleteLayout.setOnClickListener {
//重置状态
leftDeleteView?.resetDeleteStatus()
itemListener?.invoke(position, ItemClickStatus.DELETE_LAYOUT_CLICK, taskBean)
if (taskBean.syncStatus != FileUploadStatus.DONE) {
Toast.makeText(binding.taskUploadBtn.context, "数据未上传,不允许关闭!", Toast.LENGTH_SHORT)
.show()
} else {
itemListener?.invoke(position, ItemClickStatus.DELETE_LAYOUT_CLICK, taskBean)
}
}
}
@ -212,7 +229,7 @@ class TaskListAdapter(
* 重置item状态
* @param point
*/
fun restoreItemView() {
private fun restoreItemView() {
leftDeleteView?.let {
if (isShowDeleteView)
it.resetDeleteStatus()
@ -245,8 +262,9 @@ class TaskListAdapter(
FileUploadStatus.DONE -> {
binding.taskUploadBtn.stopAnimator()
binding.taskUploadBtn.setText("已上传")
binding.taskUploadBtn.isEnabled = false
binding.taskUploadBtn.setProgress(0)
binding.taskUploadBtn.setBackgroundColor(binding.root.resources.getColor(R.color.ripple_end_color))
binding.taskUploadBtn.setBackgroundColor(binding.root.resources.getColor(R.color.gray_121))
}
FileUploadStatus.ERROR -> {
@ -366,6 +384,17 @@ class TaskListAdapter(
}
}
fun initSelectTask(list: List<TaskBean>, id: Int?) {
for (i in list.indices) {
if (list[i].id == id) {
selectPosition = i
break
}
}
refreshData(list)
}
companion object {
object ItemClickStatus {
const val ITEM_LAYOUT_CLICK = 0 //条目点击

View File

@ -1,6 +1,5 @@
package com.navinfo.omqs.ui.fragment.tasklist
import android.app.Dialog
import android.os.Build
import android.os.Bundle
import android.text.Editable
@ -9,26 +8,15 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.recyclerview.widget.LinearLayoutManager
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.collect.library.data.entity.TaskBean
import com.navinfo.omqs.databinding.FragmentTaskListBinding
import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
import com.navinfo.omqs.http.taskupload.TaskUploadManager
import com.navinfo.omqs.tools.FileManager
import com.navinfo.omqs.ui.dialog.FirstDialog
import com.navinfo.omqs.ui.fragment.BaseFragment
import com.navinfo.omqs.ui.other.shareViewModels
import dagger.hilt.android.AndroidEntryPoint
import io.realm.Realm
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
@RequiresApi(Build.VERSION_CODES.M)
@AndroidEntryPoint
class TaskListFragment : BaseFragment() {
@ -47,21 +35,28 @@ class TaskListFragment : BaseFragment() {
private val adapter: TaskListAdapter by lazy {
TaskListAdapter(
downloadManager, uploadManager,binding.taskListRecyclerview
downloadManager, uploadManager, binding.taskListRecyclerview
) { _, status, taskBean ->
if(taskBean.hadLinkDvoList.isEmpty()){
if (taskBean.hadLinkDvoList.isEmpty()) {
Toast.makeText(context, "数据错误无Link数据", Toast.LENGTH_SHORT).show()
}
if(status==TaskListAdapter.Companion.ItemClickStatus.ITEM_LAYOUT_CLICK){
viewModel.setSelectTaskBean(taskBean as TaskBean)
}else if(status==TaskListAdapter.Companion.ItemClickStatus.DELETE_LAYOUT_CLICK){
context?.let { viewModel.removeTask(it, taskBean as TaskBean) }
}else if(status==TaskListAdapter.Companion.ItemClickStatus.UPLOAD_LAYOUT_CLICK){
showLoadingDialog("正在校验")
Toast.makeText(context, "正在校验", Toast.LENGTH_SHORT).show()
viewModel.checkUploadTask(binding.root.context,taskBean)
} else {
when (status) {
TaskListAdapter.Companion.ItemClickStatus.ITEM_LAYOUT_CLICK -> {
viewModel.setSelectTaskBean(taskBean)
}
TaskListAdapter.Companion.ItemClickStatus.DELETE_LAYOUT_CLICK -> {
showLoadingDialog("正在关闭")
context?.let { viewModel.removeTask(it, taskBean) }
}
TaskListAdapter.Companion.ItemClickStatus.UPLOAD_LAYOUT_CLICK -> {
showLoadingDialog("正在校验")
Toast.makeText(context, "正在校验", Toast.LENGTH_SHORT).show()
viewModel.checkUploadTask(binding.root.context, taskBean)
}
else -> {
}
}
}
}
@ -85,13 +80,13 @@ class TaskListFragment : BaseFragment() {
binding.taskListRecyclerview.layoutManager = layoutManager
binding.taskListRecyclerview.adapter = adapter
viewModel.liveDataTaskList.observe(viewLifecycleOwner) {
adapter.refreshData(it)
adapter.initSelectTask(it, viewModel.currentSelectTaskBean?.id)
}
//监听并调用上传
viewModel.liveDataTaskUpload.observe(viewLifecycleOwner){
viewModel.liveDataTaskUpload.observe(viewLifecycleOwner) {
for ((key, value) in it) {
if(value){
if (value) {
adapter.uploadTask(key)
}
}
@ -111,6 +106,8 @@ class TaskListFragment : BaseFragment() {
})
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null

View File

@ -4,7 +4,9 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.navigation.fragment.findNavController
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayoutMediator
import com.navinfo.omqs.databinding.FragmentTaskManagerBinding
import com.navinfo.omqs.ui.fragment.BaseFragment
@ -38,10 +40,20 @@ class TaskManagerFragment(private var backListener: ((TaskManagerFragment) -> Un
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.liveDataToastMessage.observe(viewLifecycleOwner) {
Toast.makeText(requireContext(), it, Toast.LENGTH_SHORT).show()
}
//禁止滑动,因为页面在抽屉里,和抽屉的滑动有冲突
binding.taskManagerViewpager.isUserInputEnabled = false
//创建viewpager2的适配器
binding.taskManagerViewpager.adapter = activity?.let { TaskManagerAdapter(it) }
binding.taskManagerViewpager.registerOnPageChangeCallback(object :
ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
viewModel.setSelectLink(false)
}
})
//绑定viewpager2与tabLayout
TabLayoutMediator(
binding.taskManagerTabLayout,

View File

@ -1,20 +1,24 @@
package com.navinfo.omqs.ui.fragment.tasklist
import android.app.Dialog
import android.content.Context
import android.graphics.Color
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.os.Build
import android.view.View
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.navinfo.collect.library.data.dao.impl.TraceDataBase
import com.navinfo.collect.library.data.entity.HadLinkDvoBean
import com.navinfo.collect.library.data.entity.NiLocation
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.collect.library.data.entity.TaskBean
import com.navinfo.collect.library.map.NIMapController
import com.navinfo.collect.library.map.OnGeoPointClickListener
import com.navinfo.collect.library.utils.GeometryTools
import com.navinfo.omqs.Constant
import com.navinfo.omqs.db.RealmOperateHelper
import com.navinfo.omqs.http.NetResult
import com.navinfo.omqs.http.NetworkService
import com.navinfo.omqs.tools.FileManager
@ -23,13 +27,19 @@ import com.navinfo.omqs.util.DateTimeUtil
import dagger.hilt.android.lifecycle.HiltViewModel
import io.realm.Realm
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collectLatest
import org.oscim.core.GeoPoint
import javax.inject.Inject
@HiltViewModel
class TaskViewModel @Inject constructor(
private val networkService: NetworkService, private val mapController: NIMapController
) : ViewModel() {
private val networkService: NetworkService,
private val mapController: NIMapController,
private val sharedPreferences: SharedPreferences,
private val realmOperateHelper: RealmOperateHelper,
) : ViewModel(), OnSharedPreferenceChangeListener {
private val TAG = "TaskViewModel"
/**
* 用来更新任务列表
@ -46,13 +56,22 @@ class TaskViewModel @Inject constructor(
*/
val liveDataTaskUpload = MutableLiveData<Map<TaskBean, Boolean>>()
private val colors =
arrayOf(Color.RED, Color.YELLOW, Color.BLUE, Color.MAGENTA, Color.GREEN, Color.CYAN)
// private val colors =
// arrayOf(Color.RED, Color.YELLOW, Color.BLUE, Color.MAGENTA, Color.GREEN, Color.CYAN)
/**
* 用来确定是否关闭
*/
val liveDataCloseTask = MutableLiveData<Boolean>()
/**
* 提示信息
*/
val liveDataToastMessage = MutableLiveData<String>()
/**
* 当前选中的任务
*/
private var currentSelectTaskBean: TaskBean? = null
var currentSelectTaskBean: TaskBean? = null
/**
* 任务列表查询协程
@ -61,13 +80,21 @@ class TaskViewModel @Inject constructor(
private var filterTaskJob: Job? = null
/**
* 是否开启了道路选择
*/
var liveDataSelectNewLink = MutableLiveData(false)
init {
sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}
/**
* 下载任务列表
*/
fun getTaskList(context: Context) {
viewModelScope.launch(Dispatchers.IO) {
var taskList: List<TaskBean> = mutableListOf()
when (val result = networkService.getTaskList(Constant.USER_ID)) {
is NetResult.Success -> {
if (result.data != null) {
@ -83,6 +110,7 @@ class TaskViewModel @Inject constructor(
task.fileSize = item.fileSize
task.status = item.status
task.currentSize = item.currentSize
task.hadLinkDvoList = item.hadLinkDvoList
//已上传后不在更新操作时间
if (task.syncStatus != FileManager.Companion.FileUploadStatus.DONE) {
//赋值时间,用于查询过滤
@ -116,35 +144,63 @@ class TaskViewModel @Inject constructor(
is NetResult.Loading -> {}
}
val realm = Realm.getDefaultInstance()
//过滤掉已上传的超过90天的数据
var nowTime: Long = DateTimeUtil.getNowDate().time
var beginNowTime: Long = nowTime - 90 * 3600 * 24 * 1000L
var syncUpload: Int = FileManager.Companion.FileUploadStatus.DONE
val objects =
realm.where(TaskBean::class.java).notEqualTo("syncStatus", syncUpload).or()
.between("operationTime", beginNowTime, nowTime)
.equalTo("syncStatus", syncUpload).findAll()
taskList = realm.copyFromRealm(objects)
getLocalTaskList()
}
}
/**
* 获取任务列表
*/
private suspend fun getLocalTaskList() {
val realm = Realm.getDefaultInstance()
//过滤掉已上传的超过90天的数据
val nowTime: Long = DateTimeUtil.getNowDate().time
val beginNowTime: Long = nowTime - 90 * 3600 * 24 * 1000L
val syncUpload: Int = FileManager.Companion.FileUploadStatus.DONE
val objects =
realm.where(TaskBean::class.java).notEqualTo("syncStatus", syncUpload).or()
.between("operationTime", beginNowTime, nowTime)
.equalTo("syncStatus", syncUpload).findAll().sort("id")
val taskList = realm.copyFromRealm(objects)
for (item in taskList) {
FileManager.checkOMDBFileInfo(item)
}
liveDataTaskList.postValue(taskList)
val id = sharedPreferences.getInt(Constant.SELECT_TASK_ID, -1)
if (id > -1) {
for (item in taskList) {
FileManager.checkOMDBFileInfo(item)
if (item.id == id) {
currentSelectTaskBean = item
liveDataTaskLinks.postValue(currentSelectTaskBean!!.hadLinkDvoList)
withContext(Dispatchers.Main) {
showTaskLinks(currentSelectTaskBean!!)
}
break
}
}
liveDataTaskList.postValue(taskList)
}
}
/**
* 设置当前选择的任务并高亮当前任务的所有link
*/
@RequiresApi(Build.VERSION_CODES.M)
fun setSelectTaskBean(taskBean: TaskBean) {
sharedPreferences.edit().putInt(Constant.SELECT_TASK_ID, taskBean.id).apply()
currentSelectTaskBean = taskBean
liveDataTaskLinks.value = taskBean.hadLinkDvoList
showTaskLinks(taskBean)
}
mapController.lineHandler.omdbTaskLinkLayer.removeAll()
private fun showTaskLinks(taskBean: TaskBean) {
mapController.lineHandler.removeAllTaskLine()
mapController.markerHandle.clearNiLocationLayer()
if (taskBean.hadLinkDvoList.isNotEmpty()) {
mapController.lineHandler.omdbTaskLinkLayer.addLineList(taskBean.hadLinkDvoList)
mapController.lineHandler.showTaskLines(taskBean.hadLinkDvoList)
var maxX = 0.0
var maxY = 0.0
var minX = 0.0
@ -174,14 +230,25 @@ class TaskViewModel @Inject constructor(
)
}
}
//重新加载轨迹
viewModelScope.launch(Dispatchers.IO) {
val list: List<NiLocation>? = TraceDataBase.getDatabase(
mapController.mMapView.context,
Constant.USER_DATA_PATH
).niLocationDao.findToTaskIdAll(taskBean.id.toString())
list!!.forEach {
mapController.markerHandle.addNiLocationMarkerItem(it)
}
}
}
/**
* 高亮当前选中的link
*/
@RequiresApi(Build.VERSION_CODES.M)
fun showCurrentLink(link: HadLinkDvoBean) {
mapController.lineHandler.omdbTaskLinkLayer.showSelectLine(link)
mapController.lineHandler.showLine(link.geometry)
// mapController.lineHandler.omdbTaskLinkLayer.showSelectLine(link)
val geometry = GeometryTools.createGeometry(link.geometry)
if (geometry != null) {
val envelope = geometry.envelopeInternal
@ -196,13 +263,14 @@ class TaskViewModel @Inject constructor(
}
override fun onCleared() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mapController.lineHandler.omdbTaskLinkLayer.clearSelectLine()
}
mapController.lineHandler.removeLine()
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
super.onCleared()
}
/**
* 保存link补作业原因
*/
suspend fun saveLinkReason(bean: HadLinkDvoBean, text: String) {
withContext(Dispatchers.IO) {
currentSelectTaskBean?.let {
@ -211,11 +279,12 @@ class TaskViewModel @Inject constructor(
item.reason = text
}
}
val realm = Realm.getDefaultInstance()
realm.executeTransaction { r ->
r.copyToRealmOrUpdate(it)
}
}
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
realm.copyToRealmOrUpdate(currentSelectTaskBean)
}
}
}
@ -239,6 +308,9 @@ class TaskViewModel @Inject constructor(
}
}
/**
* 筛选link
*/
fun filterTask(pidKey: String) {
if (currentSelectTaskBean == null)
return
@ -256,53 +328,61 @@ class TaskViewModel @Inject constructor(
}
}
/**
* 关闭任务
*/
fun removeTask(context: Context, taskBean: TaskBean) {
if (taskBean != null) {
val mDialog = FirstDialog(context)
mDialog.setTitle("提示?")
mDialog.setMessage("是否关闭,请确认!")
mDialog.setPositiveButton("确定", object : FirstDialog.OnClickListener {
override fun onClick(dialog: Dialog?, which: Int) {
mDialog.dismiss()
viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
val objects = it.where(TaskBean::class.java)
.equalTo("id", taskBean.id).findFirst()
objects?.deleteFromRealm()
val mDialog = FirstDialog(context)
mDialog.setTitle("提示?")
mDialog.setMessage("是否关闭,请确认!")
mDialog.setPositiveButton(
"确定"
) { dialog, _ ->
dialog.dismiss()
viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
val objects = it.where(TaskBean::class.java)
.equalTo("id", taskBean.id).findFirst()
objects?.deleteFromRealm()
}
//遍历删除对应的数据
taskBean.hadLinkDvoList.forEach { hadLinkDvoBean ->
val qsRecordList = realm.where(QsRecordBean::class.java)
.equalTo("linkId", hadLinkDvoBean.linkPid).and()
.equalTo("taskId", hadLinkDvoBean.taskId).findAll()
if (qsRecordList != null && qsRecordList.size > 0) {
val copyList = realm.copyFromRealm(qsRecordList)
copyList.forEach {
it.deleteFromRealm()
mapController.markerHandle.removeQsRecordMark(it)
mapController.mMapView.vtmMap.updateMap(true)
}
//遍历删除对应的数据
taskBean.hadLinkDvoList.forEach { hadLinkDvoBean ->
val qsRecordList = realm.where(QsRecordBean::class.java)
.equalTo("linkId", hadLinkDvoBean.linkPid).findAll()
if (qsRecordList != null && qsRecordList.size > 0) {
val copyList = realm.copyFromRealm(qsRecordList)
copyList.forEach {
it.deleteFromRealm()
mapController.markerHandle.removeQsRecordMark(it)
mapController.mMapView.vtmMap.updateMap(true)
}
}
}
//过滤掉已上传的超过90天的数据
var nowTime: Long = DateTimeUtil.getNowDate().time
var beginNowTime: Long = nowTime - 90 * 3600 * 24 * 1000L
var syncUpload: Int = FileManager.Companion.FileUploadStatus.DONE
val objects = realm.where(TaskBean::class.java)
.notEqualTo("syncStatus", syncUpload).or()
.between("operationTime", beginNowTime, nowTime)
.equalTo("syncStatus", syncUpload).findAll()
val taskList = realm.copyFromRealm(objects)
for (item in taskList) {
FileManager.checkOMDBFileInfo(item)
}
liveDataTaskList.postValue(taskList)
}
}
})
mDialog.setNegativeButton("取消", null)
mDialog.show()
//过滤掉已上传的超过90天的数据
val nowTime: Long = DateTimeUtil.getNowDate().time
val beginNowTime: Long = nowTime - 90 * 3600 * 24 * 1000L
val syncUpload: Int = FileManager.Companion.FileUploadStatus.DONE
val objects = realm.where(TaskBean::class.java)
.notEqualTo("syncStatus", syncUpload).or()
.between("operationTime", beginNowTime, nowTime)
.equalTo("syncStatus", syncUpload).findAll()
val taskList = realm.copyFromRealm(objects)
for (item in taskList) {
FileManager.checkOMDBFileInfo(item)
}
liveDataTaskList.postValue(taskList)
liveDataCloseTask.postValue(true)
}
}
mDialog.setNegativeButton(
"取消"
) { _, _ ->
liveDataCloseTask.postValue(false)
mDialog.dismiss()
}
mDialog.show()
}
fun checkUploadTask(context: Context, taskBean: TaskBean) {
@ -310,7 +390,8 @@ class TaskViewModel @Inject constructor(
val realm = Realm.getDefaultInstance()
taskBean.hadLinkDvoList.forEach { hadLinkDvoBean ->
val objects = realm.where(QsRecordBean::class.java)
.equalTo("linkId", hadLinkDvoBean.linkPid).findAll()
.equalTo("linkId", hadLinkDvoBean.linkPid).and()
.equalTo("taskId", hadLinkDvoBean.taskId).findAll()
val map: MutableMap<TaskBean, Boolean> = HashMap<TaskBean, Boolean>()
if (objects.isEmpty() && hadLinkDvoBean.reason.isEmpty()) {
withContext(Dispatchers.Main) {
@ -319,19 +400,15 @@ class TaskViewModel @Inject constructor(
mDialog.setTitle("提示?")
mDialog.setMessage("此任务中存在未测评link请确认")
mDialog.setPositiveButton(
"确定",
object : FirstDialog.OnClickListener {
override fun onClick(dialog: Dialog?, which: Int) {
mDialog.dismiss()
map[taskBean] = true
liveDataTaskUpload.postValue(map)
}
})
mDialog.setNegativeButton("取消", object : FirstDialog.OnClickListener {
override fun onClick(dialog: Dialog?, which: Int) {
mDialog.dismiss()
}
})
"确定"
) { _, _ ->
mDialog.dismiss()
map[taskBean] = true
liveDataTaskUpload.postValue(map)
}
mDialog.setNegativeButton(
"取消"
) { _, _ -> mDialog.dismiss() }
mDialog.show()
}
return@launch
@ -341,4 +418,131 @@ class TaskViewModel @Inject constructor(
}
}
}
/**
* 监听新增的评测link
*/
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
if (key == Constant.SHARED_SYNC_TASK_LINK_ID) {
viewModelScope.launch(Dispatchers.IO) {
getLocalTaskList()
}
}
}
/**
* 设置是否开启选择link
*/
fun setSelectLink(selected: Boolean) {
liveDataSelectNewLink.value = selected
//开始捕捉
if (selected) {
mapController.mMapView.addOnNIMapClickListener(TAG, object : OnGeoPointClickListener {
override fun onMapClick(tag: String, point: GeoPoint) {
if (tag == TAG) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
viewModelScope.launch(Dispatchers.Default) {
if (currentSelectTaskBean == null) {
liveDataToastMessage.postValue("还没有开启任何任务")
} else {
val links = realmOperateHelper.queryLink(
point = point,
)
if (links.isNotEmpty()) {
val l = links[0]
for (link in currentSelectTaskBean!!.hadLinkDvoList) {
if (link.linkPid == l.properties["linkPid"]) {
return@launch
}
}
val hadLinkDvoBean = HadLinkDvoBean(
taskId = currentSelectTaskBean!!.id,
linkPid = l.properties["linkPid"]!!,
geometry = l.geometry,
linkStatus = 2
)
currentSelectTaskBean!!.hadLinkDvoList.add(
hadLinkDvoBean
)
val realm = Realm.getDefaultInstance()
realm.executeTransaction { r ->
r.copyToRealmOrUpdate(hadLinkDvoBean)
r.copyToRealmOrUpdate(currentSelectTaskBean!!)
}
liveDataTaskLinks.postValue(currentSelectTaskBean!!.hadLinkDvoList)
mapController.lineHandler.addTaskLink(hadLinkDvoBean)
}
}
}
}
}
}
})
} else {
mapController.mMapView.removeOnNIMapClickListener(TAG)
mapController.lineHandler.removeLine()
}
}
/**
* 删除评测link
*/
fun deleteTaskLink(context: Context, hadLinkDvoBean: HadLinkDvoBean) {
if (hadLinkDvoBean.linkStatus == 1) {
val mDialog = FirstDialog(context)
mDialog.setTitle("提示")
mDialog.setMessage("当前要评测的link是任务原始规划的不能删除如果不进行作业请标记原因")
mDialog.setCancelVisibility(View.GONE)
mDialog.setPositiveButton(
"确定"
) { _, _ ->
mDialog.dismiss()
}
mDialog.show()
} else {
val mDialog = FirstDialog(context)
mDialog.setTitle("提示")
mDialog.setMessage("是否删除当前link与之相关联的评测任务会一起删除")
mDialog.setPositiveButton(
"确定"
) { dialog, _ ->
dialog.dismiss()
viewModelScope.launch(Dispatchers.IO) {
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
for (link in currentSelectTaskBean!!.hadLinkDvoList) {
if (link.linkPid == hadLinkDvoBean.linkPid) {
currentSelectTaskBean!!.hadLinkDvoList.remove(link)
break
}
}
realm.where(HadLinkDvoBean::class.java)
.equalTo("linkPid", hadLinkDvoBean.linkPid).findFirst()
?.deleteFromRealm()
val markers = realm.where(QsRecordBean::class.java)
.equalTo("linkId", hadLinkDvoBean.linkPid)
.and().equalTo("taskId", hadLinkDvoBean.taskId)
.findAll()
if(markers != null){
for(marker in markers){
mapController.markerHandle.removeQsRecordMark(marker)
}
markers.deleteAllFromRealm()
}
realm.copyToRealmOrUpdate(currentSelectTaskBean)
mapController.lineHandler.removeTaskLink(hadLinkDvoBean.linkPid)
liveDataTaskLinks.postValue(currentSelectTaskBean!!.hadLinkDvoList)
}
}
}
mDialog.setNegativeButton(
"取消"
) { _, _ ->
mDialog.dismiss()
}
mDialog.show()
}
}
}

View File

@ -16,6 +16,8 @@ open class BaseViewHolder(val viewBinding: ViewBinding) :
private val lifecycleRegistry = LifecycleRegistry(this)
var tag = ""
private var listener: OnLifecycleStateListener? = null
init {
// dataBinding.lifecycleOwner = this
lifecycleRegistry.currentState = Lifecycle.State.INITIALIZED
@ -37,19 +39,33 @@ open class BaseViewHolder(val viewBinding: ViewBinding) :
fun onStart() {
lifecycleRegistry.currentState = Lifecycle.State.STARTED //
lifecycleRegistry.currentState = Lifecycle.State.RESUMED // ON_RESUME EVENT
listener?.onState(tag,Lifecycle.State.STARTED)
}
fun onStop() {
lifecycleRegistry.currentState = Lifecycle.State.STARTED //
lifecycleRegistry.currentState = Lifecycle.State.CREATED // ON_STOP EVENT
lifecycleRegistry.currentState = Lifecycle.State.CREATED //
// listener?.onState(tag,Lifecycle.State.STARTED)// ON_STOP EVENT
}
fun onDestroy() {
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED /// ON_DESTROY EVENT
listener?.onState(tag,Lifecycle.State.DESTROYED)
}
override fun getLifecycle(): Lifecycle {
return lifecycleRegistry
}
fun addObserver(listener: OnLifecycleStateListener) {
this.listener = listener
}
}
/**
* 生命周期变化
*/
interface OnLifecycleStateListener {
fun onState(tag:String,state: Lifecycle.State)
}

View File

@ -45,7 +45,7 @@ class SignUtil {
*获取道路功能等级文字
*/
private fun getLinkFunctionClassText(data: RenderEntity): String {
return "等级${data.properties["functionClass"]}"
return "FC${data.properties["functionClass"]}"
}
/**
@ -55,9 +55,9 @@ class SignUtil {
val direct = data.properties["direct"]
when (direct?.toInt()) {
0 -> return "不应用"
1 -> return "方向"
2 -> return "方向"
3 -> return "方向"
1 -> return ""
2 -> return ""
3 -> return ""
}
return ""
}

View File

@ -122,18 +122,16 @@ class TextProgressButtonBar : View {
* 绘制进度值
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val shader = LinearGradient(
oval.left,
oval.top,
oval.right,
oval.bottom,
mStartColor,
mCurrentColor,
Shader.TileMode.MIRROR
)
it.shader = shader
}
val shader = LinearGradient(
oval.left,
oval.top,
oval.right,
oval.bottom,
mStartColor,
mCurrentColor,
Shader.TileMode.MIRROR
)
it.shader = shader
canvas.drawRoundRect(oval, progress.toFloat(), progress.toFloat(), it)
} else {
oval = RectF(
@ -143,18 +141,16 @@ class TextProgressButtonBar : View {
* 绘制进度值
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val shader = LinearGradient(
oval.left,
oval.top,
oval.right,
oval.bottom,
mStartColor,
mCurrentColor,
Shader.TileMode.CLAMP
)
it.shader = shader
}
val shader = LinearGradient(
oval.left,
oval.top,
oval.right,
oval.bottom,
mStartColor,
mCurrentColor,
Shader.TileMode.CLAMP
)
it.shader = shader
canvas.drawRoundRect(oval, corner.toFloat(), corner.toFloat(), it)
}
/***

View File

@ -370,4 +370,5 @@ public class ShareUtil {
return null;
}
}

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#91909A"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#1717E0"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/baseline_add_24_press" android:state_selected="true" />
<item android:drawable="@drawable/baseline_add_24" android:state_selected="false" />
</selector>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape>
<padding android:bottom="2dp" android:left="@dimen/default_widget_padding" android:right="@dimen/default_widget_padding" android:top="2dp"></padding>
<stroke android:width="1.1dp" android:color="#1ABBFE" />
</shape>
</item>
<item>
<shape>
<padding android:bottom="@dimen/default_widget_padding" android:left="@dimen/default_widget_padding" android:right="@dimen/default_widget_padding" android:top="@dimen/default_widget_padding"></padding>
<solid android:color="@color/transp" />
</shape>
</item>
</selector>

View File

@ -4,7 +4,7 @@
android:left="-300dp"
android:right="-300dp">
<rotate
android:drawable="@drawable/laneinfo_1_2"
android:drawable="@drawable/shape_dashed_line"
android:fromDegrees="90" />
</item>
</layer-list>

View File

@ -31,6 +31,28 @@
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/main_activity_home_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/home_map_center"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/main_activity_home_center_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="12sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/main_activity_home_center"
app:layout_constraintRight_toLeftOf="@id/main_activity_home_center"
app:layout_constraintTop_toTopOf="@id/main_activity_home_center" />
<ImageButton
android:id="@+id/main_activity_camera2"
android:layout_width="48dp"
@ -79,7 +101,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/top_right_drawer_btns_mr"
app:constraint_referenced_ids="main_activity_serach,main_activity_2d_3d,main_activity_camera,main_activity_trace,main_activity_calc_disance,main_activity_menu"
app:constraint_referenced_ids="main_activity_note,main_activity_task_line,main_activity_serach,main_activity_2d_3d,main_activity_camera,main_activity_trace,main_activity_calc_disance,main_activity_menu"
app:flow_horizontalGap="6dp"
app:flow_wrapMode="aligned"
app:layout_constraintRight_toLeftOf="@id/main_activity_right_fragment"
@ -90,7 +112,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
app:constraint_referenced_ids="main_activity_serach,main_activity_2d_3d,main_activity_camera,main_activity_trace,main_activity_calc_disance" />
app:constraint_referenced_ids="main_activity_serach,main_activity_2d_3d,main_activity_camera,main_activity_trace,main_activity_note,main_activity_task_line,main_activity_calc_disance" />
<ImageButton
android:id="@+id/main_activity_serach"
@ -122,6 +144,18 @@
android:onClick="@{()->mainActivity.onClickCalcDisance()}"
android:src="@drawable/icon_calc_disance" />
<ImageButton
android:id="@+id/main_activity_note"
style="@style/top_right_drawer_btns_style"
android:onClick="@{()->mainActivity.onClickNewNote()}"
android:src="@drawable/icon_menu_note" />
<ImageButton
android:id="@+id/main_activity_task_line"
style="@style/top_right_drawer_btns_style"
android:onClick="@{()->mainActivity.onClickTaskLink()}"
android:src="@drawable/icon_calc_disance" />
<ImageButton
android:id="@+id/main_activity_menu"
android:layout_width="@dimen/top_right_drawer_wh"
@ -131,72 +165,6 @@
android:onClick="@{()->mainActivity.onClickMenu()}" />
<androidx.constraintlayout.helper.widget.Flow
android:id="@+id/main_activity_flow_indoor"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/top_right_drawer_btns_mr"
app:constraint_referenced_ids="main_activity_snapshot_finish,main_activity_trace_snapshot_points,main_activity_snapshot_media_flag,main_activity_snapshot_rewind,main_activity_snapshot_pause,main_activity_snapshot_next,main_activity_menu_indoor_group"
app:flow_horizontalGap="6dp"
app:flow_wrapMode="aligned"
app:layout_constraintRight_toLeftOf="@id/main_activity_right_fragment"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Group
android:id="@+id/main_activity_menu_indoor_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="main_activity_snapshot_finish,main_activity_trace_snapshot_points,main_activity_snapshot_media_flag,main_activity_snapshot_rewind,main_activity_snapshot_pause,main_activity_snapshot_next" />
<ImageButton
android:id="@+id/main_activity_snapshot_finish"
style="@style/top_right_drawer_btns_style"
android:clickable="true"
android:enabled="false"
android:focusable="true"
android:src="@drawable/map_trace_finish"
tools:ignore="MissingConstraints" />
<ImageButton
android:id="@+id/main_activity_trace_snapshot_points"
style="@style/top_right_drawer_btns_style"
android:focusable="true"
android:src="@drawable/map_trace_select_point"
tools:ignore="MissingConstraints" />
<ImageButton
android:id="@+id/main_activity_snapshot_media_flag"
style="@style/top_right_drawer_btns_style"
android:enabled="false"
android:focusable="true"
android:src="@drawable/map_trace_mediaflag"
tools:ignore="MissingConstraints" />
<ImageButton
android:id="@+id/main_activity_snapshot_rewind"
style="@style/top_right_drawer_btns_style"
android:enabled="false"
android:focusable="true"
android:src="@drawable/map_trace_forward"
tools:ignore="MissingConstraints" />
<ImageButton
android:id="@+id/main_activity_snapshot_pause"
style="@style/top_right_drawer_btns_style"
android:enabled="false"
android:focusable="true"
android:src="@drawable/map_trace_pause"
tools:ignore="DuplicateIds,MissingConstraints" />
<ImageButton
android:id="@+id/main_activity_snapshot_next"
style="@style/top_right_drawer_btns_style"
android:enabled="false"
android:focusable="true"
android:src="@drawable/map_trace_next"
tools:ignore="DuplicateIds,MissingConstraints" />
<androidx.constraintlayout.widget.Barrier
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -224,16 +192,6 @@
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="@id/main_activity_sign_recyclerview" />
<fragment
android:id="@+id/main_activity_right_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:elevation="3dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/right_fragment_nav_graph" />
<TextView
android:id="@+id/main_activity_geometry"
@ -250,7 +208,18 @@
android:text="经纬度:116.99388424,38.8403844"
android:textSize="10sp"
app:layout_constraintBottom_toTopOf="@id/main_activity_bottom_sheet_bg"
app:layout_constraintRight_toLeftOf="@id/main_activity_middle_fragment" />
app:layout_constraintRight_toLeftOf="@id/main_activity_right_fragment" />
<fragment
android:id="@+id/main_activity_right_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:elevation="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/right_fragment_nav_graph" />
<TextView
android:id="@+id/main_activity_road_name"
@ -336,16 +305,21 @@
android:layout_height="wrap_content"
app:constraint_referenced_ids="main_activity_select_line,main_activity_voice,main_activity_add_new" />
<androidx.constraintlayout.widget.Group
android:id="@+id/main_activity_right_visibility_buttons_group2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="main_activity_select_line,main_activity_voice,main_activity_add_new,main_activity_zoom_in,main_activity_zoom_out,main_activity_geometry,main_activity_location" />
<fragment
android:id="@+id/main_activity_middle_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="6dp"
android:layout_marginRight="-1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/main_activity_right_fragment"
app:layout_constraintTop_toBottomOf="@id/main_activity_flow"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/middle_fragment_nav_graph" />
<androidx.constraintlayout.widget.Group
@ -354,6 +328,62 @@
android:layout_height="wrap_content"
app:constraint_referenced_ids="main_activity_right_fragment,main_activity_middle_fragment" />
<androidx.constraintlayout.helper.widget.Flow
android:id="@+id/main_activity_flow_indoor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/five"
app:constraint_referenced_ids="main_activity_snapshot_finish,main_activity_trace_snapshot_points,main_activity_snapshot_media_flag,main_activity_snapshot_rewind,main_activity_snapshot_pause,main_activity_snapshot_next,main_activity_menu_indoor_group"
app:flow_horizontalGap="6dp"
app:flow_wrapMode="aligned"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/main_activity_bottom_sheet" />
<androidx.constraintlayout.widget.Group
android:id="@+id/main_activity_menu_indoor_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="main_activity_snapshot_finish,main_activity_trace_snapshot_points,main_activity_snapshot_rewind,main_activity_snapshot_pause,main_activity_snapshot_next" />
<ImageButton
android:id="@+id/main_activity_snapshot_finish"
style="@style/top_right_drawer_btns_style"
android:onClick="@{()->mainActivity.finishTraceOnclick()}"
android:src="@drawable/map_trace_finish" />
<ImageButton
android:id="@+id/main_activity_trace_snapshot_points"
style="@style/top_right_drawer_btns_style"
android:onClick="@{()->mainActivity.tracePointsOnclick()}"
android:src="@drawable/map_trace_select_point" />
<!-- <ImageButton
android:id="@+id/main_activity_snapshot_media_flag"
style="@style/top_right_drawer_btns_style"
android:visibility="gone"
android:onClick="@{()->mainActivity.mediaFlagOnclick()}"
android:src="@drawable/map_trace_mediaflag" />-->
<ImageButton
android:id="@+id/main_activity_snapshot_rewind"
style="@style/top_right_drawer_btns_style"
android:onClick="@{()->mainActivity.rewindTraceOnclick()}"
android:src="@drawable/map_trace_forward" />
<ImageButton
android:id="@+id/main_activity_snapshot_pause"
style="@style/top_right_drawer_btns_style"
android:onClick="@{()->mainActivity.pauseTraceOnclick()}"
android:src="@drawable/map_trace_pause" />
<ImageButton
android:id="@+id/main_activity_snapshot_next"
style="@style/top_right_drawer_btns_style"
android:onClick="@{()->mainActivity.nextTraceOnclick()}"
android:src="@drawable/map_trace_next" />
<View
android:id="@+id/main_activity_bottom_sheet"
android:layout_width="60dp"
@ -496,6 +526,7 @@
main_activity_bottom_sheet_bg,
main_bottom_task,main_bottom_home" />
<FrameLayout
android:id="@+id/console_fragment_layout"
android:layout_width="0dp"
@ -505,5 +536,6 @@
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp"
tools:context="com.navinfo.omqs.ui.fragment.tasklink.TaskLinkMiddleAdapter">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:textColor="@color/white" />
</LinearLayout>

View File

@ -150,6 +150,7 @@
android:layout_gravity="right|bottom"
android:layout_margin="10dp"
android:paddingLeft="@dimen/five"
android:visibility="invisible"
android:textColor="@color/white"
android:text="录像"
android:button="@drawable/chk_icon_camera_record_or_takephoto_xml"

View File

@ -278,7 +278,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="轨迹回放"
android:text="室内整理"
android:textColor="@color/white"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="@id/console_track_icon_bg"

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<com.navinfo.omqs.ui.fragment.note.CanvasView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/canvas_view"
android:elevation="4dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#94fcfbfb"
android:clickable="true" />

View File

@ -39,7 +39,7 @@
android:layout_height="40dp"
android:layout_marginTop="9dp"
android:layout_marginRight="14dp"
android:background="@drawable/ripple_fragment_save_botton_bg"
android:background="@drawable/ripple_fragment_save_button_bg"
android:src="@drawable/icon_save"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@ -87,6 +87,24 @@
android:layout_marginBottom="7dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="7dp"
android:orientation="horizontal">
<TextView
style="@style/evaluation_fragment_title_text_style"
android:text="任务名称" />
<TextView
android:id="@+id/evaluation_task_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{viewModel.liveDataTaskBean.evaluationTaskName}" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -0,0 +1,224 @@
<?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="@dimen/right_fragment_w"
android:layout_height="match_parent"
android:background="@drawable/shape_right_fragment_bg"
tools:context=".ui.fragment.note.NoteFragment">
<TextView
android:id="@+id/note_bar_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:layout_marginTop="14dp"
android:drawableLeft="@drawable/selector_btn_back_xml"
android:text="便签"
android:textColor="@color/default_blue_text_color"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/note_bar_save"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="9dp"
android:layout_marginRight="14dp"
android:background="@drawable/ripple_fragment_save_button_bg"
android:src="@drawable/icon_save"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/note_bar_delete"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerInParent="true"
android:layout_marginRight="5dp"
android:background="@color/transparent"
android:src="@drawable/icon_delete"
app:layout_constraintRight_toLeftOf="@id/note_bar_cancel"
app:layout_constraintTop_toTopOf="@id/note_bar_save" />
<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="6dp"
android:paddingLeft="11dp"
android:paddingTop="6dp"
android:paddingRight="9dp"
android:paddingBottom="6dp"
app:layout_constraintBottom_toTopOf="@id/note_camera"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/note_bar_save">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="7dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="5dp"
android:paddingBottom="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="橡皮擦&#8195;" />
<ImageView
android:id="@+id/sketch_eraser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/selector_sketch_eraser_bg"
android:src="@drawable/sketch_eraser" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/sketch_back"
style="@style/sketch_operation_style"
android:src="@drawable/sketch_back" />
<View
style="@style/link_gray_style"
android:layout_margin="2dp" />
<ImageView
android:id="@+id/sketch_forward"
style="@style/sketch_operation_style"
android:src="@drawable/sketch_forward" />
<View
style="@style/link_gray_style"
android:layout_margin="2dp" />
<TextView
android:id="@+id/sketch_clear"
style="@style/sketch_operation_style"
android:text="重绘" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
style="@style/evaluation_fragment_title_text_style"
android:layout_gravity="top"
android:layout_marginTop="3dp"
android:text="备注" />
<com.navinfo.omqs.ui.widget.MyEditeText
android:id="@+id/note_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_rect_white_2dp_bg"
android:elevation="2dp"
android:gravity="start"
android:hint="请输入备注信息"
android:inputType="textMultiLine"
android:lines="3"
android:maxLines="3"
android:paddingLeft="12dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:textSize="12sp" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="多媒体"
android:textColor="@color/default_blue_text_color"
android:textSize="16sp" />
<!--
这种效果也好实现,主要的关键点是 Android:clipChildren=”false” 这个属性。
1.配置ViewPager 和其父布局的 android:clipChildren属性为”false”.
(android:clipChildren表示是否限制子View在其范围内默认为true. 代码设置setClipChildren(false))
因为如果clipChildren属性设置为true,就表明我们要将children给clip掉就是说对于子元素来说超出当前view的部分都会被切掉那我们在这里把它设置成false就表明超出view的部分不要切掉依然显示。
注意setClipChildren(false)在3.0以上版本中,开启了硬件加速后将不能正常工作,所以需要将其设置为软件加速。设置软硬件加速使用 setLayerType(View.LAYER_TYPE_SOFTWARE, null); 也可以在布局文件中添加 android:layerType=”software”
-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:id="@+id/note_picture_left"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginRight="4dp"
android:background="@drawable/icon_picture_left"
android:padding="5dp" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/note_picture_viewpager"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight="1"
android:clipChildren="false" />
<ImageView
android:id="@+id/note_picture_right"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginLeft="4dp"
android:background="@drawable/icon_picture_right"
android:padding="5dp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/note_voice_recyclerview"
android:layout_width="match_parent"
android:layout_height="120dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<ImageView
android:id="@+id/note_camera"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="10dp"
android:src="@drawable/baseline_camera_alt_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/note_voice" />
<ImageView
android:id="@+id/note_voice"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="10dp"
android:src="@drawable/baseline_keyboard_voice_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/note_camera"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,26 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout 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="@dimen/fragment_phenomenon_width"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/shape_middle_fragment_bg"
android:gravity="right"
tools:context="com.navinfo.omqs.ui.fragment.evaluationresult.PhenomenonFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/phenomenon_left_recyclerview"
android:layout_width="148dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="@dimen/fragment_phenomenon_width"
android:layout_height="match_parent"
android:layout_marginTop="55dp"
android:background="@drawable/shape_middle_fragment_bg"
android:orientation="horizontal">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/phenomenon_right_recyclerview"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/phenomenon_left_recyclerview"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/phenomenon_left_recyclerview"
android:layout_width="148dp"
android:layout_height="match_parent"
android:layout_toLeftOf="@id/phenomenon_right_recyclerview" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/phenomenon_right_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentRight="true" />
</LinearLayout>
</LinearLayout>

View File

@ -2,13 +2,15 @@
<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="@dimen/fragment_problem_link_width"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/shape_middle_fragment_bg"
tools:context="com.navinfo.omqs.ui.fragment.evaluationresult.ProblemLinkFragment">
<androidx.recyclerview.widget.RecyclerView
android:layout_marginTop="55dp"
android:id="@+id/link_right_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_width="@dimen/fragment_problem_link_width"
android:layout_height="match_parent"
android:background="@drawable/shape_middle_fragment_bg"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -8,7 +8,7 @@
<EditText
android:id="@+id/task_search"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="32dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
@ -20,8 +20,19 @@
android:singleLine="true"
android:textSize="13sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/task_add_link"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/task_add_link"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:src="@drawable/selector_add_taskline"
app:layout_constraintBottom_toBottomOf="@id/task_search"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/task_search" />
<ImageView
android:layout_width="14dp"
android:layout_height="14dp"
@ -41,7 +52,7 @@
app:layout_constraintRight_toRightOf="@id/task_search"
app:layout_constraintTop_toTopOf="@id/task_search" />
<androidx.recyclerview.widget.RecyclerView
<com.yanzhenjie.recyclerview.SwipeRecyclerView
android:id="@+id/task_recyclerview"
android:layout_width="match_parent"
android:layout_height="0dp"

View File

@ -0,0 +1,285 @@
<?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="@dimen/right_fragment_w"
android:layout_height="match_parent"
android:background="@drawable/shape_right_fragment_bg"
tools:context=".ui.fragment.tasklink.TaskLinkFragment">
<TextView
android:id="@+id/task_link_bar_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:layout_marginTop="14dp"
android:drawableLeft="@drawable/selector_btn_back_xml"
android:text="测评Link"
android:textColor="@color/default_blue_text_color"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/task_link_bar_save"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="9dp"
android:layout_marginRight="14dp"
android:background="@drawable/ripple_fragment_save_button_bg"
android:src="@drawable/icon_save"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/task_link_bar_delete"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerInParent="true"
android:layout_marginRight="5dp"
android:background="@color/transparent"
android:src="@drawable/icon_delete"
app:layout_constraintBottom_toBottomOf="@id/task_link_bar_save"
app:layout_constraintRight_toLeftOf="@id/task_link_bar_save"
app:layout_constraintTop_toTopOf="@id/task_link_bar_save" />
<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="6dp"
android:paddingLeft="11dp"
android:paddingTop="6dp"
android:paddingRight="9dp"
android:paddingBottom="6dp"
app:layout_constraintBottom_toTopOf="@id/note_camera"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/task_link_bar_save">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="7dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
style="@style/evaluation_fragment_title_text_style"
android:layout_width="60dp"
android:text="当前任务" />
<TextView
android:id="@+id/task_link_task_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/task_link_back"
style="@style/sketch_operation_style"
android:src="@drawable/sketch_back" />
<View
style="@style/link_gray_style"
android:layout_margin="2dp" />
<TextView
android:id="@+id/task_link_clear"
style="@style/sketch_operation_style"
android:text="重绘" />
</LinearLayout>
<Button
android:id="@+id/task_link_add_point"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="打点" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="7dp"
android:orientation="horizontal">
<TextView
style="@style/evaluation_fragment_title_text_style"
android:layout_width="60dp"
android:text="Link长度" />
<TextView
android:id="@+id/task_link_length"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0米" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="7dp"
android:orientation="horizontal">
<TextView
style="@style/evaluation_fragment_title_text_style"
android:layout_width="60dp"
android:text="种别" />
<TextView
android:id="@+id/task_link_kind"
style="@style/evaluation_fragment_text_style"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="7dp"
android:orientation="horizontal">
<TextView
style="@style/evaluation_fragment_title_text_style"
android:layout_width="60dp"
android:text="功能等级" />
<TextView
android:id="@+id/task_link_functional_level"
style="@style/evaluation_fragment_text_style"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="7dp"
android:orientation="horizontal">
<TextView
style="@style/evaluation_fragment_title_text_style"
android:layout_width="60dp"
android:text="数据级别" />
<TextView
android:id="@+id/task_link_data_level"
style="@style/evaluation_fragment_text_style"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
style="@style/evaluation_fragment_title_text_style"
android:layout_width="60dp"
android:layout_gravity="top"
android:text="备注" />
<com.navinfo.omqs.ui.widget.MyEditeText
android:id="@+id/note_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_rect_white_2dp_bg"
android:elevation="2dp"
android:gravity="start"
android:hint="请输入备注信息"
android:inputType="textMultiLine"
android:lines="3"
android:maxLines="3"
android:paddingLeft="12dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:textSize="12sp" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="多媒体"
android:textColor="@color/default_blue_text_color"
android:textSize="16sp" />
<!--
这种效果也好实现,主要的关键点是 Android:clipChildren=”false” 这个属性。
1.配置ViewPager 和其父布局的 android:clipChildren属性为”false”.
(android:clipChildren表示是否限制子View在其范围内默认为true. 代码设置setClipChildren(false))
因为如果clipChildren属性设置为true,就表明我们要将children给clip掉就是说对于子元素来说超出当前view的部分都会被切掉那我们在这里把它设置成false就表明超出view的部分不要切掉依然显示。
注意setClipChildren(false)在3.0以上版本中,开启了硬件加速后将不能正常工作,所以需要将其设置为软件加速。设置软硬件加速使用 setLayerType(View.LAYER_TYPE_SOFTWARE, null); 也可以在布局文件中添加 android:layerType=”software”
-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:id="@+id/note_picture_left"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginRight="4dp"
android:background="@drawable/icon_picture_left"
android:padding="5dp" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/note_picture_viewpager"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight="1"
android:clipChildren="false" />
<ImageView
android:id="@+id/note_picture_right"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginLeft="4dp"
android:background="@drawable/icon_picture_right"
android:padding="5dp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/note_voice_recyclerview"
android:layout_width="match_parent"
android:layout_height="120dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<ImageView
android:id="@+id/note_camera"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="10dp"
android:src="@drawable/baseline_camera_alt_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/note_voice" />
<ImageView
android:id="@+id/note_voice"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="10dp"
android:src="@drawable/baseline_keyboard_voice_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/note_camera"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/task_link_middle_recyclerview"
android:layout_width="@dimen/fragment_problem_link_width"
android:layout_height="match_parent"
android:layout_marginTop="55dp"
app:layout_constraintRight_toRightOf="parent"
android:background="@drawable/shape_middle_fragment_bg" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -41,7 +41,7 @@
app:layout_constraintRight_toRightOf="@id/task_list_search"
app:layout_constraintTop_toTopOf="@id/task_list_search" />
<androidx.recyclerview.widget.RecyclerView
<com.yanzhenjie.recyclerview.SwipeRecyclerView
android:id="@+id/task_list_recyclerview"
android:layout_width="match_parent"
android:layout_height="0dp"

View File

@ -7,6 +7,7 @@
<item
android:id="@+id/personal_center_menu_offline_map"
android:icon="@drawable/baseline_map_24"
android:visible="false"
android:title="离线地图" />
<item
android:id="@+id/personal_center_menu_obtain_data"
@ -16,7 +17,7 @@
<item
android:id="@+id/personal_center_menu_import_data"
android:icon="@drawable/ic_baseline_import_export_24"
android:visible="true"
android:visible="false"
android:title="导入数据" />
<item
android:id="@+id/personal_center_menu_import_yuan_data"
@ -25,14 +26,19 @@
<item
android:id="@+id/personal_center_menu_scan_qr_code"
android:icon="@drawable/ic_baseline_scatter_plot_24"
android:title="扫一扫" />
android:title="扫码连电脑" />
<item
android:id="@+id/personal_center_menu_scan_indoor_data"
android:icon="@drawable/ic_baseline_scatter_plot_24"
android:title="室内整理" />
<item
android:visible="false"
android:icon="@drawable/ic_baseline_sim_card_download_24"
android:title="备份数据" />
<item
android:id="@+id/personal_center_menu_version"
android:icon="@drawable/ic_baseline_layers_24"
android:title="版本ONE_QE_V1.1.0_20230630_A" />
android:title="版本ONE_QE_V1.4.0_20230721_A" />
</group>
<group android:checkableBehavior="single">
<item android:title="小标题">
@ -50,6 +56,18 @@
<!-- android:icon="@drawable/ic_baseline_layers_24"-->
<!-- android:title="图层管理" />-->
<item
android:id="@+id/personal_center_menu_open_auto_location"
android:icon="@drawable/baseline_person_24"
android:visible="true"
android:title="开启自动定位" />
<item
android:id="@+id/personal_center_menu_close_auto_location"
android:icon="@drawable/baseline_person_24"
android:visible="true"
android:title="关闭自动定位" />
<item
android:id="@+id/personal_center_menu_test"
android:icon="@drawable/baseline_person_24"

View File

@ -20,4 +20,15 @@
android:name="com.navinfo.omqs.ui.fragment.evaluationresult.ProblemLinkFragment"
android:label="评测页面"
tools:layout="@layout/fragment_problem_link"></fragment>
<fragment
android:id="@+id/CanvasFragment"
android:name="com.navinfo.omqs.ui.fragment.note.CanvasFragment"
android:label="绘图页面"
tools:layout="@layout/fragment_canvas"></fragment>
<fragment
android:id="@+id/TaskLinkMiddleFragment"
android:name="com.navinfo.omqs.ui.fragment.tasklink.TaskLinkMiddleFragment"
android:label="新增评测Link属性选择页面"
tools:layout="@layout/fragment_task_link_middle"></fragment>
</navigation>

View File

@ -28,6 +28,19 @@
android:name="com.navinfo.omqs.ui.fragment.evaluationresult.EvaluationResultFragment"
android:label="评测页面"
tools:layout="@layout/fragment_evaluation_result">
</fragment>
<fragment
android:id="@+id/NoteFragment"
android:name="com.navinfo.omqs.ui.fragment.note.NoteFragment"
android:label="便签页面"
tools:layout="@layout/fragment_note">
</fragment>
<fragment
android:id="@+id/TaskLinkFragment"
android:name="com.navinfo.omqs.ui.fragment.tasklink.TaskLinkFragment"
android:label="测评Link"
tools:layout="@layout/fragment_task_link">
</fragment>
</navigation>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CanvasView">
<attr name="isSavePoint" format="boolean" />
</declare-styleable>
</resources>

View File

@ -1,5 +1,20 @@
<resources>
<style name="sketch_operation_style">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item>
<item name="android:gravity">center</item>
<item name="android:paddingTop">5dp</item>
<item name="android:paddingBottom">5dp</item>
</style>
<style name="link_gray_style" comment="竖着的灰色分隔线">
<item name="android:layout_width">1dp</item>
<item name="android:layout_height">match_parent</item>
<item name="android:background">#C3C3C3</item>
</style>
<style name="main_activity_bottom_sheet_icon" comment="主控页面下方按钮样式">
<item name="android:layout_width">36dp</item>
<item name="android:layout_height">36dp</item>

View File

@ -79,7 +79,7 @@ dependencies {
implementation "net.sf.kxml:kxml2:2.3.0"
implementation 'org.slf4j:slf4j-api:2.0.7'
implementation project(":vtm-themes")
api project(":vtm-android")
implementation project(":vtm-android")
implementation project(':vtm-extras')
implementation project(":vtm-http")
// implementation "org.mapsforge:vtm-themes:$vtmVersion"

View File

@ -1479,132 +1479,20 @@
</m>
</m>
<!-- &lt;!&ndash; 自定义渲染样式 &ndash;&gt;-->
<!-- <m k="navi_type" zoom-max="22" zoom-min="15">-->
<!-- &lt;!&ndash; 车道中心线 &ndash;&gt;-->
<!-- <m v="had_lane_link">-->
<!-- <line dasharray="20,20" fix="true" stipple-stroke="#00000000" stroke="#ff0000"-->
<!-- width="0.3" />-->
<!-- </m>-->
<!-- &lt;!&ndash; 车道边线 &ndash;&gt;-->
<!-- <m v="had_lane_mark_link">-->
<!-- <line stipple-width="0.5" stroke="#0000ff" width="0.1" />-->
<!-- </m>-->
<!-- &lt;!&ndash;道路箭头 objectArrow&ndash;&gt;-->
<!-- <m v="object_arrow">-->
<!-- <area fade="5" fill="#88aaaa00" stroke="#ff0000" stroke-width="0.1"></area>-->
<!-- </m>-->
<!-- &lt;!&ndash;人行横道 objectcrosswalk&ndash;&gt;-->
<!-- <m v="object_crosswalk">-->
<!-- <area fill="#88800080" stroke="#ff0000" stroke-width="0.2"></area>-->
<!-- <caption style="bold" dy="12" fill="#4D2F08" k="name" size="14" stroke="#ffffff"-->
<!-- stroke-width="2.0" />-->
<!-- <caption style="bold" dy="-12" fill="#4D2F08" k="ele" size="12" stroke="#ffffff"-->
<!-- stroke-width="2.0" />-->
<!-- </m>-->
<!-- &lt;!&ndash;杆状物 objectpole&ndash;&gt;-->
<!-- <m v="object_pole">-->
<!-- <line stipple-width="0.5" stroke="#8800aaaa" width="0.1" />-->
<!-- </m>-->
<!-- &lt;!&ndash;对象标志 objectsymbol&ndash;&gt;-->
<!-- <m v="object_symbol">-->
<!-- <area fill="#880000cc" stroke="#0000cc" stroke-width="0.2"></area>-->
<!-- </m>-->
<!-- &lt;!&ndash;交通信号灯 objectTrfficLights&ndash;&gt;-->
<!-- <m v="object_trrfic">-->
<!-- <area fill="#8800cc00" stroke="#00cc00" stroke-width="0.2"></area>-->
<!-- </m>-->
<!-- <m zoom-max="19" zoom-min="15">-->
<!-- <text use="ferry" />-->
<!-- </m>-->
<!-- &lt;!&ndash;道路方向&ndash;&gt;-->
<!-- <m v="symbol_object_arrow">-->
<!-- <symbol use="oneway"></symbol>-->
<!-- </m>-->
<!-- &lt;!&ndash;杆状物&ndash;&gt;-->
<!-- <m v="symbol_object_pole">-->
<!-- <symbol src="assets:symbols/gondola.svg" />-->
<!-- </m>-->
<!-- &lt;!&ndash;对象标志&ndash;&gt;-->
<!-- <m v="symbol_object_symbol">-->
<!-- <symbol src="assets:symbols/peak.svg" />-->
<!-- </m>-->
<!-- &lt;!&ndash;交通信号灯&ndash;&gt;-->
<!-- <m v="symbol_object_traffic">-->
<!-- <symbol src="assets:symbols/traffic_signal.svg" />-->
<!-- </m>-->
<!-- </m>-->
<!-- <m k="nav_style">-->
<!-- <m v="symbol_object_line">-->
<!-- <m k="rule" zoom-max="22" zoom-min="15">-->
<!-- &lt;!&ndash; 蓝色黑色间隔线 &ndash;&gt;-->
<!-- <m v="blue_link">-->
<!-- <line dasharray="20,20" fix="true" stipple-stroke="#00000000" stroke="#00000000"-->
<!-- width="0.1" />-->
<!-- </m>-->
<!-- &lt;!&ndash; 黄色线 &ndash;&gt;-->
<!-- <m v="yellow_link">-->
<!-- <line stipple-width="0.1" stroke="#f4ea2a" width="0.1" />-->
<!-- </m>-->
<!-- </m>-->
<!-- <line stipple-width="0.5" stroke="#33aaaa" width="0.3" />-->
<!-- </m>-->
<!-- <m v="symbol_track_point" zoom-max="25" zoom-min="10">-->
<!-- <symbol src="assets:symbols/dot_blue.svg" />-->
<!-- </m>-->
<!-- </m>-->
<m k="qi_table">
<!--车道数-->
<m v="OMDB_LANE_NUM">
<m k="laneNum">
<m v="1">
<line stroke="#545D6C" width="3" />
</m>
<m v="2">
<line stroke="#545D6C" width="6" />
</m>
<m v="3">
<line stroke="#545D6C" width="9" />
</m>
<m v="4">
<line stroke="#545D6C" width="12" />
</m>
<m v="5">
<line stroke="#545D6C" width="15" />
</m>
<m v="6">
<line stroke="#545D6C" width="18" />
</m>
<m v="7">
<line stroke="#545D6C" width="21" />
</m>
<m v="8">
<line stroke="#545D6C" width="24" />
</m>
<m v="9">
<line stroke="#545D6C" width="27" />
</m>
<m v="10">
<line stroke="#545D6C" width="30" />
</m>
<m v="11">
<line stroke="#545D6C" width="33" />
</m>
<m v="12">
<line stroke="#545D6C" width="36" />
</m>
</m>
</m>
<!-- 道路线 -->
<m v="OMDB_RD_LINK">
<m v="OMDB_RD_LINK" zoom-max="19">
<line stroke="#9c9c9c" width="1" />
</m>
<!-- 检查点 -->
<m v="OMDB_CHECKPOINT" zoom-max="19">
<symbol src="assets:omdb/icon_1012_0.svg" symbol-height="64"
symbol-width="64"></symbol>
</m>
<!--道路种别-->
<m v="OMDB_RD_LINK_KIND">
<m v="OMDB_RD_LINK_KIND" zoom-max="19">
<outline-layer id="kind0" stroke="#44000000" width="0.1" />
<outline-layer id="kind1" stroke="#aa807040" width="0.1" />
<m k="kind" v="1">
@ -1637,159 +1525,170 @@
</m>
<!--常规点限速-->
<m v="OMDB_SPEEDLIMIT">
<m v="OMDB_SPEEDLIMIT" zoom-max="19">
<m k="speedFlag" v="0">
<!-- <symbol src="assets:omdb/round_speedlimit.svg" symbol-width="30" symbol-height="30"></symbol>-->
<caption fill="#000000" k="maxSpeed" priority="0" size="12" stroke="#ffffff"
stroke-width="1.0"></caption>
<symbol src="assets:omdb/icon_4002_0.svg" symbol-height="46"
symbol-width="46"></symbol>
<!-- <caption k="minSpeed" dy="-28" fill="#000000" priority="0" size="14" stroke="#ffffff"-->
<!-- stroke-width="1.0"></caption>-->
</m>
<m k="speedFlag" v="1">
<caption fill="#000000" k="maxSpeed" priority="0" size="12" stroke="#ffffff"
stroke-width="1.0"></caption>
<symbol src="assets:omdb/icon_4002_1.svg" symbol-height="46"
symbol-width="46"></symbol>
<!-- <caption k="minSpeed" dy="-28" fill="#000000" priority="0" size="14" stroke="#ffffff"-->
<!-- stroke-width="1.0"></caption>-->
</m>
</m>
<!--条件点限速-->
<m v="OMDB_SPEEDLIMIT_COND">
<m k="speedFlag" v="0">
<!-- <symbol src="assets:omdb/round_speedlimit.svg" symbol-width="30" symbol-height="30"></symbol>-->
<caption fill="#000000" k="maxSpeed" priority="0" size="12" stroke="#ffffff"
stroke-width="1.0"></caption>
<symbol src="assets:omdb/icon_4003_0.svg" symbol-height="46"
symbol-width="46"></symbol>
<!-- <caption k="minSpeed" dy="-28" fill="#000000" priority="0" size="14" stroke="#ffffff"-->
<!-- stroke-width="1.0"></caption>-->
</m>
<m k="speedFlag" v="1">
<caption fill="#000000" k="maxSpeed" priority="0" size="12" stroke="#ffffff"
stroke-width="1.0"></caption>
<symbol src="assets:omdb/icon_4003_1.svg" symbol-height="46"
symbol-width="46"></symbol>
<!-- <caption k="minSpeed" dy="-28" fill="#000000" priority="0" size="14" stroke="#ffffff"-->
<!-- stroke-width="1.0"></caption>-->
</m>
</m>
<!--可变点限速-->
<m v="OMDB_SPEEDLIMIT_VAR">
<m v="OMDB_SPEEDLIMIT_VAR" zoom-max="19">
<m k="speedFlag" v="0">
<!-- <symbol src="assets:omdb/round_speedlimit.svg" symbol-width="30" symbol-height="30"></symbol>-->
<caption fill="#000000" k="maxSpeed" priority="0" size="12" stroke="#ffffff"
stroke-width="1.0"></caption>
<symbol src="assets:omdb/icon_4004_0.svg" symbol-height="46"
symbol-width="46"></symbol>
<!-- <caption k="minSpeed" dy="-28" fill="#000000" priority="0" size="14" stroke="#ffffff"-->
<!-- stroke-width="1.0"></caption>-->
</m>
<m k="speedFlag" v="1">
<caption fill="#000000" k="maxSpeed" priority="0" size="12" stroke="#ffffff"
stroke-width="1.0"></caption>
<symbol src="assets:omdb/icon_4004_1.png" symbol-height="46"
<symbol src="assets:omdb/icon_4004_0.svg" symbol-height="46"
symbol-width="46"></symbol>
<!-- <caption k="minSpeed" dy="-28" fill="#000000" priority="0" size="14" stroke="#ffffff"-->
<!-- stroke-width="1.0"></caption>-->
</m>
</m>
<!--车道中心线-->
<m v="OMDB_LANE_LINK_LG">
<line dasharray="35,35" stroke="#ecf0f1" width="0.1" />
<m v="OMDB_LANE_LINK_LG" zoom-min="20">
<m k="width" v="~">
<line stroke="#7A88A0" width="5" />
</m>
</m>
<!-- 道路边界类型 -->
<m v="OMDB_RDBOUND_BOUNDARYTYPE">
<line stroke="#ffffff" width="0.1" />
<m v="OMDB_RDBOUND_BOUNDARYTYPE" zoom-min="20">
<outline-layer id="boundaryType" stroke="#8e44ad" width="0.1" />
<m k="boundaryType" v="0|2|3|4|5|6|7|8|9">
<line stroke="#ffffff" use="boundaryType" width="0.1"/>
</m>
<m k="boundaryType" v="1">
<!--无标线无可区分边界-->
<line dasharray="12,6" repeat-start="0" stroke="#ffffff" width="0.2"/>
</m>
</m>
<!-- 车道边界类型 -->
<m v="OMDB_LANE_MARK_BOUNDARYTYPE">
<outline-layer id="boundary" stroke="#ffffff" width="0.2" />
<m k="boundaryType">
<m v="OMDB_LANE_MARK_BOUNDARYTYPE" zoom-min="20">
<outline-layer id="boundary" stroke="#ffffff" width="0.1" />
<m k="boundaryType" v="2">
<!--标线-->
<m v="2">
<m k="markType">
<m k="markType" v="0|1|4|5|6|7|8">
<!--其他|实线-->
<m k="markColor" v="1">
<line stroke="#ffffff" use="boundaryType" />
</m>
<m k="markColor" v="2">
<line stroke="#eccc68" use="boundaryType" />
</m>
<m k="markColor" v="6">
<line stroke="#0000ff" use="boundaryType" />
</m>
<m k="markColor" v="7">
<line stroke="#00ff00" use="boundaryType" />
</m>
<m k="markColor" v="0|9">
<line stroke="#8e44ad" use="boundaryType" />
</m>
</m>
<m k="markType" v="2|3">
<!--其他|实线-->
<m v="0|1|2|3|4|5|6|7|8">
<!--其他|实线-->
<m v="0|1">
<m k="markColor">
<m v="0|1">
<line stroke="#ffffff" use="boundaryType" />
</m>
<m v="2">
<line stroke="#eccc68" use="boundaryType" />
</m>
<m v="6">
<line stroke="#0000ff" use="boundaryType" />
</m>
<m v="7">
<line stroke="#00ff00" use="boundaryType" />
</m>
<m v="9">
<line stroke="#8e44ad" use="boundaryType" />
</m>
</m>
<m k="markColor" v="1">
<line dasharray="12,6" repeat-start="0" stroke="#ffffff" width="0.1"/>
</m>
<!--虚线-->
<m v="2">
<m k="markColor">
<m v="0|1">
<line dasharray="13,135" stipple="5" stipple-stroke="#000000"
stroke="#ffffff" use="boundaryType" />
</m>
<m v="2">
<line dasharray="13,135" stipple="5" stipple-stroke="#ffffff"
stroke="#eccc68" use="boundaryType" />
</m>
<m v="6">
<line dasharray="13,135" stipple="5" stipple-stroke="#ffffff"
stroke="#0000ff" use="boundaryType" />
</m>
<m v="7">
<line dasharray="13,135" stipple="5" stipple-stroke="#ffffff"
stroke="#00ff00" use="boundaryType" />
</m>
<m v="9">
<line dasharray="13,135" stipple="5" stipple-stroke="#ffffff"
stroke="#8e44ad" use="boundaryType" />
</m>
</m>
<m k="markColor" v="2">
<line dasharray="12,6" repeat-start="0" stroke="#eccc68" width="0.1"/>
</m>
<!--导流区边线-->
<m v="4">
<line outline="boundary" stroke="#545D6C"></line>
<lineSymbol repeat-gap="0.5" repeat-start="0"
src="assets:omdb/icon_right.png" />
<m k="markColor" v="6">
<line dasharray="12,6" repeat-start="0" stroke="#0000ff" width="0.1"/>
</m>
<!-- &lt;!&ndash;铺设路面边缘&ndash;&gt;-->
<!-- <m v="5">-->
<!-- <line outline="#ffffff" fix="true" src="assets:omdb/icon_close.png" stroke="#ffffffff" use="boundaryType"/>-->
<!-- </m>-->
<m k="markColor" v="7">
<line dasharray="12,6" repeat-start="0" stroke="#00ff00" width="0.1"/>
</m>
<m k="markColor" v="0|9">
<line dasharray="12,6" repeat-start="0" stroke="#8e44ad" width="0.1"/>
</m>
</m>
</m>
</m>
<m k="boundaryType" v="0|3|4|5|6|7|8|9">
<line stroke="#ffffff" use="boundaryType" />
</m>
<!--只区分虚线与实线-->
<m k="boundaryType" v="1">
<line dasharray="12,6" repeat-start="0" stroke="#ffffff" width="0.1"/>
</m>
</m>
<!--隧道-->
<m v="OMDB_TUNNEL" zoom-max="19">
<m k="formOfWay">
<line dasharray="0.2,0.2" stroke="#d4237a" width="0.2" />
</m>
<m k="type" v="s_2_p">
<symbol repeat="false" repeat-start="0" rotate="false"
src="assets:omdb/icon_2202_0.svg" symbol-height="32" symbol-width="32"></symbol>
</m>
<m k="type" v="e_2_p">
<symbol repeat="false" repeat-start="0" rotate="false"
src="assets:omdb/icon_2202_1.svg" symbol-height="32" symbol-width="32"></symbol>
</m>
</m>
<!--道路方向-->
<m v="OMDB_LINK_DIRECT">
<m k="direct">
<m v="2">
<!-- <lineSymbol src="assets:omdb/oneway_right.svg"></lineSymbol>-->
<lineSymbol src="assets:omdb/oneway_right.svg"></lineSymbol>
</m>
<m v="3">
<!-- <lineSymbol src="assets:omdb/oneway_left.svg"></lineSymbol>-->
<lineSymbol src="assets:omdb/oneway_left.svg"></lineSymbol>
</m>
</m>
</m>
<!--交通灯-->
<m v="OMDB_TRAFFICLIGHT">
<m v="OMDB_TRAFFICLIGHT" zoom-max="19">
<symbol repeat="false" rotate="false" src="assets:omdb/icon_4022_0.svg"
symbol-height="69" symbol-width="69"></symbol>
</m>
<!--普通交限-->
<m v="OMDB_RESTRICTION">
<m v="OMDB_RESTRICTION" zoom-max="19">
<m k="angle">
<symbol repeat="false" repeat-start="0" rotate="false"
src="assets:omdb/icon_4006_0.svg" symbol-height="69" symbol-width="69"></symbol>
@ -1803,12 +1702,9 @@
<line use="s2e" />
</m>
</m>
<!--电子眼-->
<m v="OMDB_ELECTRONICEYE">
<!-- <m k="angle">-->
<!-- <symbol repeat="false" repeat-start="0" rotate="false"-->
<!-- src="assets:symbols/volcano.svg" symbol-height="69" symbol-width="69"></symbol>-->
<!-- </m>-->
<m v="OMDB_ELECTRONICEYE" zoom-max="19">
<caption dy="-30" fill="#000000" k="name" priority="0" size="14"
stroke="#ffffff" stroke-width="1.0"></caption>
<m k="type" v="angle">
@ -1819,8 +1715,9 @@
<line use="s2e" />
</m>
</m>
<!-- 路口 -->
<m v="OMDB_INTERSECTION">
<m v="OMDB_INTERSECTION" zoom-max="19">
<m k="type" v="node">
<symbol src="assets:symbols/dot_blue_dark.svg"></symbol>
</m>
@ -1828,424 +1725,424 @@
<symbol src="assets:symbols/dot_magenta.svg"></symbol>
</m>
</m>
<!-- 道路名 -->
<m v="OMDB_LINK_NAME">
<text use="road"></text>
</m>
<!-- 车信 -->
<m v="OMDB_LANEINFO">
<m v="OMDB_LANEINFO" zoom-max="19">
<m k="currentType" v="0">
<m k="currentDirect" v="1">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_2.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_2.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_3">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_2_3.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_2_3.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_3_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_2_3_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_2_3_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_2_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_2_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_2_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_2_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_2_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_2_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_3">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_3.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_3.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_3_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_3_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_3_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_3_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_3_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_3_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_3_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_3_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_3_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_7">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_1_7.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_1_7.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_2.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_2.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_3">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_2_3.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_2_3.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_3_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_2_3_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_2_3_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_2_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_2_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_2_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_2_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_2_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_2_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="3">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_3.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_3.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="3_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_3_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_3_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="3_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_3_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_3_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="3_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_3_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_3_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="4_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_4_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_4_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="4_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_4_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_4_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="5_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_5_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_5_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="7">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/normal/1301_7.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/normal/1301_7.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
</m>
<m k="currentType" v="1">
<m k="currentDirect" v="0">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_0.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_0.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_2.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_2.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_3">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_2_3.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_2_3.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_3_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_2_3_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_2_3_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_2_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_2_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_2_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_2_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_2_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_2_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_3">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_3.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_3.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_3_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_3_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_3_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_3_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_3_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_3_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_3_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_3_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_3_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_7">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_1_7.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_1_7.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_2.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_2.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_3">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_2_3.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_2_3.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_3_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_2_3_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_2_3_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_2_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_2_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_2_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_2_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_2_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_2_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="3">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_3.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_3.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="3_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_3_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_3_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="3_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_3_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_3_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="3_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_3_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_3_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="4_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_4_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_4_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="4_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_4_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_4_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="5_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_5_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_5_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="7">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/extend/1301_7.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/extend/1301_7.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
</m>
<m k="currentType" v="2">
<m k="currentDirect" v="0">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_0.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_0.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_2.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_2.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_3">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_2_3.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_2_3.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_3_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_2_3_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_2_3_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_2_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_2_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_2_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_2_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_2_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_2_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_2_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_3">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_3.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_3.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_3_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_3_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_3_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_3_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_3_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_3_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_3_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_3_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_3_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="1_7">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_1_7.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_1_7.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_2.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_2.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_3">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_2_3.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_2_3.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_3_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_2_3_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_2_3_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_2_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_2_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_2_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_2_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="2_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_2_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_2_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="3">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_3.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_3.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="3_4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_3_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_3_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="3_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_3_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_3_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="3_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_3_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_3_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="4">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_4.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_4.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="4_5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_4_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_4_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="4_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_4_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_4_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="5">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_5.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_5.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="5_6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_5_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_5_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="6">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_6.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_6.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
<m k="currentDirect" v="7">
<symbol repeat="false" repeat-start="0" repeat-gap="2000"
src="assets:omdb/4601/bus/1301_7.svg" symbol-height="29" symbol-width="29"></symbol>
src="assets:omdb/4601/bus/1301_7.svg" symbol-height="24" symbol-width="24"></symbol>
</m>
</m>
</m>
<m v="OMDB_AREA">
<area use="water" repeat="true" src="assets:omdb/area_test.jpg" stroke="#ff0000" stroke-width="2"></area>
</m>
<m k="type" v="s_2_e">
<line use="s2e" />
</m>
<m v="OMDB_POLE">
<line stroke="#0000ff" width="0.1" cap="butt"></line>
<line stroke="#0000ff" width="2" cap="butt"></line>
</m>
<m v="OMDB_TRAFFIC_SIGN">
<area use="water" repeat="false" stroke="#ff0000" stroke-width="2"></area>
</m>
<m v="OMDB_AREA">
<area use="water" repeat="true" src="assets:omdb/area_test.jpg" stroke="#ff0000" stroke-width="2"></area>
</m>
</m>
</rendertheme>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="b" xmlns="http://www.w3.org/2000/svg" width="124.7" height="124.7" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 124.7 124.7"><defs><style>.i{fill:url(#f);}.j{fill:#fff;}.k{fill:#1566e8;}.l,.m{fill:#535a60;}.n{fill:#262d34;isolation:isolate;opacity:.2;}.o{fill:url(#g);stroke:#8b9fae;stroke-miterlimit:10;stroke-width:1px;}.m{opacity:0;}</style><linearGradient id="f" x1="60.1" y1="50.4" x2="64.9" y2="50.4" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#989898"/><stop offset="0" stop-color="#a3a3a3"/><stop offset=".1" stop-color="#c4c5c5"/><stop offset=".2" stop-color="#d8d9d9"/><stop offset=".3" stop-color="#e0e1e1"/><stop offset=".4" stop-color="#dbdcdc"/><stop offset=".5" stop-color="#cccece"/><stop offset=".6" stop-color="#b5b6b7"/><stop offset=".7" stop-color="#949697"/><stop offset=".8" stop-color="#6a6c6f"/><stop offset=".8" stop-color="#3f4246"/><stop offset="1" stop-color="#404247"/><stop offset="1" stop-color="#43434a"/></linearGradient><linearGradient id="g" x1="40.1" y1="23.8" x2="84.6" y2="23.8" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#afbacb"/><stop offset=".1" stop-color="#c1ccda"/><stop offset=".4" stop-color="#d9e6f0"/><stop offset=".5" stop-color="#e3f0f8"/><stop offset=".6" stop-color="#dde9f2"/><stop offset=".8" stop-color="#ccd8e4"/><stop offset="1" stop-color="#b1bbcc"/><stop offset="1" stop-color="#aeb8c9"/></linearGradient></defs><g id="c"><g><rect class="m" y="0" width="124.7" height="124.7"/><g><ellipse id="d" class="n" cx="62.4" cy="61.8" rx="14.4" ry="3.7"/><ellipse id="e" class="l" cx="62.4" cy="61.8" rx="7.5" ry="3"/><path class="i" d="M62.4,38.3h0c1.4,0,2.6,1.2,2.6,2.6v19.2c0,1.4-1.1,2.5-2.5,2.5h-.3c-1.4,0-2.5-1.1-2.5-2.5v-19.3c0-1.4,1.2-2.6,2.6-2.6Z"/><rect class="o" x="40.1" y=".5" width="44.5" height="46.6" rx="14.4" ry="14.4"/><rect class="k" x="40.6" y="2.6" width="43.5" height="44" rx="14.1" ry="14.1"/><path id="h" class="j" d="M46,11.4c-.3,0-.6-.2-.7-.4s0-.6,.1-.8c1.3-1.6,3-2.9,4.8-3.9,.2,0,.4-.1,.6,0,.2,0,.4,.2,.5,.4,.2,.4,0,.9-.3,1.1-1.7,.9-3.1,2.1-4.3,3.5-.2,.2-.4,.3-.6,.3h0Zm-1.8,2.6c-.1,0-.3,0-.4-.1-.2-.1-.3-.3-.4-.5,0-.2,0-.4,.1-.6l.3-.4c.1-.2,.3-.3,.5-.4,.2,0,.4,0,.6,0,.2,.1,.3,.3,.4,.5s0,.4-.1,.6l-.3,.4c-.1,.2-.4,.4-.7,.4h0Z"/><g><path class="j" d="M61,23.3c-.3-.1-.7-.4-1.2-.7,0,0-.2,0-.2-.1v1.5h-7.1v-1.4c-.2,.2-.5,.4-.9,.7-.1,0-.2,.2-.3,.2-.3-.5-.5-1.1-.9-1.6,.2,0,.4-.2,.6-.3h-1.6v1.8c.7,.5,1.4,1.1,2.1,1.7l-.9,1.4-1.2-1.2v7.3h-1.6v-7.6c-.4,1.3-1,2.5-1.8,3.8,0-.6-.2-1.4-.4-2.3,.9-1.5,1.6-3.2,2.2-4.9h-1.8v-1.5h1.8v-3.2h1.6v3.2h1.6v1.5c1.9-1.2,3.4-2.8,4.4-4.9h1.8c0,.1-.3,.9-.3,.9,1.4,1.8,3,3.2,4.8,4.1-.3,.5-.5,1.1-.7,1.6Zm-10.3,8.5v-1.4h6.6c.4-1,.8-2.4,1.4-4.4,.1-.5,.2-.9,.3-1.1l1.6,.4c-.1,.4-.3,1-.6,1.7-.5,1.5-.9,2.6-1.2,3.4h2.4v1.4h-10.6Zm2-2c-.4-1.4-.8-2.9-1.2-4.3l1.4-.3c.5,1.3,.9,2.7,1.3,4.2l-1.5,.4Zm3.3-10.8c-.9,1.3-2,2.5-3.3,3.5h6.9c-1.5-1.1-2.7-2.3-3.5-3.5Zm-.3,10.1c-.2-1.1-.5-2.5-1-4l1.5-.3c.4,1.3,.7,2.7,.9,4l-1.4,.3Z"/><path class="j" d="M77.8,23.9c-.5-.1-1-.3-1.4-.5v6.1h-11.6v-6c-.1,0-.3,.1-.5,.2-.4,.2-.8,.3-1.1,.4,0-.2-.2-.6-.4-1.1,0-.2-.2-.4-.2-.5,2.4-.7,4.4-1.6,6-2.7h-5.6v-1.4h6.6v-1.5h1.7v1.5h6.6v1.4h-5.6c1.6,1.1,3.6,2,6,2.6l-.7,1.6Zm-15.1,8.1v-1.3h15.6v1.3h-15.6Zm7-9.5v-2c-1.3,1.1-2.6,1.9-3.9,2.5h9.7c-1.6-.7-3-1.6-4-2.6v2h-1.7Zm-3.2,1.8v1.3h8.1v-1.3h-8.1Zm0,2.4v1.3h8.1v-1.3h-8.1Z"/></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1689041545166" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="30665" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M512.005117 958.708971C265.683035 958.708971 65.290005 758.316965 65.290005 511.99386c0-246.310825 200.39303-446.703855 446.715111-446.703855 246.310825 0 446.703855 200.39303 446.703855 446.703855C958.708971 758.316965 758.316965 958.708971 512.005117 958.708971zM512.005117 169.716356c-188.738595 0-342.289784 153.545048-342.289784 342.277504 0 188.738595 153.551188 342.289784 342.289784 342.289784 188.733479 0 342.278527-153.551188 342.278527-342.289784C854.283644 323.261405 700.738595 169.716356 512.005117 169.716356z" p-id="30666" fill="#fcba5a"></path></svg>

After

Width:  |  Height:  |  Size: 900 B

View File

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="4" height="58.142" viewBox="0 0 4 58.142">
<defs>
<style>.a{fill:none;stroke:#ebb972;stroke-width:4px;}.b{opacity:0.001;}</style>
</defs>
<g transform="translate(-401.035 -35.964)">
<g transform="translate(313.535 166.535) rotate(-90)">
<line class="a" x2="29.071" transform="translate(101.5 89.5)" />
</g>
<g class="b" transform="translate(313.535 195.605) rotate(-90)">
<line class="a" x2="29.071" transform="translate(101.5 89.5)" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 580 B

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="b" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<defs>
<style>.e{fill:#fcba5a;}</style>
</defs>
<g id="c">
<path id="d" class="e"
d="M31.9,0l-14.3,23.2-1.6,2.6-1.6-2.6L0,0h0V6.1L14.1,28.9l1.9,3.1h0s1.9-3.1,1.9-3.1L32,6V0h0Z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 365 B

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<defs>
<style>.a{fill:#fcba5a;}</style>
</defs>
<path class="a"
d="M31.94,0,17.6,23.21l-1.62,2.622L14.4,23.274.021,0H0V6.084L14.09,28.891l1.869,3.094.024.015,1.888-3.109L32,6.021V0Z"
transform="translate(0 0)" />
</svg>

After

Width:  |  Height:  |  Size: 339 B

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="48" viewBox="0 0 15 48">
<defs>
<style>.a{fill:#ebb972;}</style>
</defs>
<rect class="a" width="15" height="48" rx="7.5" />
</svg>

After

Width:  |  Height:  |  Size: 209 B

View File

@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80">
<defs>
<style>
.a{fill:#fceaa0;stroke:#1b23b4;stroke-width:3px;}.b{fill:#1b23b4;}.c{stroke:none;}.d{fill:none;}
</style>
</defs>
<g transform="translate(-126 -381)">
<g transform="translate(9304 7585)">
<g class="a" transform="translate(-9178 -7204)">
<circle class="c" cx="40" cy="40" r="40" />
<circle class="d" cx="40" cy="40" r="38.5" />
</g>
</g>
<path class="b"
d="M257.043,173.635V146.2c0-9.344-8.378-16.918-18.708-16.918s-18.712,7.574-18.712,16.918v27.436H214.94V145.378c0-11.808,10.6-21.378,23.684-21.378s23.683,9.57,23.683,21.378v28.257Zm-18.13-42.773c13.594-.133,16.377,13.195,16.377,13.195v29.579H254.7l-9.934-14.271V144.584s-.436-4.223-5.851-4.223-6.431,4.223-6.431,4.223v14.779l-10.2,14.271h-.913V144.06S223.714,131.009,238.913,130.861Zm5.049,28.5,10.159,14.271h-31.21l10.159-14.272h10.893Zm0,0"
transform="translate(-72.624 269.184)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><defs><style>.a{fill:#1b23b4;stroke:#fceaa0;stroke-width:3px;}.b{fill:#fceaa0;}.c{stroke:none;}.d{fill:none;}</style></defs><g transform="translate(-268 -381)"><g transform="translate(9446 7585)"><g class="a" transform="translate(-9178 -7204)"><circle class="c" cx="40" cy="40" r="40"/><circle class="d" cx="40" cy="40" r="38.5"/></g></g><path class="b" d="M257.043,173.635V146.2c0-9.344-8.378-16.918-18.708-16.918s-18.712,7.574-18.712,16.918v27.436H214.94V145.378c0-11.808,10.6-21.378,23.684-21.378s23.683,9.57,23.683,21.378v28.257Zm-18.13-42.773c13.594-.133,16.377,13.195,16.377,13.195v29.579H254.7l-9.934-14.271V144.584s-.436-4.223-5.851-4.223-6.431,4.223-6.431,4.223v14.779l-10.2,14.271h-.913V144.06S223.714,131.009,238.913,130.861Zm5.049,28.5,10.159,14.271h-31.21l10.159-14.272h10.893Zm0,0" transform="translate(69.376 269.184)"/></g></svg>

After

Width:  |  Height:  |  Size: 928 B

View File

@ -1 +1,45 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="136" height="136" viewBox="0 0 136 136"><defs><style>.a,.f{fill:#fff;}.a{opacity:0;}.b{fill:#ff5f4c;opacity:0.304;}.c{fill:#a74d4b;opacity:0.708;}.d{fill:url(#a);}.e{fill:url(#b);}.g{fill:#2a23f5;stroke:#db4646;stroke-linecap:square;stroke-width:3px;stroke-dasharray:9 10;}.h{stroke:none;}.i{fill:none;}</style><radialGradient id="a" cx="0.21" cy="0.134" r="1.274" gradientTransform="matrix(0.849, 0.529, -0.307, 0.493, 0.073, -0.043)" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#ff9287"/><stop offset="0.786" stop-color="#ff5f4c"/><stop offset="1" stop-color="#ff5f4c"/></radialGradient><radialGradient id="b" cx="0.5" cy="0.5" r="0.5" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#e75545"/><stop offset="0.793" stop-color="#c4483b"/><stop offset="1" stop-color="#983b31"/></radialGradient></defs><g transform="translate(-956 -396)"><rect class="a" width="136" height="136" transform="translate(956 396)"/><g transform="translate(989.164 429.346)"><g transform="translate(10.653 81.66)"><ellipse class="b" cx="24.183" cy="8.497" rx="24.183" ry="8.497"/><ellipse class="c" cx="8.497" cy="3.268" rx="8.497" ry="3.268" transform="translate(15.687 5.229)"/></g><g transform="translate(0 0)"><path class="d" d="M22.956,71.538q-.792-.8-1.543-1.533A36.466,36.466,0,0,1,0,36.4C0,16.3,15.6,0,34.837,0S69.673,16.3,69.673,36.4c0,15.235-8.954,28.283-21.664,33.711q-.588.673-1.219,1.424A73.582,73.582,0,0,0,35.337,90.157S30.335,78.981,22.956,71.538Z" transform="translate(0 0)"/><circle class="e" cx="27.451" cy="27.451" r="27.451" transform="translate(7.029 7.568)"/></g></g><g transform="translate(10096 7643)"><circle class="f" cx="28" cy="28" r="28" transform="translate(-9100 -7207)"/><g class="g" transform="translate(-9096 -7203)"><circle class="h" cx="24" cy="24" r="24"/><circle class="i" cx="24" cy="24" r="25.5"/></g></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="136"
height="136" viewBox="0 0 136 136">
<defs>
<style>
.a,.f{fill:#fff;}.a{opacity:0;}.b{fill:#ff5f4c;opacity:0.304;}.c{fill:#a74d4b;opacity:0.708;}.d{fill:url(#a);}.e{fill:url(#b);}.g{fill:#2a23f5;stroke:#db4646;stroke-linecap:square;stroke-width:3px;stroke-dasharray:9
10;}.h{stroke:none;}.i{fill:none;}
</style>
<radialGradient id="a" cx="0.21" cy="0.134" r="1.274"
gradientTransform="matrix(0.849, 0.529, -0.307, 0.493, 0.073, -0.043)"
gradientUnits="objectBoundingBox">
<stop offset="0" stop-color="#ff9287" />
<stop offset="0.786" stop-color="#ff5f4c" />
<stop offset="1" stop-color="#ff5f4c" />
</radialGradient>
<radialGradient id="b" cx="0.5" cy="0.5" r="0.5" gradientUnits="objectBoundingBox">
<stop offset="0" stop-color="#e75545" />
<stop offset="0.793" stop-color="#c4483b" />
<stop offset="1" stop-color="#983b31" />
</radialGradient>
</defs>
<g transform="translate(-956 -396)">
<rect class="a" width="136" height="136" transform="translate(956 396)" />
<g transform="translate(989.164 429.346)">
<g transform="translate(10.653 81.66)">
<ellipse class="b" cx="24.183" cy="8.497" rx="24.183" ry="8.497" />
<ellipse class="c" cx="8.497" cy="3.268" rx="8.497" ry="3.268"
transform="translate(15.687 5.229)" />
</g>
<g transform="translate(0 0)">
<path class="d"
d="M22.956,71.538q-.792-.8-1.543-1.533A36.466,36.466,0,0,1,0,36.4C0,16.3,15.6,0,34.837,0S69.673,16.3,69.673,36.4c0,15.235-8.954,28.283-21.664,33.711q-.588.673-1.219,1.424A73.582,73.582,0,0,0,35.337,90.157S30.335,78.981,22.956,71.538Z"
transform="translate(0 0)" />
<circle class="e" cx="27.451" cy="27.451" r="27.451"
transform="translate(7.029 7.568)" />
</g>
</g>
<g transform="translate(10096 7643)">
<circle class="f" cx="28" cy="28" r="28" transform="translate(-9100 -7207)" />
<g class="g" transform="translate(-9096 -7203)">
<circle class="h" cx="24" cy="24" r="24" />
<circle class="i" cx="24" cy="24" r="25.5" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1 +1,24 @@
<svg xmlns="http://www.w3.org/2000/svg" width="56" height="74.999" viewBox="0 0 56 74.999"><defs><style>.a{fill:#fff;opacity:0;}.b{fill:#fad950;}.c,.d{fill:#0b1923;}.c{stroke:#0b1923;stroke-width:0.5px;}.e,.f{stroke:none;}.f{fill:#0b1923;}</style></defs><g transform="translate(1401 -1261.001) rotate(90)"><rect class="a" width="56" height="56" transform="translate(1280 1345)"/><g transform="translate(0 -2)"><g class="b" transform="translate(1280 1349)"><path class="e" d="M 52.55363845825195 47.5 L 3.446360111236572 47.5 C 3.195830106735229 47.5 3.067879915237427 47.34397125244141 3.0139000415802 47.25096893310547 C 2.959929943084717 47.157958984375 2.887939929962158 46.96945190429688 3.012239933013916 46.75191879272461 L 27.56587028503418 3.783060550689697 C 27.69112968444824 3.563860416412354 27.89163017272949 3.53113055229187 28 3.53113055229187 C 28.10836029052734 3.53113055229187 28.30886077880859 3.563860416412354 28.43411064147949 3.783050537109375 L 52.98777008056641 46.75193023681641 C 53.112060546875 46.96945190429688 53.04006958007812 47.157958984375 52.98609924316406 47.25096893310547 C 52.93212127685547 47.34397125244141 52.80416870117188 47.5 52.55363845825195 47.5 Z"/><path class="f" d="M 27.99999618530273 6.046699523925781 L 5.169540405273438 46 L 50.83046340942383 46 L 27.99999618530273 6.046699523925781 M 27.99999809265137 2.0311279296875 C 28.67629432678223 2.0311279296875 29.35259056091309 2.367034912109375 29.73648071289062 3.038848876953125 L 54.29013061523438 46.00772094726562 C 55.05202102661133 47.34104156494141 54.08929061889648 49 52.55363845825195 49 L 3.446361541748047 49 C 1.910709381103516 49 0.9479789733886719 47.34104156494141 1.709869384765625 46.00772094726562 L 26.26350975036621 3.038848876953125 C 26.64740562438965 2.367034912109375 27.32370185852051 2.0311279296875 27.99999809265137 2.0311279296875 Z"/></g><path class="c" d="M44.849,49.162a.812.812,0,0,0,.794-.794V46.779H48.2a4.526,4.526,0,0,0,3.462-1.419,5.191,5.191,0,0,0,1.248-3.178,2.467,2.467,0,0,0,2.213-2.667c-.113-3.235-3.235-4.483-5.221-4.483H40.309a5.77,5.77,0,0,0-5.278,5.618v1.475a1.138,1.138,0,0,0,1.135,1.135h.34c.113,2.043,1.305,3.518,2.951,3.518h1.873v1.589a.812.812,0,0,0,.794.794h.908v.624a2.519,2.519,0,0,0,2.5,2.5h.738v1.362a1.5,1.5,0,0,0,1.475,1.475H50.41a1.5,1.5,0,0,0,1.475-1.475V50.127a1.5,1.5,0,0,0-1.475-1.475H47.743a1.5,1.5,0,0,0-1.475,1.475v1.362H45.53a1.707,1.707,0,0,1-1.7-1.7v-.624Zm2.213,4.483V52.283c1.873,0,1.873-.794,0-.794ZM37.3,43.2h6.242a2.894,2.894,0,0,0,1.759-.624,2.984,2.984,0,0,0,1.021,1.589,3.224,3.224,0,0,0,2.1.794h.4c1.532-.284,2.44-1.589,2.44-3.575a4,4,0,0,0-1.816-3.745,6.605,6.605,0,0,1,.851-.34.413.413,0,1,0-.227-.794,3.922,3.922,0,0,0-1.532.794l-.057.057a6.481,6.481,0,0,0-1.532,2.1c-.738,1.419-2.1,2.951-3.4,2.951H36.167a.366.366,0,0,1-.34-.34V40.593a4.919,4.919,0,0,1,4.483-4.824H49.9c1.135,0,4.313.681,4.426,3.689a1.7,1.7,0,0,1-1.419,1.873,6.868,6.868,0,0,0-.057-1.078.4.4,0,1,0-.794.113,5.661,5.661,0,0,1-1.021,4.426,3.6,3.6,0,0,1-2.894,1.192H39.458C38.266,45.984,37.415,44.849,37.3,43.2Zm4.824,3.575h2.667v1.589H42.125Z" transform="translate(1262.925 1337.469)"/></g><path class="d" d="M69.876,257.508H31.287a2.233,2.233,0,1,1,0-4.466H69.876a2.233,2.233,0,1,1,0,4.466Zm1.217-.951-9.7-8.471a2.2,2.2,0,0,1,0-3.157,2.328,2.328,0,0,1,3.234,0l9.705,8.471a2.2,2.2,0,0,1,0,3.157A2.325,2.325,0,0,1,71.093,256.557Zm-9.7,5.908,9.7-8.471a2.328,2.328,0,0,1,3.234,0,2.2,2.2,0,0,1,0,3.157l-9.7,8.471a2.328,2.328,0,0,1-3.234,0A2.2,2.2,0,0,1,61.392,262.465Z" transform="translate(1016.726 1425) rotate(-90)"/></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="56" height="74.999" viewBox="0 0 56 74.999">
<defs>
<style>
.a{fill:#fff;opacity:0;}.b{fill:#fad950;}.c,.d{fill:#0b1923;}.c{stroke:#0b1923;stroke-width:0.5px;}.e,.f{stroke:none;}.f{fill:#0b1923;}
</style>
</defs>
<g transform="translate(1401 -1261.001) rotate(90)">
<rect class="a" width="56" height="56" transform="translate(1280 1345)" />
<g transform="translate(0 -2)">
<g class="b" transform="translate(1280 1349)">
<path class="e"
d="M 52.55363845825195 47.5 L 3.446360111236572 47.5 C 3.195830106735229 47.5 3.067879915237427 47.34397125244141 3.0139000415802 47.25096893310547 C 2.959929943084717 47.157958984375 2.887939929962158 46.96945190429688 3.012239933013916 46.75191879272461 L 27.56587028503418 3.783060550689697 C 27.69112968444824 3.563860416412354 27.89163017272949 3.53113055229187 28 3.53113055229187 C 28.10836029052734 3.53113055229187 28.30886077880859 3.563860416412354 28.43411064147949 3.783050537109375 L 52.98777008056641 46.75193023681641 C 53.112060546875 46.96945190429688 53.04006958007812 47.157958984375 52.98609924316406 47.25096893310547 C 52.93212127685547 47.34397125244141 52.80416870117188 47.5 52.55363845825195 47.5 Z" />
<path class="f"
d="M 27.99999618530273 6.046699523925781 L 5.169540405273438 46 L 50.83046340942383 46 L 27.99999618530273 6.046699523925781 M 27.99999809265137 2.0311279296875 C 28.67629432678223 2.0311279296875 29.35259056091309 2.367034912109375 29.73648071289062 3.038848876953125 L 54.29013061523438 46.00772094726562 C 55.05202102661133 47.34104156494141 54.08929061889648 49 52.55363845825195 49 L 3.446361541748047 49 C 1.910709381103516 49 0.9479789733886719 47.34104156494141 1.709869384765625 46.00772094726562 L 26.26350975036621 3.038848876953125 C 26.64740562438965 2.367034912109375 27.32370185852051 2.0311279296875 27.99999809265137 2.0311279296875 Z" />
</g>
<path class="c"
d="M44.849,49.162a.812.812,0,0,0,.794-.794V46.779H48.2a4.526,4.526,0,0,0,3.462-1.419,5.191,5.191,0,0,0,1.248-3.178,2.467,2.467,0,0,0,2.213-2.667c-.113-3.235-3.235-4.483-5.221-4.483H40.309a5.77,5.77,0,0,0-5.278,5.618v1.475a1.138,1.138,0,0,0,1.135,1.135h.34c.113,2.043,1.305,3.518,2.951,3.518h1.873v1.589a.812.812,0,0,0,.794.794h.908v.624a2.519,2.519,0,0,0,2.5,2.5h.738v1.362a1.5,1.5,0,0,0,1.475,1.475H50.41a1.5,1.5,0,0,0,1.475-1.475V50.127a1.5,1.5,0,0,0-1.475-1.475H47.743a1.5,1.5,0,0,0-1.475,1.475v1.362H45.53a1.707,1.707,0,0,1-1.7-1.7v-.624Zm2.213,4.483V52.283c1.873,0,1.873-.794,0-.794ZM37.3,43.2h6.242a2.894,2.894,0,0,0,1.759-.624,2.984,2.984,0,0,0,1.021,1.589,3.224,3.224,0,0,0,2.1.794h.4c1.532-.284,2.44-1.589,2.44-3.575a4,4,0,0,0-1.816-3.745,6.605,6.605,0,0,1,.851-.34.413.413,0,1,0-.227-.794,3.922,3.922,0,0,0-1.532.794l-.057.057a6.481,6.481,0,0,0-1.532,2.1c-.738,1.419-2.1,2.951-3.4,2.951H36.167a.366.366,0,0,1-.34-.34V40.593a4.919,4.919,0,0,1,4.483-4.824H49.9c1.135,0,4.313.681,4.426,3.689a1.7,1.7,0,0,1-1.419,1.873,6.868,6.868,0,0,0-.057-1.078.4.4,0,1,0-.794.113,5.661,5.661,0,0,1-1.021,4.426,3.6,3.6,0,0,1-2.894,1.192H39.458C38.266,45.984,37.415,44.849,37.3,43.2Zm4.824,3.575h2.667v1.589H42.125Z"
transform="translate(1262.925 1337.469)" />
</g>
<path class="d"
d="M69.876,257.508H31.287a2.233,2.233,0,1,1,0-4.466H69.876a2.233,2.233,0,1,1,0,4.466Zm1.217-.951-9.7-8.471a2.2,2.2,0,0,1,0-3.157,2.328,2.328,0,0,1,3.234,0l9.705,8.471a2.2,2.2,0,0,1,0,3.157A2.325,2.325,0,0,1,71.093,256.557Zm-9.7,5.908,9.7-8.471a2.328,2.328,0,0,1,3.234,0,2.2,2.2,0,0,1,0,3.157l-9.7,8.471a2.328,2.328,0,0,1-3.234,0A2.2,2.2,0,0,1,61.392,262.465Z"
transform="translate(1016.726 1425) rotate(-90)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -46,4 +46,10 @@ public interface INiLocationDao {
@Query("SELECT * FROM niLocation")
List<NiLocation> findAll();
@Query("SELECT * FROM niLocation where time>=:startTime and time<=:endTime and taskId=:taskId")
List<NiLocation> taskIdAndTimeTofindList(String taskId,long startTime,long endTime);
@Query("SELECT * FROM niLocation where taskId =:taskId")
List<NiLocation> findToTaskIdAll(String taskId);
}

View File

@ -14,7 +14,7 @@ import java.util.UUID;
* @Date 2022/4/14
* @Description: ${TODO}(数据基类)
*/
public class Feature implements Serializable, Cloneable {
public class Feature extends Object implements Serializable, Cloneable {
// //主键
// @PrimaryKey(autoGenerate = true)
// public int rowId;

View File

@ -1,8 +1,13 @@
package com.navinfo.collect.library.data.entity
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
open class HadLinkDvoBean @JvmOverloads constructor(
/**
* 任务id方便捕捉查询
*/
var taskId: Int = 0,
/**
* 图幅号
*/
@ -10,6 +15,7 @@ open class HadLinkDvoBean @JvmOverloads constructor(
/**
* linkPid
*/
@PrimaryKey
var linkPid: String = "",
/**
* (几何)加偏后
@ -19,6 +25,18 @@ open class HadLinkDvoBean @JvmOverloads constructor(
/**
* 不作业原因
*/
var reason: String = ""
var reason: String = "",
/**
* 1:源库link2选择link 3现场新增
*/
var linkStatus: Int = 1,
/**
* 详细属性
*/
var linkInfo: LinkInfoBean? = null,
/**
* 长度
*/
var length: Double = 0.000,
) : RealmObject()

View File

@ -0,0 +1,26 @@
package com.navinfo.collect.library.data.entity
import io.realm.RealmObject
/**
* 道路信息
*/
open class LinkInfoBean @JvmOverloads constructor(
/**
* 种别
*/
var kind: Int = 0,
/**
* 功能等级
*/
var functionLevel: Int = 0,
/**
* 数据的等级
*/
var dataLevel: Int = 0,
/**
* 备注信息
*/
var description: String = ""
) : RealmObject()

View File

@ -65,6 +65,10 @@ public class NiLocation extends Feature{
private String groupId;
@ColumnInfo(name = "timeStamp")
private String timeStamp;
@ColumnInfo(name = "media")
private int media;
@ColumnInfo(name = "taskId")
private String taskId;
private boolean isAccouracy;
private boolean isSpeed;
@ -318,4 +322,20 @@ public class NiLocation extends Feature{
public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp;
}
public int getMedia() {
return media;
}
public void setMedia(int media) {
this.media = media;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
}

Some files were not shown because too many files have changed in this diff Show More