Merge branch 'master' of https://gitlab.navinfo.com/CollectVehicle/OneMapQS
This commit is contained in:
commit
f96292b686
@ -35,7 +35,7 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
jvmTarget = '11'
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
@ -91,7 +91,6 @@ dependencies {
|
||||
|
||||
// 读取spatialite文件
|
||||
implementation 'com.github.sevar83:android-spatialite:2.0.1'
|
||||
|
||||
}
|
||||
//允许引用生成的代码
|
||||
kapt {
|
||||
|
@ -16,7 +16,6 @@ class OMQSApplication : Application() {
|
||||
Util.getInstance().init(applicationContext)
|
||||
NetUtils.getInstance().init(this)
|
||||
TakePhotoManager.getInstance().init(this, 1)
|
||||
FileManager.initRootDir(this)
|
||||
}
|
||||
|
||||
private fun getKey(inputString: String): String {
|
||||
|
@ -5,6 +5,7 @@ import com.navinfo.omqs.Constant
|
||||
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.Ignore
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import io.realm.annotations.RealmClass
|
||||
|
||||
@ -55,9 +56,11 @@ open class TaskBean @JvmOverloads constructor(
|
||||
/**
|
||||
* 当前下载状态
|
||||
*/
|
||||
var status: Int = FileDownloadStatus.NONE
|
||||
) : RealmObject(){
|
||||
fun getDownLoadUrl():String{
|
||||
var status: Int = FileDownloadStatus.NONE,
|
||||
@Ignore
|
||||
var message: String = ""
|
||||
) : RealmObject() {
|
||||
fun getDownLoadUrl(): String {
|
||||
return "${Constant.SERVER_ADDRESS}devcp/download?fileStr=26"
|
||||
}
|
||||
}
|
@ -30,13 +30,24 @@ import kotlin.streams.toList
|
||||
/**
|
||||
* 导入omdb数据的帮助类
|
||||
* */
|
||||
class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val context: Context,@Assisted("omdbFile") val omdbFile: File) {
|
||||
class ImportOMDBHelper @AssistedInject constructor(
|
||||
@Assisted("context") val context: Context,
|
||||
@Assisted("omdbFile") val omdbFile: File
|
||||
) {
|
||||
@Inject
|
||||
lateinit var omdbHiltFactory: OMDBDataBaseHiltFactory
|
||||
|
||||
@Inject
|
||||
lateinit var gson: Gson
|
||||
private val database by lazy { omdbHiltFactory.obtainOmdbDataBaseHelper(context, omdbFile.absolutePath, 1).writableDatabase }
|
||||
private val configFile: File = File("${Constant.USER_DATA_PATH}", Constant.OMDB_CONFIG)
|
||||
private val database by lazy {
|
||||
omdbHiltFactory.obtainOmdbDataBaseHelper(
|
||||
context,
|
||||
omdbFile.absolutePath,
|
||||
1
|
||||
).writableDatabase
|
||||
}
|
||||
private val configFile: File =
|
||||
File("${Constant.DATA_PATH}/${Constant.CURRENT_USER_ID}", Constant.OMDB_CONFIG)
|
||||
|
||||
/**
|
||||
* 读取config的配置文件
|
||||
@ -67,8 +78,10 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
|
||||
}
|
||||
}.toList()
|
||||
|
||||
val cursor = database.query(table, finalColumns.toTypedArray(), "1=1",
|
||||
mutableListOf<String>().toTypedArray(), null, null, null, null)
|
||||
val cursor = database.query(
|
||||
table, finalColumns.toTypedArray(), "1=1",
|
||||
mutableListOf<String>().toTypedArray(), null, null, null, null
|
||||
)
|
||||
with(cursor) {
|
||||
if (moveToFirst()) {
|
||||
while (moveToNext()) {
|
||||
@ -76,13 +89,17 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
|
||||
for (columnIndex in 0 until columnCount) {
|
||||
var columnName = getColumnName(columnIndex)
|
||||
if (columnName.startsWith("ST_AsText(")) {
|
||||
columnName = columnName.replace("ST_AsText(", "").substringBeforeLast(")")
|
||||
columnName = columnName.replace("ST_AsText(", "")
|
||||
.substringBeforeLast(")")
|
||||
}
|
||||
when(getType(columnIndex)) {
|
||||
when (getType(columnIndex)) {
|
||||
FIELD_TYPE_NULL -> rowMap[columnName] = ""
|
||||
FIELD_TYPE_INTEGER -> rowMap[columnName] = getInt(columnIndex)
|
||||
FIELD_TYPE_FLOAT -> rowMap[columnName] = getFloat(columnIndex)
|
||||
FIELD_TYPE_BLOB -> rowMap[columnName] = String(getBlob(columnIndex), Charsets.UTF_8)
|
||||
FIELD_TYPE_INTEGER -> rowMap[columnName] =
|
||||
getInt(columnIndex)
|
||||
FIELD_TYPE_FLOAT -> rowMap[columnName] =
|
||||
getFloat(columnIndex)
|
||||
FIELD_TYPE_BLOB -> rowMap[columnName] =
|
||||
String(getBlob(columnIndex), Charsets.UTF_8)
|
||||
else -> rowMap[columnName] = getString(columnIndex)
|
||||
}
|
||||
}
|
||||
@ -104,54 +121,60 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
|
||||
suspend fun importOmdbZipFile(omdbZipFile: File): Flow<String> = withContext(Dispatchers.IO) {
|
||||
val importConfig = openConfigFile()
|
||||
val unZipFolder = File(omdbZipFile.parentFile, "result")
|
||||
flow<String> {
|
||||
flow {
|
||||
if (unZipFolder.exists()) {
|
||||
unZipFolder.deleteRecursively()
|
||||
}
|
||||
unZipFolder.mkdirs()
|
||||
// 开始解压zip文件
|
||||
val unZipFiles = ZipUtils.unzipFile(omdbZipFile, unZipFolder)
|
||||
// 将listResult数据插入到Realm数据库中
|
||||
Realm.getDefaultInstance().beginTransaction()
|
||||
// 遍历解压后的文件,读取该数据返回
|
||||
for ((index, currentConfig) in importConfig.tables.withIndex()) {
|
||||
val txtFile = unZipFiles.find {
|
||||
it.name == currentConfig.table
|
||||
}
|
||||
|
||||
val listResult: MutableList<Map<String, Any>> = mutableListOf()
|
||||
val listResult = mutableListOf<Map<String, Any?>>()
|
||||
currentConfig?.let {
|
||||
val list = FileIOUtils.readFile2List(txtFile, "UTF-8")
|
||||
if (list!=null) {
|
||||
if (list != null) {
|
||||
// 将list数据转换为map
|
||||
for (line in list) {
|
||||
val map = gson.fromJson<Map<String, Any>>(line, object : TypeToken<MutableMap<String, Any>>() {}.type)
|
||||
val map = gson.fromJson<Map<String, Any?>>(line, object:TypeToken<Map<String, Any?>>(){}.getType())
|
||||
.toMutableMap()
|
||||
map["QItable"] = currentConfig.table
|
||||
map["QIname"] = currentConfig.name
|
||||
map["QIcode"] = currentConfig.code
|
||||
map["qi_table"] = currentConfig.table
|
||||
map["qi_name"] = currentConfig.name
|
||||
map["qi_code"] = currentConfig.code
|
||||
listResult.add(map)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 将listResult数据插入到Realm数据库中
|
||||
Realm.getDefaultInstance().beginTransaction()
|
||||
for (map in listResult) { // 每一个map就是Realm的一条数据
|
||||
// 先查询这个mesh下有没有数据,如果有则跳过即可
|
||||
// val meshEntity = Realm.getDefaultInstance().where(RenderEntity::class.java).equalTo("properties['mesh']", map["mesh"].toString()).findFirst()
|
||||
val renderEntity = RenderEntity()
|
||||
renderEntity.code = map["QIcode"].toString().toInt()
|
||||
renderEntity.name = map["QIname"].toString()
|
||||
renderEntity.table = map["QItable"].toString()
|
||||
renderEntity.code = map["qi_code"].toString().toInt()
|
||||
renderEntity.name = map["qi_name"].toString()
|
||||
renderEntity.table = map["qi_table"].toString()
|
||||
// 其他数据插入到Properties中
|
||||
renderEntity.geometry = map["geometry"].toString()
|
||||
for (entry in map) {
|
||||
renderEntity.properties[entry.key] = entry.value.toString()
|
||||
for ((key, value) in map) {
|
||||
when (value) {
|
||||
is String -> renderEntity.properties[key.toString()] = value
|
||||
is Int -> renderEntity.properties[key.toString()] = value.toInt().toString()
|
||||
is Double -> renderEntity.properties[key.toString()] = value.toDouble().toString()
|
||||
else -> renderEntity.properties[key.toString()] = value.toString()
|
||||
}
|
||||
}
|
||||
Realm.getDefaultInstance().insert(renderEntity)
|
||||
}
|
||||
Realm.getDefaultInstance().commitTransaction()
|
||||
// 1个文件发送一次flow流
|
||||
emit("${index+1}/${importConfig.tables.size}")
|
||||
emit("${index + 1}/${importConfig.tables.size}")
|
||||
}
|
||||
Realm.getDefaultInstance().commitTransaction()
|
||||
emit("OK")
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,7 +183,15 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
|
||||
val columns = mutableListOf<String>()
|
||||
|
||||
// 查询 sqlite_master 表获取指定数据表的元数据信息
|
||||
val cursor = db.query("sqlite_master", arrayOf("sql"), "type='table' AND name=?", arrayOf(tableName), null, null, null)
|
||||
val cursor = db.query(
|
||||
"sqlite_master",
|
||||
arrayOf("sql"),
|
||||
"type='table' AND name=?",
|
||||
arrayOf(tableName),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
// 从元数据信息中解析出列名
|
||||
if (cursor.moveToFirst()) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.navinfo.omqs.db
|
||||
|
||||
import com.navinfo.collect.library.data.entity.QsRecordBean
|
||||
import com.navinfo.omqs.bean.HadLinkDvoBean
|
||||
import com.navinfo.omqs.bean.TaskBean
|
||||
import io.realm.annotations.RealmModule
|
||||
|
||||
@io.realm.annotations.RealmModule(classes = [TaskBean::class, HadLinkDvoBean::class])
|
||||
@RealmModule(classes = [TaskBean::class, HadLinkDvoBean::class])
|
||||
class MyRealmModule {
|
||||
}
|
66
app/src/main/java/com/navinfo/omqs/hilt/ActivityModule.kt
Normal file
66
app/src/main/java/com/navinfo/omqs/hilt/ActivityModule.kt
Normal file
@ -0,0 +1,66 @@
|
||||
package com.navinfo.omqs.hilt
|
||||
|
||||
import android.content.Context
|
||||
import com.navinfo.collect.library.map.NIMapController
|
||||
import com.navinfo.omqs.db.RealmOperateHelper
|
||||
import com.navinfo.omqs.db.RoomAppDatabase
|
||||
import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
|
||||
import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager
|
||||
import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ActivityRetainedComponent
|
||||
import dagger.hilt.android.qualifiers.ActivityContext
|
||||
import dagger.hilt.android.scopes.ActivityRetainedScoped
|
||||
|
||||
@InstallIn(ActivityRetainedComponent::class)
|
||||
@Module
|
||||
class ActivityModule {
|
||||
|
||||
/**
|
||||
* 注入地图控制器,在activity范围内使用,单例
|
||||
*/
|
||||
@ActivityRetainedScoped
|
||||
@Provides
|
||||
fun providesMapController(): NIMapController = NIMapController()
|
||||
|
||||
/**
|
||||
* 注入离线地图下载管理,在activity范围内使用,单例
|
||||
*/
|
||||
@ActivityRetainedScoped
|
||||
@Provides
|
||||
fun providesOfflineMapDownloadManager(
|
||||
networkServiceAPI: RetrofitNetworkServiceAPI,
|
||||
roomAppDatabase: RoomAppDatabase,
|
||||
mapController: NIMapController
|
||||
): OfflineMapDownloadManager =
|
||||
OfflineMapDownloadManager(networkServiceAPI, roomAppDatabase, mapController)
|
||||
|
||||
/**
|
||||
* 注入任务下载
|
||||
*/
|
||||
@ActivityRetainedScoped
|
||||
@Provides
|
||||
fun providesTaskListDownloadManager(
|
||||
networkServiceAPI: RetrofitNetworkServiceAPI,
|
||||
importFactory: ImportOMDBHiltFactory,
|
||||
): TaskDownloadManager =
|
||||
TaskDownloadManager(importFactory, networkServiceAPI)
|
||||
|
||||
/**
|
||||
* 实验失败,这样创建,viewmodel不会在activity销毁的时候同时销毁
|
||||
* 4-14:因为没有传入activity的 owner,无法检测生命周期,
|
||||
*/
|
||||
// @ActivityRetainedScoped
|
||||
// @Provides
|
||||
// fun providesMainViewModel(mapController: NIMapController): MainViewModel {
|
||||
// return MainViewModel(mapController)
|
||||
// }
|
||||
|
||||
@ActivityRetainedScoped
|
||||
@Provides
|
||||
fun providesRealmOperateHelper(): RealmOperateHelper {
|
||||
return RealmOperateHelper()
|
||||
}
|
||||
}
|
@ -1,20 +1,23 @@
|
||||
package com.navinfo.omqs.hilt
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.room.Room
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.navinfo.omqs.Constant
|
||||
import com.navinfo.omqs.OMQSApplication
|
||||
import com.navinfo.omqs.db.RoomAppDatabase
|
||||
import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
|
||||
import com.navinfo.omqs.tools.IntTypeAdapter
|
||||
import com.tencent.wcdb.database.SQLiteCipherSpec
|
||||
import com.tencent.wcdb.room.db.WCDBOpenHelperFactory
|
||||
import dagger.Lazy
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import io.realm.Realm
|
||||
import kotlinx.coroutines.*
|
||||
@ -34,7 +37,7 @@ class GlobalModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideApplication(application: Application): OMQSApplication {
|
||||
fun provideApplication(@ApplicationContext application: Application): OMQSApplication {
|
||||
return application as OMQSApplication
|
||||
}
|
||||
|
||||
@ -86,7 +89,12 @@ class GlobalModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGson(): Gson = Gson()
|
||||
fun provideGson(): Gson = GsonBuilder()
|
||||
// 解决解析Json时将int类型自动转换为Double的问题
|
||||
.registerTypeAdapter(object : TypeToken<Map<String, Any?>>() {}.getType(), IntTypeAdapter())
|
||||
.registerTypeAdapter(object : TypeToken<Map<String, Any>>() {}.getType(), IntTypeAdapter())
|
||||
.registerTypeAdapter(object : TypeToken<Map<Any, Any>>() {}.getType(), IntTypeAdapter())
|
||||
.create()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
|
@ -1,63 +1,21 @@
|
||||
package com.navinfo.omqs.hilt
|
||||
|
||||
import android.content.Context
|
||||
import com.navinfo.collect.library.map.NIMapController
|
||||
import com.navinfo.omqs.db.RealmOperateHelper
|
||||
import com.navinfo.omqs.db.RoomAppDatabase
|
||||
import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
|
||||
import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager
|
||||
import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ActivityRetainedComponent
|
||||
import dagger.hilt.android.scopes.ActivityRetainedScoped
|
||||
import dagger.hilt.android.components.ActivityComponent
|
||||
import dagger.hilt.android.qualifiers.ActivityContext
|
||||
import dagger.hilt.android.scopes.ActivityScoped
|
||||
|
||||
@InstallIn(ActivityRetainedComponent::class)
|
||||
@InstallIn(ActivityComponent::class)
|
||||
@Module
|
||||
class MainActivityModule {
|
||||
|
||||
/**
|
||||
* 注入地图控制器,在activity范围内使用,单例
|
||||
*/
|
||||
@ActivityRetainedScoped
|
||||
@ActivityScoped
|
||||
@Provides
|
||||
fun providesMapController(): NIMapController = NIMapController()
|
||||
|
||||
/**
|
||||
* 注入离线地图下载管理,在activity范围内使用,单例
|
||||
*/
|
||||
@ActivityRetainedScoped
|
||||
@Provides
|
||||
fun providesOfflineMapDownloadManager(
|
||||
networkServiceAPI: RetrofitNetworkServiceAPI,
|
||||
roomAppDatabase: RoomAppDatabase,
|
||||
mapController: NIMapController
|
||||
): OfflineMapDownloadManager =
|
||||
OfflineMapDownloadManager(networkServiceAPI, roomAppDatabase, mapController)
|
||||
|
||||
/**
|
||||
* 注入任务下载
|
||||
*/
|
||||
@ActivityRetainedScoped
|
||||
@Provides
|
||||
fun providesTaskListDownloadManager(
|
||||
networkServiceAPI: RetrofitNetworkServiceAPI,
|
||||
): TaskDownloadManager =
|
||||
TaskDownloadManager(networkServiceAPI)
|
||||
|
||||
/**
|
||||
* 实验失败,这样创建,viewmodel不会在activity销毁的时候同时销毁
|
||||
* 4-14:因为没有传入activity的 owner,无法检测生命周期,
|
||||
*/
|
||||
// @ActivityRetainedScoped
|
||||
// @Provides
|
||||
// fun providesMainViewModel(mapController: NIMapController): MainViewModel {
|
||||
// return MainViewModel(mapController)
|
||||
// }
|
||||
|
||||
@ActivityRetainedScoped
|
||||
@Provides
|
||||
fun providesRealmOperateHelper(): RealmOperateHelper {
|
||||
return RealmOperateHelper()
|
||||
}
|
||||
fun providesContext(@ActivityContext context: Context): Context = context
|
||||
}
|
7
app/src/main/java/com/navinfo/omqs/hilt/Qualifiers.kt
Normal file
7
app/src/main/java/com/navinfo/omqs/hilt/Qualifiers.kt
Normal file
@ -0,0 +1,7 @@
|
||||
//package com.navinfo.omqs.hilt
|
||||
//
|
||||
//import javax.inject.Qualifier
|
||||
//
|
||||
//@Qualifier
|
||||
//@Retention(AnnotationRetention.RUNTIME)
|
||||
//annotation class ActivityContext
|
@ -1,23 +1,32 @@
|
||||
package com.navinfo.omqs.http.taskdownload
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.Observer
|
||||
import com.navinfo.omqs.bean.TaskBean
|
||||
import com.navinfo.omqs.hilt.ImportOMDBHiltFactory
|
||||
import com.navinfo.omqs.hilt.OMDBDataBaseHiltFactory
|
||||
import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
|
||||
import dagger.hilt.android.qualifiers.ActivityContext
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
/**
|
||||
* 管理任务数据下载
|
||||
*/
|
||||
|
||||
class TaskDownloadManager(
|
||||
class TaskDownloadManager constructor(
|
||||
val importFactory: ImportOMDBHiltFactory,
|
||||
val netApi: RetrofitNetworkServiceAPI,
|
||||
) {
|
||||
|
||||
lateinit var context: Context
|
||||
|
||||
/**
|
||||
* 最多同时下载数量
|
||||
*/
|
||||
private val MAX_SCOPE = 3
|
||||
private val MAX_SCOPE = 1
|
||||
|
||||
/**
|
||||
* 存储有哪些城市需要下载的队列
|
||||
@ -33,6 +42,9 @@ class TaskDownloadManager(
|
||||
ConcurrentHashMap<Int, TaskDownloadScope>()
|
||||
}
|
||||
|
||||
fun init(context: Context) {
|
||||
this.context = context
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动下载任务
|
||||
@ -92,7 +104,7 @@ class TaskDownloadManager(
|
||||
|
||||
fun addTask(taskBean: TaskBean) {
|
||||
if (!scopeMap.containsKey(taskBean.id)) {
|
||||
scopeMap[taskBean.id] = TaskDownloadScope(this, taskBean)
|
||||
scopeMap[taskBean.id] = TaskDownloadScope( this, taskBean)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,34 @@
|
||||
package com.navinfo.omqs.http.taskdownload
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.core.content.ContentProviderCompat.requireContext
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import com.navinfo.omqs.Constant
|
||||
import com.navinfo.omqs.bean.TaskBean
|
||||
import com.navinfo.omqs.db.ImportOMDBHelper
|
||||
import com.navinfo.omqs.hilt.ImportOMDBHiltFactory
|
||||
import com.navinfo.omqs.tools.FileManager
|
||||
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
|
||||
import io.realm.Realm
|
||||
import kotlinx.coroutines.*
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.RandomAccessFile
|
||||
import javax.inject.Inject
|
||||
|
||||
class TaskDownloadScope(
|
||||
private val downloadManager: TaskDownloadManager,
|
||||
val taskBean: TaskBean,
|
||||
) :
|
||||
CoroutineScope by CoroutineScope(Dispatchers.IO + CoroutineName("OfflineMapDownLoad")) {
|
||||
|
||||
@Inject
|
||||
lateinit var importOMDBHiltFactory: ImportOMDBHiltFactory
|
||||
|
||||
/**
|
||||
*下载任务,用来取消的
|
||||
*/
|
||||
@ -59,7 +70,12 @@ class TaskDownloadScope(
|
||||
*/
|
||||
fun launch() {
|
||||
downloadJob = launch() {
|
||||
download()
|
||||
FileManager.checkOMDBFileInfo(taskBean)
|
||||
if (taskBean.status == FileDownloadStatus.IMPORT) {
|
||||
importData()
|
||||
} else {
|
||||
download()
|
||||
}
|
||||
downloadManager.launchNext(taskBean.id)
|
||||
}
|
||||
}
|
||||
@ -76,14 +92,17 @@ class TaskDownloadScope(
|
||||
* 更新任务
|
||||
* @param status [OfflineMapCityBean.Status]
|
||||
*/
|
||||
private fun change(status: Int) {
|
||||
if (taskBean.status != status || status == FileDownloadStatus.LOADING) {
|
||||
private fun change(status: Int, message: String = "") {
|
||||
if (taskBean.status != status || status == FileDownloadStatus.LOADING || status == FileDownloadStatus.IMPORTING) {
|
||||
taskBean.status = status
|
||||
taskBean.message = message
|
||||
downloadData.postValue(taskBean)
|
||||
launch(Dispatchers.IO) {
|
||||
// downloadManager.roomDatabase.getOfflineMapDao().update(taskBean)
|
||||
launch {
|
||||
val realm = Realm.getDefaultInstance()
|
||||
realm.executeTransaction {
|
||||
it.copyToRealmOrUpdate(taskBean)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,36 +115,75 @@ class TaskDownloadScope(
|
||||
downloadData.observe(owner, ob)
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入数据
|
||||
*/
|
||||
private suspend fun importData(file: File? = null) {
|
||||
try {
|
||||
Log.e("jingo", "importData SSS")
|
||||
change(FileDownloadStatus.IMPORTING)
|
||||
var fileNew = file
|
||||
?: File("${Constant.DOWNLOAD_PATH}${taskBean.evaluationTaskName}_${taskBean.dataVersion}.zip")
|
||||
val importOMDBHelper: ImportOMDBHelper =
|
||||
downloadManager.importFactory.obtainImportOMDBHelper(
|
||||
downloadManager.context,
|
||||
fileNew
|
||||
)
|
||||
importOMDBHelper.importOmdbZipFile(importOMDBHelper.omdbFile).collect {
|
||||
Log.e("jingo", "数据安装 $it")
|
||||
if (it == "OK") {
|
||||
change(FileDownloadStatus.DONE)
|
||||
} else {
|
||||
change(FileDownloadStatus.IMPORTING, it)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("jingo", "数据安装失败 ${e.toString()}")
|
||||
change(FileDownloadStatus.ERROR)
|
||||
}
|
||||
|
||||
Log.e("jingo", "importData EEE")
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*/
|
||||
private suspend fun download() {
|
||||
//如果文件下载安装已经完毕
|
||||
if (taskBean.status == FileDownloadStatus.DONE) {
|
||||
return
|
||||
}
|
||||
var inputStream: InputStream? = null
|
||||
var randomAccessFile: RandomAccessFile? = null
|
||||
try {
|
||||
//创建离线地图 下载文件夹,.map文件夹的下一级
|
||||
val fileDir = File("${Constant.DOWNLOAD_PATH}download")
|
||||
val fileDir = File("${Constant.DOWNLOAD_PATH}")
|
||||
if (!fileDir.exists()) {
|
||||
fileDir.mkdirs()
|
||||
}
|
||||
|
||||
val fileTemp =
|
||||
File("${Constant.DOWNLOAD_PATH}${taskBean.id}_${taskBean.dataVersion}")
|
||||
File("${Constant.DOWNLOAD_PATH}${taskBean.evaluationTaskName}_${taskBean.dataVersion}.zip")
|
||||
val startPosition = taskBean.currentSize
|
||||
//验证断点有效性
|
||||
if (startPosition < 0) throw IOException("jingo Start position less than zero")
|
||||
|
||||
if (fileTemp.length() > 0 && taskBean.fileSize > 0 && fileTemp.length() == taskBean.fileSize) {
|
||||
importData(fileTemp)
|
||||
return
|
||||
}
|
||||
|
||||
val response = downloadManager.netApi.retrofitDownLoadFile(
|
||||
start = "bytes=$startPosition-",
|
||||
url = taskBean.getDownLoadUrl()
|
||||
)
|
||||
val responseBody = response.body()
|
||||
|
||||
change(FileDownloadStatus.LOADING)
|
||||
responseBody ?: throw IOException("jingo ResponseBody is null")
|
||||
|
||||
responseBody ?: throw IOException("jingo ResponseBody is null")
|
||||
if (startPosition == 0L) {
|
||||
taskBean.fileSize = responseBody.contentLength()
|
||||
Log.e("jingo", "当前文件大小 ${taskBean.fileSize}")
|
||||
}
|
||||
change(FileDownloadStatus.LOADING)
|
||||
//写入文件
|
||||
randomAccessFile = RandomAccessFile(fileTemp, "rwd")
|
||||
randomAccessFile.seek(startPosition)
|
||||
@ -146,17 +204,14 @@ class TaskDownloadScope(
|
||||
}
|
||||
}
|
||||
|
||||
Log.e("jingo", "文件下载完成 ${taskBean.currentSize} == ${taskBean.fileSize}")
|
||||
if (taskBean.currentSize == taskBean.fileSize) {
|
||||
val res =
|
||||
fileTemp.renameTo(File("${Constant.DOWNLOAD_PATH}${taskBean.evaluationTaskName}.zip"))
|
||||
Log.e("jingo", "文件下载完成 修改文件 $res")
|
||||
change(FileDownloadStatus.DONE)
|
||||
importData(fileTemp)
|
||||
} else {
|
||||
change(FileDownloadStatus.PAUSE)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
change(FileDownloadStatus.ERROR)
|
||||
Log.e("jingo","数据下载出错 ${e.message}")
|
||||
} finally {
|
||||
inputStream?.close()
|
||||
randomAccessFile?.close()
|
||||
|
@ -16,8 +16,10 @@ class FileManager {
|
||||
const val LOADING = 2 //下载中
|
||||
const val PAUSE = 3 //暂停
|
||||
const val ERROR = 4 //错误
|
||||
const val DONE = 5 //完成
|
||||
const val UPDATE = 6 //有新版本要更新
|
||||
const val IMPORT = 5 //安装
|
||||
const val IMPORTING = 6 //安装中
|
||||
const val UPDATE = 7 //有新版本要更新
|
||||
const val DONE = 8 //完成
|
||||
}
|
||||
|
||||
//初始化数据文件夹
|
||||
@ -109,60 +111,28 @@ class FileManager {
|
||||
* 检查离线地图文件
|
||||
*/
|
||||
suspend fun checkOMDBFileInfo(taskBean: TaskBean) {
|
||||
if (taskBean.status == FileDownloadStatus.DONE)
|
||||
return
|
||||
//访问离线地图文件夹
|
||||
val fileDir = File("${Constant.DOWNLOAD_PATH}")
|
||||
//如果连本地文件夹还没有,就不用修改任何数据了
|
||||
if (!fileDir.exists()) {
|
||||
return
|
||||
}
|
||||
//访问离线地图临时下载文件夹
|
||||
val fileTempDir = File(Constant.DOWNLOAD_PATH)
|
||||
//是否有一份.map文件了
|
||||
var mapFile: File? = null
|
||||
//文件夹里文件挨个访问
|
||||
for (item in fileDir.listFiles()) {
|
||||
//先找到对应的省市文件,例如:540000_西藏自治区_20230401195018.map",以id开头
|
||||
if (item.isFile && item.name.startsWith("${taskBean.id}_")) {
|
||||
//如果本地文件与从网络获取到版本号一致,表示这个文件已经下载完毕,不用处理了
|
||||
if (item.name == "${taskBean.id}_${taskBean.dataVersion}") {
|
||||
taskBean.status = FileDownloadStatus.DONE
|
||||
return
|
||||
}
|
||||
//文件存在,版本号不对应,留给下面流程处理
|
||||
mapFile = item
|
||||
break
|
||||
}
|
||||
}
|
||||
//临时下载文件夹
|
||||
if (fileTempDir.exists()) {
|
||||
for (item in fileTempDir.listFiles()) {
|
||||
//先找到对应的省市文件,例如:540000_20230401195018",以id开头
|
||||
if (item.isFile && item.name.startsWith("${taskBean.id}_")) {
|
||||
//如果本地文件与从网络获取到版本号一致,表示这个文件已经在下载列表中
|
||||
if (item.name == "${taskBean.id}_${taskBean.dataVersion}") {
|
||||
//如果这个临时文件的大小和下载大小是一致的,说明已经下载完了,但是在下载环节没有更名移动成功,需要重命名和移动文件夹
|
||||
if (item.length() == taskBean.fileSize) {
|
||||
//移动更名文件后删除旧数据,修改状态
|
||||
if (item.renameTo(File("${Constant.OFFLINE_MAP_PATH}${taskBean.evaluationTaskName}.zip"))) {
|
||||
//删除旧版本数据
|
||||
mapFile?.delete()
|
||||
taskBean.status = FileDownloadStatus.DONE
|
||||
return
|
||||
}
|
||||
} else { // 临时文件大小和目标不一致,说明下载了一半
|
||||
taskBean.status = FileDownloadStatus.PAUSE
|
||||
taskBean.currentSize = item.length()
|
||||
return
|
||||
}
|
||||
} else { //虽然省市id开头一致,但是版本号不一致,说明之前版本下载了一部分,现在要更新了,原来下载的文件直接删除
|
||||
taskBean.status = FileDownloadStatus.UPDATE
|
||||
item.delete()
|
||||
return
|
||||
}
|
||||
break
|
||||
if (item.isFile && item.name == "${taskBean.evaluationTaskName}_${taskBean.dataVersion}.zip") {
|
||||
taskBean.currentSize = item.length()
|
||||
if (taskBean.fileSize > 0 && taskBean.fileSize == item.length()) {
|
||||
taskBean.status = FileDownloadStatus.IMPORT
|
||||
} else {
|
||||
taskBean.status = FileDownloadStatus.PAUSE
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
taskBean.status = FileDownloadStatus.NONE
|
||||
}
|
||||
}
|
||||
}
|
69
app/src/main/java/com/navinfo/omqs/tools/IntTypeAdapter.kt
Normal file
69
app/src/main/java/com/navinfo/omqs/tools/IntTypeAdapter.kt
Normal file
@ -0,0 +1,69 @@
|
||||
package com.navinfo.omqs.tools
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.internal.LinkedTreeMap
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonToken
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import java.io.IOException
|
||||
|
||||
class IntTypeAdapter : TypeAdapter<Any>() {
|
||||
private val delegate: TypeAdapter<Any> = Gson().getAdapter(Any::class.java)
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun read(`in`: JsonReader): Any? {
|
||||
val token = `in`.peek()
|
||||
when (token) {
|
||||
JsonToken.BEGIN_ARRAY -> {
|
||||
val list: MutableList<Any?> = ArrayList()
|
||||
`in`.beginArray()
|
||||
while (`in`.hasNext()) {
|
||||
list.add(read(`in`))
|
||||
}
|
||||
`in`.endArray()
|
||||
return list
|
||||
}
|
||||
JsonToken.BEGIN_OBJECT -> {
|
||||
val map: MutableMap<String, Any?> = LinkedTreeMap()
|
||||
`in`.beginObject()
|
||||
while (`in`.hasNext()) {
|
||||
map[`in`.nextName()] = read(`in`)
|
||||
}
|
||||
`in`.endObject()
|
||||
return map
|
||||
}
|
||||
JsonToken.STRING -> return `in`.nextString()
|
||||
JsonToken.NUMBER -> {
|
||||
// 改写数字的处理逻辑,将数字值分为整型与浮点型。
|
||||
val dbNum = `in`.nextDouble()
|
||||
// 数字超过long的最大值,返回浮点类型
|
||||
if (dbNum > Long.MAX_VALUE) {
|
||||
return dbNum
|
||||
}
|
||||
// 判断数字是否为整数值
|
||||
val lngNum = dbNum.toLong()
|
||||
return if (dbNum == lngNum.toDouble()) {
|
||||
try {
|
||||
lngNum.toInt()
|
||||
} catch (e: Exception) {
|
||||
lngNum
|
||||
}
|
||||
} else {
|
||||
dbNum
|
||||
}
|
||||
}
|
||||
JsonToken.BOOLEAN -> return `in`.nextBoolean()
|
||||
JsonToken.NULL -> {
|
||||
`in`.nextNull()
|
||||
return null
|
||||
}
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun write(out: JsonWriter, value: Any?) {
|
||||
delegate.write(out, value)
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.blankj.utilcode.util.ResourceUtils
|
||||
import com.navinfo.omqs.Constant
|
||||
import com.navinfo.omqs.bean.LoginUserBean
|
||||
import com.navinfo.omqs.db.MyRealmModule
|
||||
import com.navinfo.omqs.db.RoomAppDatabase
|
||||
import com.navinfo.omqs.http.NetResult
|
||||
import com.navinfo.omqs.http.NetworkService
|
||||
@ -159,7 +160,8 @@ class LoginViewModel @Inject constructor(
|
||||
Constant.VERSION_ID = userId
|
||||
Constant.USER_DATA_PATH = Constant.DATA_PATH + Constant.USER_ID + "/" + Constant.VERSION_ID
|
||||
// 在SD卡创建用户目录,解压资源等
|
||||
val userFolder = File("${Constant.DATA_PATH}/${userId}")
|
||||
val userFolder = File(Constant.USER_DATA_PATH)
|
||||
if (!userFolder.exists()) userFolder.mkdirs()
|
||||
// 初始化Realm
|
||||
Realm.init(context.applicationContext)
|
||||
val password = "encryp".encodeToByteArray().copyInto(ByteArray(64))
|
||||
@ -169,7 +171,7 @@ class LoginViewModel @Inject constructor(
|
||||
.directory(userFolder)
|
||||
.name("OMQS.realm")
|
||||
.encryptionKey(password)
|
||||
// .modules(Realm.getDefaultModule(), MyRealmModule())
|
||||
.modules(Realm.getDefaultModule(), MyRealmModule())
|
||||
.schemaVersion(1)
|
||||
.build()
|
||||
Realm.setDefaultConfiguration(config)
|
||||
|
@ -4,10 +4,8 @@ import android.os.Bundle
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.blankj.utilcode.util.ToastUtils
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.findNavController
|
||||
import com.blankj.utilcode.util.ToastUtils
|
||||
import com.navinfo.collect.library.map.NIMapController
|
||||
import com.navinfo.collect.library.map.handler.NiLocationListener
|
||||
import com.navinfo.omqs.Constant
|
||||
@ -34,10 +32,10 @@ class MainActivity : BaseActivity() {
|
||||
@Inject
|
||||
lateinit var offlineMapDownloadManager: OfflineMapDownloadManager
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
|
||||
//初始化地图
|
||||
mapController.init(
|
||||
|
@ -3,38 +3,24 @@ package com.navinfo.omqs.ui.fragment.personalcenter
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
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.RealmUtils
|
||||
import com.navinfo.collect.library.data.entity.OMDBEntity
|
||||
import com.navinfo.collect.library.map.NIMapController
|
||||
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.BaseActivity
|
||||
import com.navinfo.omqs.ui.fragment.BaseFragment
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmDictionary
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.oscim.core.GeoPoint
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
@ -104,13 +90,6 @@ class PersonalCenterFragment : BaseFragment(), FSAFActivityCallbacks {
|
||||
file
|
||||
)
|
||||
viewModel.importOMDBData(importOMDBHelper)
|
||||
// // 开始导入数据
|
||||
// CoroutineUtils.launchWithLoading(
|
||||
// requireContext(),
|
||||
// loadingMessage = "导入数据..."
|
||||
// ) {
|
||||
//
|
||||
// }
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -122,14 +101,13 @@ class PersonalCenterFragment : BaseFragment(), FSAFActivityCallbacks {
|
||||
|
||||
override fun onResult(uri: Uri) {
|
||||
viewModel.importScProblemData(uri)
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
R.id.personal_center_menu_test -> {
|
||||
viewModel.readRealmData()
|
||||
// 定位到指定位置
|
||||
niMapController.mMapView.vtmMap.animator().animateTo(GeoPoint(28.608398, 115.67901))
|
||||
niMapController.mMapView.vtmMap.animator().animateTo(GeoPoint(30.270367985798032, 113.83513667119433))
|
||||
}
|
||||
R.id.personal_center_menu_task_list -> {
|
||||
findNavController().navigate(R.id.TaskListFragment)
|
||||
|
@ -13,6 +13,8 @@ import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
|
||||
import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
|
||||
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
|
||||
import com.navinfo.omqs.ui.other.BaseViewHolder
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* 离线地图城市列表 RecyclerView 适配器
|
||||
@ -31,7 +33,7 @@ class TaskListAdapter(
|
||||
if (it.tag != null) {
|
||||
val taskBean = data[it.tag as Int]
|
||||
when (taskBean.status) {
|
||||
FileDownloadStatus.NONE, FileDownloadStatus.UPDATE, FileDownloadStatus.PAUSE, FileDownloadStatus.ERROR -> {
|
||||
FileDownloadStatus.NONE, FileDownloadStatus.UPDATE, FileDownloadStatus.PAUSE, FileDownloadStatus.IMPORT, FileDownloadStatus.ERROR -> {
|
||||
Log.e("jingo", "开始下载 ${taskBean.status}")
|
||||
downloadManager.start(taskBean.id)
|
||||
}
|
||||
@ -125,6 +127,29 @@ class TaskListAdapter(
|
||||
View.INVISIBLE
|
||||
binding.taskDownloadBtn.text = "更新"
|
||||
}
|
||||
FileDownloadStatus.IMPORTING -> {
|
||||
if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
|
||||
View.VISIBLE
|
||||
binding.taskDownloadBtn.text = "安装中"
|
||||
val split = taskBean.message.split("/")
|
||||
if (split.size == 2) {
|
||||
try {
|
||||
val index = split[0].toInt()
|
||||
val count = split[1].toInt()
|
||||
binding.taskProgress.progress =
|
||||
index * 100 / count
|
||||
} catch (e: Exception) {
|
||||
Log.e("jingo", "更新进度条 $e")
|
||||
}
|
||||
} else {
|
||||
binding.taskProgress.progress = 0
|
||||
}
|
||||
}
|
||||
FileDownloadStatus.IMPORT -> {
|
||||
if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
|
||||
View.INVISIBLE
|
||||
binding.taskDownloadBtn.text = "安装"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ class TaskListFragment : BaseFragment(){
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
downloadManager.init(requireContext())
|
||||
_binding = FragmentTaskListBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
|
||||
|
@ -27,12 +27,28 @@ class TaskListViewModel @Inject constructor(
|
||||
fun getTaskList(context: Context) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val realm = Realm.getDefaultInstance()
|
||||
Log.e("jingo","realm hashCOde ${realm.hashCode()}")
|
||||
Log.e("jingo", "realm hashCOde ${realm.hashCode()}")
|
||||
var taskList: List<TaskBean> = mutableListOf()
|
||||
when (val result = networkService.getTaskList("02911")) {
|
||||
is NetResult.Success -> {
|
||||
if (result.data != null) {
|
||||
realm.executeTransaction {
|
||||
realm.copyToRealmOrUpdate(result.data.obj)
|
||||
result.data.obj?.let { list ->
|
||||
for (task in list) {
|
||||
val item = realm.where(TaskBean::class.java).equalTo(
|
||||
"id", task.id
|
||||
).findFirst()
|
||||
if (item != null) {
|
||||
task.fileSize = item.fileSize
|
||||
Log.e("jingo", "当前文件大小 ${task.fileSize}")
|
||||
task.status = item.status
|
||||
task.currentSize = item.currentSize
|
||||
}
|
||||
realm.copyToRealmOrUpdate(task)
|
||||
}
|
||||
}
|
||||
val objects = realm.where(TaskBean::class.java).findAll()
|
||||
taskList = realm.copyFromRealm(objects)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -51,9 +67,8 @@ class TaskListViewModel @Inject constructor(
|
||||
is NetResult.Loading -> {}
|
||||
else -> {}
|
||||
}
|
||||
val objects = realm.where(TaskBean::class.java).findAll()
|
||||
val taskList = realm.copyFromRealm(objects)
|
||||
for(item in taskList){
|
||||
|
||||
for (item in taskList) {
|
||||
FileManager.checkOMDBFileInfo(item)
|
||||
}
|
||||
liveDataTaskList.postValue(taskList)
|
||||
|
@ -8,6 +8,7 @@
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingBottom="5dp"
|
||||
tools:context="com.navinfo.omqs.ui.fragment.tasklist.TaskListAdapter">
|
||||
|
||||
<TextView
|
||||
|
@ -38,8 +38,8 @@ android {
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
@ -1549,4 +1549,104 @@
|
||||
<symbol src="assets:symbols/dot_blue.svg" />
|
||||
</m>
|
||||
</m>
|
||||
|
||||
<m k="qi_table">
|
||||
<!-- 道路线 -->
|
||||
<m v="OMDB_RD_LINK">
|
||||
<line stroke="#9c9c9c" width="1"/>
|
||||
</m>
|
||||
<!--道路方向-->
|
||||
<m v="OMDB_RD_LINK_DIRECT">
|
||||
<m k="direct">
|
||||
<m v="2">
|
||||
<lineSymbol src="assets:omdb/oneway_left.svg"></lineSymbol>
|
||||
</m>
|
||||
<m v="3">
|
||||
<lineSymbol src="assets:omdb/oneway_right.svg"></lineSymbol>
|
||||
</m>
|
||||
</m>
|
||||
</m>
|
||||
<!--道路种别-->
|
||||
<m v="OMDB_RD_LINK_KIND">
|
||||
<m k="kind">
|
||||
<m v="1">
|
||||
<line stroke="#fcacd4" width="1"/>
|
||||
</m>
|
||||
<m v="2">
|
||||
<line stroke="#dcacfc" width="1"/>
|
||||
</m>
|
||||
<m v="3">
|
||||
<line stroke="#fc9c9c" width="1"/>
|
||||
</m>
|
||||
<m v="4">
|
||||
<line stroke="#fcd484" width="1"/>
|
||||
</m>
|
||||
<m v="5">
|
||||
<line stroke="#ecfccc" width="1"/>
|
||||
</m>
|
||||
<m v="6">
|
||||
<line stroke="#acec84" width="1"/>
|
||||
</m>
|
||||
<m v="7">
|
||||
<line stroke="#806048" width="1"/>
|
||||
</m>
|
||||
<m v="8">
|
||||
<line stroke="#fcfc7c" width="1"/>
|
||||
</m>
|
||||
<m v="9">
|
||||
<line stroke="#acc4fc" width="1"/>
|
||||
</m>
|
||||
<m v="10">
|
||||
<line stroke="#8cc8e0" width="1"/>
|
||||
</m>
|
||||
<m v="11">
|
||||
<line stroke="#64ecdc" width="1"/>
|
||||
</m>
|
||||
<m v="13">
|
||||
<line stroke="#585080" width="1"/>
|
||||
</m>
|
||||
<m v="15">
|
||||
<line stroke="#647430" width="1"/>
|
||||
</m>
|
||||
</m>
|
||||
</m>
|
||||
|
||||
<!--常规点限速-->
|
||||
<m v="OMDB_SPEEDLIMIT">
|
||||
<m k="speedFlag">
|
||||
<m v="0">
|
||||
<circle fill="#0000ff" radius="30" scale-radius="true" />
|
||||
<text k="maxSpeed" use="road"></text>
|
||||
<text k="minSpeed" dy="30" bg-fill="#00ff00" use="road"></text>
|
||||
</m>
|
||||
<m v="1">
|
||||
<!-- <circle fill="#0000ff" radius="30" scale-radius="true" />-->
|
||||
<text k="maxSpeed" use="road"></text>
|
||||
<text k="minSpeed" dy="30" bg-fill="#00ff00" use="road"></text>
|
||||
</m>
|
||||
</m>
|
||||
</m>
|
||||
<!--条件点限速-->
|
||||
<m v="OMDB_SPEEDLIMIT_COND">
|
||||
<m k="direct">
|
||||
<m v="2">
|
||||
<lineSymbol src="assets:omdb/oneway_left.svg"></lineSymbol>
|
||||
</m>
|
||||
<m v="3">
|
||||
<lineSymbol src="assets:omdb/oneway_right.svg"></lineSymbol>
|
||||
</m>
|
||||
</m>
|
||||
</m>
|
||||
<!--可变点限速-->
|
||||
<m v="OMDB_SPEEDLIMIT_VAR">
|
||||
<m k="direct">
|
||||
<m v="2">
|
||||
<lineSymbol src="assets:omdb/oneway_left.svg"></lineSymbol>
|
||||
</m>
|
||||
<m v="3">
|
||||
<lineSymbol src="assets:omdb/oneway_right.svg"></lineSymbol>
|
||||
</m>
|
||||
</m>
|
||||
</m>
|
||||
</m>
|
||||
</rendertheme>
|
11
collect-library/src/main/assets/omdb/oneway_left.svg
Normal file
11
collect-library/src/main/assets/omdb/oneway_left.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="580" height="580" xmlns="http://www.w3.org/2000/svg" version="1.0">
|
||||
<metadata id="metadata10"/>
|
||||
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<g transform="rotate(-179.925 290 290)" id="svg_1">
|
||||
<path stroke="#ffffff" shape-rendering="auto" filter-blend-mode="normal" stroke-linejoin="round" fill="none" solid-opacity="1" color-interpolation="sRGB" isolation="auto" stroke-width="64" color-rendering="auto" image-rendering="auto" color="#000000" filter-gaussianBlur-deviation="0" color-interpolation-filters="linearRGB" opacity="0.8" solid-color="#000000" mix-blend-mode="normal" d="m30,261l286,0l0,-72.5l234,101.85l-234,101.15l0,-72.5l-286,0l0,-58z" id="path4151"/>
|
||||
<path fill="#6a6a6a" id="path4136" d="m30,261l286,0l0,-72.5l234,101.85l-234,101.15l0,-72.5l-286,0l0,-58z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 799 B |
11
collect-library/src/main/assets/omdb/oneway_right.svg
Normal file
11
collect-library/src/main/assets/omdb/oneway_right.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="580" height="580" xmlns="http://www.w3.org/2000/svg" version="1.0">
|
||||
<metadata id="metadata10"/>
|
||||
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<g id="svg_1" transform="rotate(-0.400407 290 290)">
|
||||
<path id="path4151" d="m30,261l286,0l0,-72.5l234,101.85l-234,101.15l0,-72.5l-286,0l0,-58z" mix-blend-mode="normal" solid-color="#000000" opacity="0.8" color-interpolation-filters="linearRGB" filter-gaussianBlur-deviation="0" color="#000000" image-rendering="auto" color-rendering="auto" stroke-width="64" isolation="auto" color-interpolation="sRGB" solid-opacity="1" fill="none" stroke-linejoin="round" filter-blend-mode="normal" shape-rendering="auto" stroke="#ffffff"/>
|
||||
<path d="m30,261l286,0l0,-72.5l234,101.85l-234,101.15l0,-72.5l-286,0l0,-58z" id="path4136" fill="#6a6a6a"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 800 B |
@ -4,7 +4,6 @@ import com.navinfo.collect.library.utils.GeometryToolsKt
|
||||
import io.realm.RealmObject
|
||||
import io.realm.RealmSet
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import io.realm.annotations.RealmClass
|
||||
|
||||
|
||||
/**
|
||||
|
@ -116,6 +116,18 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
|
||||
mMapView.updateMap()
|
||||
// initMapLifeSource()
|
||||
|
||||
// 设置矢量图层均在12级以上才显示
|
||||
mMapView.vtmMap.events.bind(UpdateListener { e, mapPosition ->
|
||||
if (e == org.oscim.map.Map.SCALE_EVENT) {
|
||||
// 测评数据图层在指定Zoom后开始显示
|
||||
val isOmdbZoom = mapPosition.zoomLevel>=Constant.OMDB_MIN_ZOOM
|
||||
baseGroupLayer?.layers?.forEach {
|
||||
it.isEnabled = !isOmdbZoom
|
||||
}
|
||||
omdbVectorTileLayer.isEnabled = isOmdbZoom
|
||||
omdbLabelLayer.isEnabled = isOmdbZoom
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun initOMDBVectorTileLayer() {
|
||||
|
@ -42,7 +42,7 @@ class GeometryToolsKt {
|
||||
val tileY1 = MercatorProjection.latitudeToTileY(minMaxY[1], Constant.OVER_ZOOM.toByte())
|
||||
val minTileY = if (tileY0 <= tileY1) tileY0 else tileY1
|
||||
val maxTileY = if (tileY0 <= tileY1) tileY1 else tileY0
|
||||
println("getTileYByGeometry$envelope===$minTileY===$maxTileY")
|
||||
// println("getTileYByGeometry$envelope===$minTileY===$maxTileY")
|
||||
|
||||
for (i in minTileY..maxTileY) {
|
||||
tileYSet.add(i)
|
||||
@ -86,7 +86,7 @@ class GeometryToolsKt {
|
||||
val tileX1 = MercatorProjection.longitudeToTileX(minMaxX[1], Constant.OVER_ZOOM.toByte())
|
||||
val minTileX = if (tileX0 <= tileX1) tileX0 else tileX1
|
||||
val maxTileX = if (tileX0 <= tileX1) tileX1 else tileX0
|
||||
println("getTileXByGeometry$envelope$minTileX===$maxTileX")
|
||||
// println("getTileXByGeometry$envelope$minTileX===$maxTileX")
|
||||
for (i in minTileX..maxTileX) {
|
||||
tileXSet.add(i)
|
||||
}
|
||||
|
367
collect-library/src/main/res/resources/rendertheme.xsd
Normal file
367
collect-library/src/main/res/resources/rendertheme.xsd
Normal file
@ -0,0 +1,367 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:tns="http://opensciencemap.org/rendertheme"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
|
||||
targetNamespace="http://opensciencemap.org/rendertheme" xml:lang="en">
|
||||
|
||||
<!-- attribute types -->
|
||||
<xs:simpleType name="cap">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="butt"/>
|
||||
<xs:enumeration value="round"/>
|
||||
<xs:enumeration value="square"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="closed">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="yes"/>
|
||||
<xs:enumeration value="no"/>
|
||||
<xs:enumeration value="any"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="color">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="elementList">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="node"/>
|
||||
<xs:enumeration value="way"/>
|
||||
<xs:enumeration value="any"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="selectorList">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="first"/>
|
||||
<xs:enumeration value="any"/>
|
||||
<xs:enumeration value="when-matched"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="fontFamily">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="default"/>
|
||||
<xs:enumeration value="default_bold"/>
|
||||
<xs:enumeration value="monospace"/>
|
||||
<xs:enumeration value="sans_serif"/>
|
||||
<xs:enumeration value="serif"/>
|
||||
<xs:enumeration value="thin"/>
|
||||
<xs:enumeration value="light"/>
|
||||
<xs:enumeration value="medium"/>
|
||||
<xs:enumeration value="black"/>
|
||||
<xs:enumeration value="condensed"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="fontStyle">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="bold"/>
|
||||
<xs:enumeration value="bold_italic"/>
|
||||
<xs:enumeration value="italic"/>
|
||||
<xs:enumeration value="normal"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="nonNegativeFloat">
|
||||
<xs:restriction base="xs:float">
|
||||
<xs:minInclusive value="0"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="src">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="((file|assets):)?.+"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="strokeDasharray">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern
|
||||
value="([0-9]+(\.[0-9]+)? *, *[0-9]+(\.[0-9]+)? *, *)*[0-9]+(\.[0-9]+)? *, *[0-9]+(\.[0-9]+)?"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="textKey">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="ele"/>
|
||||
<xs:enumeration value="addr:housenumber"/>
|
||||
<xs:enumeration value="addr_housenumber"/> <!-- Mapzen -->
|
||||
<xs:enumeration value="housenumber"/> <!-- OpenMapTiles -->
|
||||
<xs:enumeration value="name"/>
|
||||
<xs:enumeration value="maxSpeed"/><!--最高速度-->
|
||||
<xs:enumeration value="minSpeed"/><!--最低速度-->
|
||||
<xs:enumeration value="ref"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<!-- style menu cat element -->
|
||||
<xs:complexType name="cat">
|
||||
<xs:attribute name="id" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- style menu name element -->
|
||||
<xs:complexType name="name">
|
||||
<xs:attribute name="lang" type="xs:string" use="required"/>
|
||||
<xs:attribute name="value" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- style menu overlay element -->
|
||||
<xs:complexType name="overlay">
|
||||
<xs:attribute name="id" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- style menu layer element -->
|
||||
<xs:complexType name="layer">
|
||||
<xs:sequence maxOccurs="1" minOccurs="0">
|
||||
<xs:element name="name" maxOccurs="unbounded" minOccurs="0" type="tns:name"/>
|
||||
<xs:element name="cat" maxOccurs="unbounded" minOccurs="0" type="tns:cat"/>
|
||||
<xs:element name="overlay" maxOccurs="unbounded" minOccurs="0" type="tns:overlay"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="id" type="xs:string" use="required"/>
|
||||
<xs:attribute name="parent" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="visible" default="false" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="enabled" default="false" type="xs:boolean" use="optional"/>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- rendering instructions -->
|
||||
<xs:complexType name="area">
|
||||
<xs:attribute name="cat" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="id" default="0" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="use" default="0" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="src" type="tns:src" use="optional"/>
|
||||
<xs:attribute name="symbol-width" type="xs:positiveInteger" use="optional"/>
|
||||
<xs:attribute name="symbol-height" type="xs:positiveInteger" use="optional"/>
|
||||
<xs:attribute name="symbol-percent" type="xs:positiveInteger" use="optional"/>
|
||||
<xs:attribute name="fill" default="#000000" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="stroke" default="#00000000" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="stroke-width" default="0" type="tns:nonNegativeFloat" use="optional"/>
|
||||
<xs:attribute name="fade" default="-1" type="xs:integer" use="optional"/>
|
||||
<xs:attribute name="blend" default="-1" type="xs:integer" use="optional"/>
|
||||
<xs:attribute name="blend-fill" default="#000000" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="mesh" default="false" type="xs:boolean" use="optional"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="caption">
|
||||
<xs:attribute name="cat" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="k" type="tns:textKey" use="required"/>
|
||||
<xs:attribute name="dy" default="0" type="xs:float" use="optional"/>
|
||||
<xs:attribute name="font-family" default="default" type="tns:fontFamily" use="optional"/>
|
||||
<xs:attribute name="style" default="normal" type="tns:fontStyle" use="optional"/>
|
||||
<xs:attribute name="size" default="0" type="tns:nonNegativeFloat" use="optional"/>
|
||||
<xs:attribute name="bg-fill" default="#00000000" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="fill" default="#000000" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="stroke" default="#000000" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="stroke-width" default="0" type="tns:nonNegativeFloat" use="optional"/>
|
||||
<!-- polygon area expressed as a ratio to tile area, e.g. 0.1 for 10% of tile area -->
|
||||
<xs:attribute name="area-size" default="0" type="tns:nonNegativeFloat" use="optional"/>
|
||||
<!-- priority for label placement, 0 = highest priority -->
|
||||
<xs:attribute name="priority" default="0" type="xs:integer" use="optional"/>
|
||||
<!-- symbol src name -->
|
||||
<xs:attribute name="symbol" type="tns:src" use="optional"/>
|
||||
<xs:attribute name="symbol-width" type="xs:positiveInteger" use="optional"/>
|
||||
<xs:attribute name="symbol-height" type="xs:positiveInteger" use="optional"/>
|
||||
<xs:attribute name="symbol-percent" type="xs:positiveInteger" use="optional"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="circle">
|
||||
<xs:attribute name="cat" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="radius" type="tns:nonNegativeFloat" use="required"/>
|
||||
<xs:attribute name="scale-radius" default="false" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="fill" default="#00000000" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="stroke" default="#00000000" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="stroke-width" default="0" type="tns:nonNegativeFloat" use="optional"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="line">
|
||||
<xs:attribute name="cat" type="xs:string" use="optional"/>
|
||||
|
||||
<!-- style: TODO only in style-line-->
|
||||
<xs:attribute name="id" default="0" type="xs:string" use="optional"/>
|
||||
|
||||
<!-- inherited style -->
|
||||
<xs:attribute name="use" default="0" type="xs:string" use="optional"/>
|
||||
|
||||
<xs:attribute name="src" type="tns:src" use="optional"/>
|
||||
<xs:attribute name="symbol-width" type="xs:positiveInteger" use="optional"/>
|
||||
<xs:attribute name="symbol-height" type="xs:positiveInteger" use="optional"/>
|
||||
<xs:attribute name="symbol-percent" type="xs:positiveInteger" use="optional"/>
|
||||
<xs:attribute name="stroke" default="#000000" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="width" default="0" type="xs:float" use="optional"/>
|
||||
<!-- minimum scaled width to draw outline -->
|
||||
<xs:attribute name="min" default="0" type="xs:float" use="optional"/>
|
||||
<xs:attribute name="dasharray" type="tns:strokeDasharray" use="optional"/>
|
||||
<xs:attribute name="cap" default="round" type="tns:cap" use="optional"/>
|
||||
<xs:attribute name="outline" default="" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="fade" default="-1" type="xs:integer" use="optional"/>
|
||||
<xs:attribute name="blur" default="-1" type="xs:float" use="optional"/>
|
||||
<xs:attribute name="fix" default="false" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="repeat-gap" default="200" type="xs:float" use="optional"/>
|
||||
<xs:attribute name="repeat-start" default="30" type="xs:float" use="optional"/>
|
||||
|
||||
<!-- stipple repeat in 'pixel' -->
|
||||
<xs:attribute name="stipple" default="0" type="xs:integer" use="optional"/>
|
||||
<!-- stipple color -->
|
||||
<xs:attribute name="stipple-stroke" default="#000000" type="tns:color" use="optional"/>
|
||||
<!-- stipple width relative to line width, i.e 0.0-1.0 -->
|
||||
<xs:attribute name="stipple-width" default="0" type="xs:float" use="optional"/>
|
||||
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="text">
|
||||
<xs:attribute name="cat" type="xs:string" use="optional"/>
|
||||
|
||||
<xs:attribute name="id" default="0" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="use" default="0" type="xs:string" use="optional"/>
|
||||
|
||||
<xs:attribute name="k" default="name" type="tns:textKey" use="optional"/>
|
||||
<xs:attribute name="dy" default="0" type="xs:float" use="optional"/>
|
||||
<xs:attribute name="font-family" default="default" type="tns:fontFamily" use="optional"/>
|
||||
<xs:attribute name="style" default="normal" type="tns:fontStyle" use="optional"/>
|
||||
<xs:attribute name="size" default="0" type="tns:nonNegativeFloat" use="optional"/>
|
||||
<xs:attribute name="bg-fill" default="#00000000" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="fill" default="#000000" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="stroke" default="#000000" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="stroke-width" default="0" type="tns:nonNegativeFloat" use="optional"/>
|
||||
<xs:attribute name="caption" default="false" type="xs:boolean" use="optional"/>
|
||||
<!-- polygon area expressed as a ratio to tile area, e.g. 0.1 for 10% of tile area -->
|
||||
<xs:attribute name="area-size" default="0" type="tns:nonNegativeFloat" use="optional"/>
|
||||
<!-- priority for label placement, 0 = highest priority -->
|
||||
<xs:attribute name="priority" default="0" type="xs:integer" use="optional"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="symbol">
|
||||
<xs:attribute name="cat" type="xs:string" use="optional"/>
|
||||
|
||||
<xs:attribute name="id" default="0" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="use" default="0" type="xs:string" use="optional"/>
|
||||
|
||||
<xs:attribute name="src" type="tns:src" use="optional"/>
|
||||
<xs:attribute name="symbol-width" type="xs:positiveInteger" use="optional"/>
|
||||
<xs:attribute name="symbol-height" type="xs:positiveInteger" use="optional"/>
|
||||
<xs:attribute name="symbol-percent" type="xs:positiveInteger" use="optional"/>
|
||||
|
||||
<!-- symbols on lines -->
|
||||
<xs:attribute name="billboard" default="false" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="repeat" default="false" type="xs:boolean" use="optional"/>
|
||||
<xs:attribute name="repeat-gap" default="200" type="xs:float" use="optional"/>
|
||||
<xs:attribute name="repeat-start" default="30" type="xs:float" use="optional"/>
|
||||
<xs:attribute name="rotate" default="true" type="xs:boolean" use="optional"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="extrusion">
|
||||
<xs:attribute name="cat" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="line-color" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="side-color" type="tns:color" use="required"/>
|
||||
<xs:attribute name="top-color" type="tns:color" use="required"/>
|
||||
<xs:attribute name="hsv-h" default="0" type="xs:double" use="optional"/>
|
||||
<xs:attribute name="hsv-s" default="1" type="xs:double" use="optional"/>
|
||||
<xs:attribute name="hsv-v" default="1" type="xs:double" use="optional"/>
|
||||
<!-- 12m default -->
|
||||
<xs:attribute name="default-height" default="12" type="xs:positiveInteger" use="optional"/>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- match elements -->
|
||||
<xs:complexType name="m">
|
||||
<xs:choice maxOccurs="unbounded" minOccurs="0">
|
||||
<!-- recursion to allow for nested m -->
|
||||
<xs:element name="m" type="tns:m"/>
|
||||
|
||||
<xs:element name="area" type="tns:area"/>
|
||||
<xs:element name="caption" type="tns:caption"/>
|
||||
<xs:element name="circle" type="tns:circle"/>
|
||||
<xs:element name="line" type="tns:line"/>
|
||||
<xs:element name="outline" type="tns:line"/>
|
||||
<xs:element name="lineSymbol" type="tns:line"/>
|
||||
<xs:element name="text" type="tns:text"/>
|
||||
<xs:element name="extrusion" type="tns:extrusion"/>
|
||||
<xs:element name="symbol" type="tns:symbol"/>
|
||||
|
||||
<!-- outline is defined within rules to match layering -->
|
||||
<xs:element name="outline-layer" type="tns:line"/>
|
||||
</xs:choice>
|
||||
|
||||
<xs:attribute name="select" default="any" type="tns:selectorList" use="optional"/>
|
||||
<xs:attribute name="e" type="tns:elementList" use="optional"/>
|
||||
<xs:attribute name="k" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="v" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="cat" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="closed" default="any" type="tns:closed" use="optional"/>
|
||||
<xs:attribute name="zoom-min" default="0" type="xs:unsignedByte" use="optional"/>
|
||||
<xs:attribute name="zoom-max" default="127" type="xs:unsignedByte" use="optional"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="atlasRect">
|
||||
<xs:attribute name="id" type="xs:string" use="required"/>
|
||||
<xs:attribute name="pos" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="atlas">
|
||||
<xs:choice maxOccurs="unbounded" minOccurs="0">
|
||||
<xs:element name="rect" type="tns:atlasRect"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="img" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- stylemenu element -->
|
||||
<xs:complexType name="stylemenu">
|
||||
<xs:sequence maxOccurs="1" minOccurs="0">
|
||||
<xs:element name="layer" maxOccurs="unbounded" minOccurs="0" type="tns:layer"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="defaultvalue" type="xs:string" use="required"/>
|
||||
<xs:attribute name="defaultlang" type="xs:string" use="required"/>
|
||||
<xs:attribute name="id" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- tag-transform element -->
|
||||
<xs:complexType name="tag-transform">
|
||||
<xs:attribute name="k" type="xs:string" use="required"/>
|
||||
<xs:attribute name="v" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="k-lib" type="xs:string" use="required"/>
|
||||
<xs:attribute name="v-lib" type="xs:string" use="optional"/>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- rendertheme element -->
|
||||
<xs:complexType name="rendertheme">
|
||||
<xs:sequence maxOccurs="1" minOccurs="0">
|
||||
<xs:element name="stylemenu" maxOccurs="1" minOccurs="0" type="tns:stylemenu"/>
|
||||
|
||||
<!-- tag definitions -->
|
||||
<xs:choice maxOccurs="unbounded" minOccurs="0">
|
||||
<xs:element name="tag-transform" type="tns:tag-transform"/>
|
||||
</xs:choice>
|
||||
|
||||
<!-- style definitions -->
|
||||
<xs:sequence maxOccurs="256" minOccurs="0">
|
||||
<xs:choice maxOccurs="unbounded" minOccurs="0">
|
||||
<xs:element name="style-text" type="tns:text"/>
|
||||
<xs:element name="style-symbol" type="tns:symbol"/>
|
||||
<xs:element name="style-area" type="tns:area"/>
|
||||
<xs:element name="style-line" type="tns:line"/>
|
||||
<!-- <xs:element name="style-outline" type="tns:line" /> -->
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
|
||||
<xs:choice maxOccurs="1" minOccurs="0">
|
||||
<xs:element name="atlas" type="tns:atlas"/>
|
||||
</xs:choice>
|
||||
|
||||
<!-- matching rules -->
|
||||
<xs:sequence maxOccurs="unbounded" minOccurs="0">
|
||||
<xs:element name="m" type="tns:m"/>
|
||||
</xs:sequence>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="version" type="xs:positiveInteger" use="required"/>
|
||||
<xs:attribute name="map-background" default="#ffffff" type="tns:color" use="optional"/>
|
||||
<xs:attribute name="base-stroke-width" default="1" type="tns:nonNegativeFloat"
|
||||
use="optional"/>
|
||||
<xs:attribute name="base-text-scale" default="1" type="tns:nonNegativeFloat"
|
||||
use="optional"/>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- root element -->
|
||||
<xs:element name="rendertheme" type="tns:rendertheme"/>
|
||||
</xs:schema>
|
Loading…
x
Reference in New Issue
Block a user