فهرست منبع

1、案件提报快捷描述信息、案件类型信息的拉取、接口、存储、获取、展示功能的开发
2、解决Activity切换和Fragment切换的BUG

不会爬树的猴 1 سال پیش
والد
کامیت
44549e1597
37فایلهای تغییر یافته به همراه1340 افزوده شده و 219 حذف شده
  1. 0 12
      .idea/deploymentTargetDropDown.xml
  2. 1 1
      .idea/misc.xml
  3. 4 0
      app/build.gradle
  4. 53 0
      app/src/main/java/com/cr/common/CrAudioUtil.kt
  5. 10 0
      app/src/main/java/com/cr/common/CrColorManager.kt
  6. 25 1
      app/src/main/java/com/cr/common/CrFlightControlInfo.kt
  7. 64 4
      app/src/main/java/com/cr/common/DataManager.kt
  8. 1 1
      app/src/main/java/com/cr/common/JSONManager.java
  9. 18 18
      app/src/main/java/com/cr/cruav/AvLogin.kt
  10. 4 5
      app/src/main/java/com/cr/cruav/AvMain.kt
  11. 71 0
      app/src/main/java/com/cr/models/SelModel.kt
  12. 3 1
      app/src/main/java/com/cr/network/TCPDataTask.kt
  13. 230 52
      app/src/main/java/com/cr/pages/FragmentMap.kt
  14. 82 28
      app/src/main/java/com/cr/pages/FragmentTopInfo.kt
  15. 230 0
      app/src/main/java/com/cr/pages/FragmentUploadAction.kt
  16. 14 0
      app/src/main/java/com/cr/pages/FragmentUploadCase.kt
  17. 3 1
      app/src/main/java/com/cr/pages/FragmentUploadCaseMain.kt
  18. 43 0
      app/src/main/java/com/cr/view/CrICON.kt
  19. 94 46
      app/src/main/java/com/cr/viewmodel/CrFlightControlVM.kt
  20. 1 1
      app/src/main/java/com/cr/viewmodel/CrLinkVM.kt
  21. BIN
      app/src/main/res/drawable/ico_air.png
  22. BIN
      app/src/main/res/drawable/ico_home.png
  23. 5 0
      app/src/main/res/drawable/shape_circle.xml
  24. 13 0
      app/src/main/res/drawable/shape_trapezoid_left.xml
  25. 1 1
      app/src/main/res/layout/av_login.xml
  26. 9 10
      app/src/main/res/layout/av_main.xml
  27. 5 5
      app/src/main/res/layout/frag_camera_params.xml
  28. 262 0
      app/src/main/res/layout/frag_case_upload_upload.xml
  29. 18 16
      app/src/main/res/layout/frag_dynamic_info.xml
  30. 3 1
      app/src/main/res/layout/frag_fpv.xml
  31. 3 2
      app/src/main/res/layout/frag_map.xml
  32. 8 8
      app/src/main/res/layout/frag_top_info.xml
  33. 13 0
      app/src/main/res/values/array.xml
  34. 1 0
      app/src/main/res/values/colors.xml
  35. 27 3
      app/src/main/res/values/strings.xml
  36. 20 1
      app/src/main/res/values/themes.xml
  37. 1 1
      gradle.properties

+ 0 - 12
.idea/deploymentTargetDropDown.xml

@@ -1,18 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="deploymentTargetDropDown">
-    <runningDeviceTargetSelectedWithDropDown>
-      <Target>
-        <type value="RUNNING_DEVICE_TARGET" />
-        <deviceKey>
-          <Key>
-            <type value="SERIAL_NUMBER" />
-            <value value="10.88.88.112:5555" />
-          </Key>
-        </deviceKey>
-      </Target>
-    </runningDeviceTargetSelectedWithDropDown>
-    <timeTargetWasSelectedWithDropDown value="2023-08-16T09:09:50.939110Z" />
     <runningDeviceTargetsSelectedWithDialog>
       <Target>
         <type value="RUNNING_DEVICE_TARGET" />

+ 1 - 1
.idea/misc.xml

@@ -9,7 +9,7 @@
   <component name="VisualizationToolProject">
     <option name="state">
       <ProjectState>
-        <option name="scale" value="0.03820412716118238" />
+        <option name="scale" value="0.165" />
       </ProjectState>
     </option>
   </component>

+ 4 - 0
app/build.gradle

@@ -25,6 +25,9 @@ android {
             minifyEnabled false
             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
+        debug{
+            debuggable true
+        }
     }
     dexOptions {
         javaMaxHeapSize "4g"
@@ -112,4 +115,5 @@ dependencies {
     api 'org.locationtech.jts:jts-core:1.18.2'
     //api "org.geotools:gt-main:$geotools_version"
     //api "org.geotools:gt-epsg-hsql:$geotools_version"
+    api 'cn.carbs.android:SegmentControlView:1.0.0'
 }

+ 53 - 0
app/src/main/java/com/cr/common/CrAudioUtil.kt

@@ -3,7 +3,10 @@ package com.cr.common
 import android.content.Context
 import android.media.AudioManager
 import android.media.MediaPlayer
+import android.speech.tts.TextToSpeech
+import com.cr.cruav.CrApplication
 import com.cr.data.CrUtil
+import java.util.*
 
 /**
  * 操作系统:MAC系统
@@ -12,6 +15,54 @@ import com.cr.data.CrUtil
  * 描述:音频播放类
  */
 class CrAudioUtil {
+    private var tts:TextToSpeech?= null // define: 2023/8/17 tts语音
+    private var isSuccess:Boolean = false  // define: 2023/8/17 是否初始化完成
+    /**
+     * 用于单例
+     */
+    object InstanceHelper{
+        var self = CrAudioUtil()
+    }
+
+    /**
+     * tts监听
+     */
+    private val ttsListener = TextToSpeech.OnInitListener {
+        if(it == TextToSpeech.SUCCESS){
+            // todo: 2023/8/17 设置播放语言
+            var result = tts?.setLanguage(Locale.CHINESE)
+            if(result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED){
+                CrUtil.showToast("不支持中文!")
+            }else if(result == TextToSpeech.LANG_AVAILABLE){
+                CrUtil.showToast("语音TTS初始化完成!")
+                isSuccess = true
+            }
+        }else{
+            CrUtil.showToast("TTS初始化失败!")
+        }
+    }
+
+    /**
+     * 初始化
+     */
+    init {
+        tts = TextToSpeech(CrApplication.getContext(),ttsListener)
+    }
+
+
+    /**
+     * 播放语音
+     * @param ttsMessage String
+     */
+    fun play(ttsMessage:String){
+        if(isSuccess){
+            tts?.speak(ttsMessage,TextToSpeech.QUEUE_ADD,null,"A")
+        }else{
+            CrUtil.showToast("TTS初始化异常!")
+        }
+
+    }
+
     /**
      * 静态方法
      */
@@ -30,6 +81,8 @@ class CrAudioUtil {
             playSound(context,resID,false)
         }
 
+        fun getInstance() = InstanceHelper.self
+
         /**
          * 播放声音
          * @param context Context 上下文

+ 10 - 0
app/src/main/java/com/cr/common/CrColorManager.kt

@@ -3,6 +3,7 @@ package com.cr.common
 import android.content.Context
 import android.content.res.ColorStateList
 import androidx.core.content.ContextCompat
+import com.cr.cruav.CrApplication
 
 /**
  * 操作系统:MAC系统
@@ -35,5 +36,14 @@ class CrColorManager {
         fun getColor(context: Context,color: Int):Int{
             return ContextCompat.getColor(context,color)
         }
+
+        /**
+         * 从XML中获取颜色值
+         * @param color Int 颜色资源Id
+         * @return Int 颜色
+         */
+        fun getColor(color:Int):Int{
+            return ContextCompat.getColor(CrApplication.getContext(),color)
+        }
     }
 }

+ 25 - 1
app/src/main/java/com/cr/common/CrFlightControlInfo.kt

@@ -32,6 +32,7 @@ data class CrFlightControlInfo(var isConnection: Boolean = false) :CrDataCommon(
     var latitude:Double = 0.0
     var altitude:Double = 0.0
     var takeoffAltitude:Double = 0.0  // define: 2023/8/15 起飞海拔
+    var isLocationValid:Boolean = false
 
     var longitudeStr:String = DEFAULT_LOCATION
     var latitudeStr:String = DEFAULT_LOCATION
@@ -51,6 +52,16 @@ data class CrFlightControlInfo(var isConnection: Boolean = false) :CrDataCommon(
     var homeDistanceStr:String = DEFAULT_STR
     var homeAltitudeStr:String = DEFAULT_STR
 
+    var homeOldLongitude:Double = 0.0
+    var homeOldLatitude:Double = 0.0
+    var isUpdateHomeLocation:Boolean = false
+    var isHomeLocationValid:Boolean = false
+
+    // define: 2023/8/17 飞行器姿态
+    var pitch:Double = 0.0
+    var yaw:Double = 0.0
+    var roll:Double = 0.0
+
 
 
     /**
@@ -63,22 +74,35 @@ data class CrFlightControlInfo(var isConnection: Boolean = false) :CrDataCommon(
         gpsCount = DEFAULT_STR
         imuState = DEFAULT_STR
         compassState = DEFAULT_STR
+        // todo: 2023/8/17 位置相关
         longitude = 0.0
         latitude = 0.0
         altitude = 0.0
-        takeoffAltitude = 0.0
         longitudeStr = DEFAULT_LOCATION
         latitudeStr = DEFAULT_LOCATION
         altitudeStr = DEFAULT_STR
+        isLocationValid = false
+        // todo: 2023/8/17 起飞相关
+        takeoffAltitude = 0.0
         takeoffAltitudeStr = DEFAULT_STR
+        // todo: 2023/8/17 速速相关
         speedX = 0.0
         speedY = 0.0
         speedZ = 0.0
+        // todo: 2023/8/17 返航相关
         homeLongitude = 0.0
         homeLatitude = 0.0
         homeAltitude = 0
         homeDistance = 0.0
         homeDistanceStr = DEFAULT_STR
         homeAltitudeStr = DEFAULT_STR
+        homeOldLatitude = 0.0
+        homeOldLongitude = 0.0
+        isUpdateHomeLocation = false
+        isHomeLocationValid = false
+        // todo: 2023/8/17 姿态相关
+        pitch = 0.0
+        yaw = 0.0
+        roll = 0.0
     }
 }

+ 64 - 4
app/src/main/java/com/cr/common/DataManager.kt

@@ -1,12 +1,10 @@
 package com.cr.common
 
+import com.cr.data.CrUtil
 import com.cr.map.CaseModel
 import com.cr.map.LayerConfigModel
 import com.cr.map.LayerModel
-import com.cr.models.IPAndComModel
-import com.cr.models.CompletionModel
-import com.cr.models.UserModel
-import com.cr.models.ICompletion
+import com.cr.models.*
 
 /**
  * 操作系统:MAC系统
@@ -231,5 +229,67 @@ class DataManager {
                 if(callback != null) callback.onCompletion(CompletionModel(false, mutableListOf("未查询到任何信息!")))
             }
         }
+
+        /**
+         * 存储案件提报快捷描述信息
+         * @param dataList List<SelModel> 快捷信息列表
+         * @return Boolean 存储是否成功
+         */
+        fun saveCaseSubmitDescription(dataList:List<SelModel>):Boolean{
+            var isReturn = true;
+            DatabaseAppUAVManager.getInstance().delete("CASEKjInput","")
+            for (model in dataList){
+                var value:HashMap<String,String> = hashMapOf()
+                value["kjid"] = model.code!!
+                value["kjnr"] = model.name!!
+                isReturn = isReturn && DatabaseAppUAVManager.getInstance().insert("CASEKjInput",value)
+            }
+            return isReturn
+        }
+
+        /**
+         * 获取案件提报快捷描述信息
+         * @return List<SelModel> 快捷描述信息列表
+         */
+        fun getCaseSubmitDescription():List<SelModel>{
+            var resList = mutableListOf<SelModel>()
+            var SQL = "select * from CASEKjInput order by kjid;"
+            var qList = DatabaseAppUAVManager.getInstance().query(SQL)
+            for (map in qList){
+                resList.add(SelModel(map["kjid"]!!,map["kjnr"]!!))
+            }
+            return resList
+        }
+
+        /**
+         * 案件类型本地化
+         * @param dataList List<SelModel> 案件类型列表
+         * @return Boolean
+         */
+        fun saveCaseType(dataList:List<SelModel>):Boolean{
+            var isReturn = true;
+            DatabaseAppUAVManager.getInstance().delete("CASEType","")
+            for (model in dataList){
+                var value:HashMap<String,String> = hashMapOf()
+                value["lxid"] = model.code!!
+                value["lxname"] = model.name!!
+                isReturn = isReturn && DatabaseAppUAVManager.getInstance().insert("CASEType",value)
+            }
+            return isReturn
+        }
+
+        /**
+         * 获取案件类型快捷描述信息
+         * @return List<SelModel> 类型信息列表
+         */
+        fun getCaseType():List<SelModel>{
+            var resList = mutableListOf<SelModel>()
+            var SQL = "select * from CASEType order by lxid;"
+            var qList = DatabaseAppUAVManager.getInstance().query(SQL)
+            for (map in qList){
+                resList.add(SelModel(map["lxid"]!!,map["lxname"]!!))
+            }
+            return resList
+        }
     }
 }

+ 1 - 1
app/src/main/java/com/cr/common/JSONManager.java

@@ -128,7 +128,7 @@ public class JSONManager {
      * @param errMessage 内容
      * @return 无数据描述JSON字符串
      */
-    public static String toJSONNodata(String errCode, String errMessage) {
+    public static String toJSONNoData(String errCode, String errMessage) {
         JSONObject obj = new JSONObject();
         try{
             obj.put("code", errCode);

+ 18 - 18
app/src/main/java/com/cr/cruav/AvLogin.kt

@@ -3,6 +3,7 @@ package com.cr.cruav
 import android.Manifest
 import android.app.Activity
 import android.content.pm.PackageManager
+import android.graphics.Color
 import android.os.Build
 import android.os.Bundle
 import android.util.Log
@@ -88,11 +89,13 @@ class AvLogin : CrActivity(), OnClickListener {
         super.joinControls()
         // todo: 2023/4/6 初始化版本信息
         lblVersion = findViewById(R.id.login_version)
-        //lblVersion?.text = "{${CrUtil.getVersionName(this)}}"
+        lblVersion?.text = "{${CrUtil.getVersionName(this)}}"
         // todo: 2023/4/6 初始化账号密码
         txtUserName = findViewById(R.id.login_username)
         txtPassword = findViewById(R.id.login_password)
         txtPassword?.setIsPassword(true)
+        txtUserName?.setContentColor(CrColorManager.getColor(R.color.login_txt_color))
+        txtPassword?.setContentColor(CrColorManager.getColor(R.color.login_txt_color))
         switchSavePassword = findViewById(R.id.switch_password)
     }
 
@@ -129,24 +132,19 @@ class AvLogin : CrActivity(), OnClickListener {
     override fun onClick(p0: View?) {
         when (p0!!.id) {
             R.id.login_btn_login -> {
-//                var userName: String? = txtUserName?.checkBlank("请输入账号!") ?: return
-//                var passWord: String? = txtPassword?.checkBlank("请输入密码!") ?: return
-//                var isSave: Boolean? = switchSavePassword?.isChecked
-//                checkUserInfo(userName!!, passWord!!, isSave!!)
-                this.finish()
-                context!!.onStart<AvMain>()
-//                showMessage(CrUnitManager.getDeviceDpi(this))
+                var userName: String? = txtUserName?.checkBlank("请输入账号!") ?: return
+                var passWord: String? = txtPassword?.checkBlank("请输入密码!") ?: return
+                var isSave: Boolean? = switchSavePassword?.isChecked
+                checkUserInfo(userName!!, passWord!!, isSave!!)
+//                this.finish()
+//                context!!.onStart<AvMain>()
 
             }
             R.id.login_btn_set -> {
-//                fragIpAndCom?.let {
-//                    it.setBarVisible(isVisible = true)
-//                    showFragment(it)
-//                }
-//                showMessage(CrUnitManager.getDeviceDpi(this))
-                var dis = CrJTMManager.calculateDistance(118.3556,35.1234,118.2314,35.2341)
-                var dis1 = CrJTMManager.getDistance(118.3556,35.1234,118.2314,35.2341)
-                CrUtil.print("距离A${dis}距离B${dis1}")
+                fragIpAndCom?.let {
+                    it.setBarVisible(isVisible = true)
+                    showFragment(it)
+                }
             }
 
         }
@@ -166,7 +164,7 @@ class AvLogin : CrActivity(), OnClickListener {
             }
         } else {
             if (DataManager.deleteUser())
-            // todo: 2023/4/10 登录系统
+                // todo: 2023/4/10 登录系统
                 login(userName, password)
         }
     }
@@ -187,6 +185,7 @@ class AvLogin : CrActivity(), OnClickListener {
                 override fun onSuccess(jsonArray: JSONArray) {
                     CrConfig.user = UserModel.toModel(jsonArray.optString(0))
                     context!!.onStart<AvMain>()
+                    finish()
                 }
 
                 // todo: 2023/4/10 失败
@@ -312,8 +311,9 @@ class AvLogin : CrActivity(), OnClickListener {
      * 销毁
      */
     override fun onDestroy() {
-        CrApplication.getEventBus().unregister(this)
         super.onDestroy()
+        CrApplication.getEventBus().unregister(this)
+        CrUtil.print("登录页面销毁,订阅事件销毁!")
     }
 
     /**

+ 4 - 5
app/src/main/java/com/cr/cruav/AvMain.kt

@@ -8,10 +8,7 @@ import androidx.activity.viewModels
 import androidx.fragment.app.commit
 import com.cr.data.CrConfig
 import com.cr.data.CrUtil
-import com.cr.event.CrCommonAction
-import com.cr.event.EventCommon
-import com.cr.event.EventFragmentBarAction
-import com.cr.event.EventMapCapture
+import com.cr.event.*
 import com.cr.map.CaseModel
 import com.cr.map.EventMap
 import com.cr.map.MapAction
@@ -524,7 +521,9 @@ class AvMain : CrActivity(), View.OnClickListener {
      */
     @Subscribe
     fun onFragmentBar(event: EventFragmentBarAction) {
-        hideFragment(event.fragment!!)
+        if(event.barAction == BarAction.ACTION_DISMISS){
+            hideFragment(event.fragment!!)
+        }
     }
 
     /**

+ 71 - 0
app/src/main/java/com/cr/models/SelModel.kt

@@ -0,0 +1,71 @@
+package com.cr.models
+
+import com.cr.common.ClassManager
+import com.cr.common.JSONManager
+import org.json.JSONArray
+import org.json.JSONObject
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/8/23 17:05
+ * 描述:选择类型模型
+ */
+class SelModel @JvmOverloads constructor(code:String,name:String) : iNetDataModel<SelModel> {
+    var code: String? = null // define: 2023/8/23 代码
+    var name: String? = null // define: 2023/8/23 名称
+
+    companion object:iJSONModel<SelModel>{
+        /**
+         * JSON字符串转换为模型
+         * @param json String
+         * @return SelModel?
+         */
+        override fun toModel(json: String): SelModel? {
+            var obj = JSONObject(json)
+            var model = SelModel()
+            model.code = JSONManager.getStringValue(obj,"code")
+            model.name = JSONManager.getStringValue(obj,"name")
+            return model
+        }
+
+
+        /**
+         * 来源于JSON数组
+         * @param array JSONArray JSON数组
+         * @return List<SelModel> 数据集
+         */
+        fun fromJSONArray(array:JSONArray):MutableList<SelModel>{
+            var resList = mutableListOf<SelModel>()
+            for (i in 0 until array.length()){
+                var model = SelModel.toModel(array.optString(i))
+                resList.add(model!!)
+            }
+            return resList
+        }
+    }
+
+    /**
+     * 初始化
+     */
+    init {
+        this.code = code
+        this.name = name
+    }
+
+    /**
+     * 无参数初始化
+     * @constructor
+     */
+    constructor() : this("","")
+
+    /**
+     * 转换为JSON字符串
+     * @return String JSON字符串
+     */
+    override fun toJSON(): String {
+        var jsonObj: JSONObject = ClassManager.fieldsToJSONObject(this)
+        return jsonObj.toString()
+    }
+
+}

+ 3 - 1
app/src/main/java/com/cr/network/TCPDataTask.kt

@@ -158,7 +158,7 @@ class TCPDataTask {
      * @param context Context 上下文  如果不显示等待框 可以传null
      * @param loadingMessage String 等待消息内容
      */
-    fun<T> sendJSON(url:String, iModel:iNetDataModel<T>, callback:OnChangeListener,context:Context?,loadingMessage:String?){
+    fun<T> sendJSON(url:String, iModel:iNetDataModel<T>, callback:OnChangeListener, context:Context?, loadingMessage:String?){
         this.context = context
         // todo: 2023/4/8 确定传输类型
         var mediaType:MediaType = "application/json;charset=utf-8".toMediaType()
@@ -193,6 +193,8 @@ class TCPDataTask {
                     }catch (e:java.lang.Exception){
                         if(callback != null) callback.onFailed(e.message!!)
                     }
+                }else{
+                    if(callback != null) callback.onFailed("服务器连接异常!")
                 }
             }
         })

+ 230 - 52
app/src/main/java/com/cr/pages/FragmentMap.kt

@@ -7,9 +7,8 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import com.cr.common.CrFileManager
-import com.cr.common.CrUnitManager
-import com.cr.common.DataManager
+import androidx.fragment.app.activityViewModels
+import com.cr.common.*
 import com.cr.cruav.CrApplication
 import com.cr.cruav.R
 import com.cr.data.CrUtil
@@ -19,6 +18,7 @@ import com.cr.event.EventMapCapture
 import com.cr.map.*
 import com.cr.models.CompletionModel
 import com.cr.models.ICompletion
+import com.cr.viewmodel.CrFlightControlVM
 import com.esri.arcgisruntime.arcgisservices.LabelDefinition
 import com.esri.arcgisruntime.data.*
 import com.esri.arcgisruntime.geometry.*
@@ -49,6 +49,8 @@ import kotlin.math.abs
  * 描述:地图界面
  */
 class FragmentMap : CrAnimationFragment() {
+    // todo: 2023/8/17 飞行器模型
+    private val flightControlVm:CrFlightControlVM by activityViewModels()
     /**
      * 事件监听接口
      */
@@ -87,40 +89,40 @@ class FragmentMap : CrAnimationFragment() {
     val LAYER_NAME_AIR_HOME = "返航点"
 
     // todo: 2023/4/14 符号相关常量
-    val SYMBOL_WIDTH = 25.0f;  //  define: 2023/4/13 图片符号的宽度
-    val SYMBOL_HEIGHT = 25.0f;  //  define: 2023/4/13 图片符号的高度
-    val R_LABEL_WJ_NO = "wj_no";  //  define: 2023/4/13 未上传违建标识
-    val R_LABEL_WJ_YES = "wj_yes"; //  define: 2023/4/13 已上传违建标识
-    val R_LABEL_REPEAT_NO = "repeat_no";  //  define: 2023/4/13 为上传复飞点标识
-    val R_LABEL_REPEAT_YES = "repeat_yes"; //  define: 2023/4/13 已上传复飞点标识
+    val SYMBOL_WIDTH = 25.0f  //  define: 2023/4/13 图片符号的宽度
+    val SYMBOL_HEIGHT = 25.0f  //  define: 2023/4/13 图片符号的高度
+    val R_LABEL_WJ_NO = "wj_no"  //  define: 2023/4/13 未上传违建标识
+    val R_LABEL_WJ_YES = "wj_yes" //  define: 2023/4/13 已上传违建标识
+    val R_LABEL_REPEAT_NO = "repeat_no"  //  define: 2023/4/13 为上传复飞点标识
+    val R_LABEL_REPEAT_YES = "repeat_yes" //  define: 2023/4/13 已上传复飞点标识
 
     // todo: 2023/4/14 媒体点相关常量
-    val MEDIA_TYPE_WJ_NO = "0";    //  define: 2023/4/13 未上传的违建点
-    val MEDIA_TYPE_WJ_YES = "1";  //  define: 2023/4/13 已上传的违建点
-    val MEDIA_TYPE_REPEAT_NO = "4";   //  define: 2023/4/13 未上传的复飞案件
-    val MEDIA_TYPE_REPEAT_YES = "5";   //  define: 2023/4/13 已上传的复飞案件
+    val MEDIA_TYPE_WJ_NO = "0"    //  define: 2023/4/13 未上传的违建点
+    val MEDIA_TYPE_WJ_YES = "1"  //  define: 2023/4/13 已上传的违建点
+    val MEDIA_TYPE_REPEAT_NO = "4"   //  define: 2023/4/13 未上传的复飞案件
+    val MEDIA_TYPE_REPEAT_YES = "5"   //  define: 2023/4/13 已上传的复飞案件
 
     // todo: 2023/4/14 字段相关常量
     companion object {
-        val FIELD_NET_CASE_POLYGON_AJH = "AJH";   //  define: 2023/4/13 网络案件的案件编号
-        val FIELD_CASE_POLYGON_ANJID = "ANJID";   //  define: 2023/4/13 案件ID
-        val FIELD_CASE_POLYGON_MJ = "MJ";   //  define: 2023/4/13 面积
-        val FIELD_CASE_POLYGON_BZ = "BZ";   //  define: 2023/4/13 违建面的类型 0--代表未匹配 1--代表已匹配
-        val FIELD_CASE_POLYGON_BZ_VALUE_NO = "0";   //  define: 2023/4/13 未匹配
-        val FIELD_CASE_POLYGON_BZ_VALUE_YES = "1";   //  define: 2023/4/13 已匹配
-        val FIELD_CASE_NAME = "NAME";   //  define: 2023/4/13 名称字段
-        val FIELD_CASE_IMAGES = "IMAGES";   //  define: 2023/4/13 图片集合字段
-        val FIELD_CASE_RQ = "RQ";   //  define: 2023/4/13 日期字段
-        val FIELD_CASE_LAT = "LAT";   //  define: 2023/4/13 纬度字段
-        val FIELD_CASE_LNG = "LNG";   //  define: 2023/4/13 经度字段
-        val FIELD_CASE_ISUP = "ISUP";   //  define: 2023/4/13 是否上传
-        val FIELD_CASE_ALT = "ALT";   //  define: 2023/4/13 高度字段
-        val FIELD_CASE_ANG = "ANG";   //  define: 2023/4/13 角度字段
-        val FIELD_CASE_TYPE = "TYPE";   //  define: 2023/4/13 类型字段
-        val FIELD_CASE_ISDOWN = "ISDOWN";   //  define: 2023/4/13 是否下载
+        val FIELD_NET_CASE_POLYGON_AJH = "AJH"   //  define: 2023/4/13 网络案件的案件编号
+        val FIELD_CASE_POLYGON_ANJID = "ANJID"   //  define: 2023/4/13 案件ID
+        val FIELD_CASE_POLYGON_MJ = "MJ"   //  define: 2023/4/13 面积
+        val FIELD_CASE_POLYGON_BZ = "BZ"   //  define: 2023/4/13 违建面的类型 0--代表未匹配 1--代表已匹配
+        val FIELD_CASE_POLYGON_BZ_VALUE_NO = "0"   //  define: 2023/4/13 未匹配
+        val FIELD_CASE_POLYGON_BZ_VALUE_YES = "1"   //  define: 2023/4/13 已匹配
+        val FIELD_CASE_NAME = "NAME"   //  define: 2023/4/13 名称字段
+        val FIELD_CASE_IMAGES = "IMAGES"   //  define: 2023/4/13 图片集合字段
+        val FIELD_CASE_RQ = "RQ"   //  define: 2023/4/13 日期字段
+        val FIELD_CASE_LAT = "LAT"   //  define: 2023/4/13 纬度字段
+        val FIELD_CASE_LNG = "LNG"   //  define: 2023/4/13 经度字段
+        val FIELD_CASE_ISUP = "ISUP"   //  define: 2023/4/13 是否上传
+        val FIELD_CASE_ALT = "ALT"  //  define: 2023/4/13 高度字段
+        val FIELD_CASE_ANG = "ANG"   //  define: 2023/4/13 角度字段
+        val FIELD_CASE_TYPE = "TYPE"   //  define: 2023/4/13 类型字段
+        val FIELD_CASE_ISDOWN = "ISDOWN"   //  define: 2023/4/13 是否下载
 
         val MEDIA_TYPE_WJ_NO = "0"  // define: 2023/6/12 未上传的案件点
-        val MEDIA_TYPE_WJ_YES = "1"; // define: 2023/6/12 已上传的案件点
+        val MEDIA_TYPE_WJ_YES = "1" // define: 2023/6/12 已上传的案件点
         val MEDIA_TYPE_REPEAT_NO = "4" // define: 2023/6/12 未上传的复飞点
         val MEDIA_TYPE_REPEAT_YES = "5" // define: 2023/6/12 已上传的复飞点
     }
@@ -130,7 +132,6 @@ class FragmentMap : CrAnimationFragment() {
 
     // todo: 2023/4/14 绘制图层
     private var gLayerIco: GraphicsOverlay? = null // define: 2023/4/13 标志图层
-    private var gLayerDoodle: GraphicsOverlay? = null // define: 2023/4/13 涂鸦图层
     private var gLayerAirplaneLocation: GraphicsOverlay? = null // define: 2023/4/13 飞行器位置图层
     private var gLayerAirplaneHomeLocation: GraphicsOverlay? = null // define: 2023/4/13 飞行器返航点位置图层
     private var gLayerAirplaneLine: GraphicsOverlay? = null // define: 2023/4/13 飞行航线图层
@@ -178,6 +179,10 @@ class FragmentMap : CrAnimationFragment() {
     private var mapStateList = mutableListOf<MapStateModel>() // define: 2023/8/14 地图状态
     private var captureNames = mutableListOf<String>()  // define: 2023/8/14 截屏图片名称
 
+    // todo: 2023/8/17 投影
+    private val spatialReferenceWGS84 = SpatialReference.create(4326)
+    private val spatialReferenceWebMTK = SpatialReference.create(3857)
+
 
     /**
      * 重写创建View方法
@@ -227,7 +232,7 @@ class FragmentMap : CrAnimationFragment() {
             setSketchEditor()
             itView.sketchEditor = sketchEditor
             // todo: 2023/4/18 Touch事件初始化
-            mapTouch = MapTouch(context!!, itView)
+            mapTouch = MapTouch(CrApplication.getContext(), itView)
             mapTouch?.setListener(touchListener)
             itView.onTouchListener = mapTouch
         }
@@ -378,7 +383,8 @@ class FragmentMap : CrAnimationFragment() {
         addEditGeoDatabaseToMap()
         // todo: 2023/4/19 添加动态图层
         addGraphicOverlayToMap()
-
+        // todo: 2023/8/17 添加飞行相关图层
+        addAirplaneLayerToMap()
         // todo: 2023/4/13 定位地图中心点
         setMapCenter(118.709, 35.219, 5000.0);
     }
@@ -532,7 +538,82 @@ class FragmentMap : CrAnimationFragment() {
     }
 
     /**
-     * 编辑图层符号话
+     * 添加飞行相关图层到地图
+     */
+    private fun addAirplaneLayerToMap() {
+        // todo: 2023/8/16 初始化航线图层
+        gLayerAirplaneLine = GraphicsOverlay()
+        gLayerAirplaneLine?.let {
+            overlaysAddToMap(it,LAYER_NAME_AIR_LINE,LayerManager.LayerGroup.LAYER_NAME_AIR)
+        }
+        // todo: 2023/8/16 初始化历史航线图层
+        gLayerHistoryAirplaneLine = GraphicsOverlay()
+        gLayerHistoryAirplaneLine?.let {
+            overlaysAddToMap(it,LAYER_NAME_AIR_HISTORY_LINE,LayerManager.LayerGroup.LAYER_NAME_AIR)
+        }
+        // todo: 2023/8/17 初始化返航点图层
+        gLayerAirplaneHomeLocation = GraphicsOverlay()
+        gLayerAirplaneHomeLocation?.let {
+            overlaysAddToMap(it,LAYER_NAME_AIR_HOME,LayerManager.LayerGroup.LAYER_NAME_AIR)
+        }
+        // todo: 2023/8/17 初始化飞行器图层
+        gLayerAirplaneLocation = GraphicsOverlay()
+        gLayerAirplaneLocation?.let {
+            overlaysAddToMap(it,LAYER_NAME_AIR_LOCATION,LayerManager.LayerGroup.LAYER_NAME_AIR)
+        }
+        // todo: 2023/8/17 符号化
+        initAirplaneSymbolInfo()
+    }
+
+    /**
+     * 飞行相关符号化
+     */
+    private fun initAirplaneSymbolInfo(){
+        // todo: 2023/8/17 符号化航线
+        symbolAirplaneLine = SimpleLineSymbol(SimpleLineSymbol.Style.SOLID,Color.WHITE,2.0f)
+        symbolAirplaneLink = SimpleLineSymbol(SimpleLineSymbol.Style.SOLID,Color.GREEN,2.0f)
+        builderAirplaneLine = PolylineBuilder(spatialReferenceWGS84)
+        builderAirplaneLink = PolylineBuilder(spatialReferenceWGS84)
+        graAirplaneLine = Graphic(builderAirplaneLine!!.toGeometry(),symbolAirplaneLine)
+        graAirplaneLink = Graphic(builderAirplaneLink!!.toGeometry(),symbolAirplaneLink)
+        gLayerAirplaneLine?.graphics?.add(graAirplaneLine)
+        gLayerAirplaneLine?.graphics?.add(graAirplaneLink)
+        // todo: 2023/8/17 飞行器符号化
+        builderAirplaneLocation = PointBuilder(spatialReferenceWGS84)
+        symbolAirplaneLocation = createPictureMarkerSymbol(R.drawable.ico_air,25f,40f)
+        graAirplaneLocation = Graphic(builderAirplaneLocation!!.toGeometry(),symbolAirplaneLocation)
+        gLayerAirplaneLocation?.graphics?.add(graAirplaneLocation)
+        // todo: 2023/8/17 返航位置初始化
+        builderAirplaneHomeLocation = PointBuilder(spatialReferenceWGS84)
+        var symbolAirplaneHomeLocation = createPictureMarkerSymbol(R.drawable.ico_home,30f,30f)
+        graAirplaneHomeLocation = Graphic(builderAirplaneHomeLocation!!.toGeometry(),symbolAirplaneHomeLocation)
+        gLayerAirplaneHomeLocation?.graphics?.add(graAirplaneHomeLocation)
+    }
+
+    /**
+     * 添加绘制图层到地图中
+     * @param layer GraphicsOverlay 绘制图层
+     * @param layerName String 图层名称
+     * @param group LayerGroup 分组
+     */
+    private fun overlaysAddToMap(layer:GraphicsOverlay,layerName:String,group:LayerManager.LayerGroup){
+        // todo: 2023/8/17 设置可见
+        layer.isVisible = true
+        // todo: 2023/8/17 加入到地图中
+        mapView?.graphicsOverlays!!.add(layer)
+        // todo: 2023/8/17 加入到图层控制中
+        LayerManager.getInstance().addLayer(
+            LayerModel(
+                layerName,
+                layer.isVisible,
+                LayerType.LAYER_TYPE_GRAPHIC,
+                layer
+            ), group
+        )
+    }
+
+    /**
+     * 编辑图层符号化
      */
     private fun editLayerRenderer() {
         // todo: 2023/4/14  永久涂鸦图层符号化
@@ -678,7 +759,7 @@ class FragmentMap : CrAnimationFragment() {
         width: Float,
         height: Float
     ): PictureMarkerSymbol {
-        val tDrawable = context!!.resources.getDrawable(drawable) as BitmapDrawable
+        val tDrawable = CrApplication.getContext().resources.getDrawable(drawable) as BitmapDrawable
         val symbol = PictureMarkerSymbol(tDrawable)
         if (width > 0) symbol.width = width else symbol.width =
             CrUnitManager.px2dp(tDrawable.bitmap.width).toFloat()
@@ -791,15 +872,15 @@ class FragmentMap : CrAnimationFragment() {
                 try {
                     addAsync.get()
                     if (addAsync.isDone) {
-                        DialogNormal(context!!, "提示", "涂鸦保存成功!").show()
+                        showInformation("涂鸦保存成功!")
                         sketchEditor?.stop()
                         CrApplication.getEventBus()
                             .post(FragmentDoodle.EventDoodleAction(FragmentDoodle.EventDoodleAction.CLOSE_DRAW))
                     }
                 } catch (e: InterruptedException) {
-                    DialogNormal(context!!, "警告", e.message!!).show()
+                    showWarning(e.message!!)
                 } catch (e: ExecutionException) {
-                    DialogNormal(context!!, "警告", e.message!!).show()
+                    showWarning(e.message!!)
                 }
             })
         }
@@ -810,7 +891,7 @@ class FragmentMap : CrAnimationFragment() {
      * @param delTable FeatureTable 数据表
      */
     private fun removeAllFeatureByTable(delTable: FeatureTable) {
-        var dialog = DialogNormal(context!!, "警告", "删除后无法恢复,是否删除?")
+        var dialog = DialogNormal(CrApplication.getContext(), "警告", "删除后无法恢复,是否删除?")
         dialog.setButtonsText("是", "否")
         dialog.setListener(object : DialogNormal.DialogNormalListener {
             // todo: 2023/4/17 删除
@@ -853,7 +934,7 @@ class FragmentMap : CrAnimationFragment() {
      * @param layer FeatureLayer 图层
      */
     private fun doodleSelectFeature(layer: FeatureLayer) {
-        var dialog = DialogNormal(context!!, "警告", "删除后无法恢复,是否删除?")
+        var dialog = DialogNormal(requireContext(), "警告", "删除后无法恢复,是否删除?")
         dialog.setButtonsText("是", "否")
         dialog.setListener(object : DialogNormal.DialogNormalListener {
             override fun completion() {
@@ -865,10 +946,10 @@ class FragmentMap : CrAnimationFragment() {
                         dAsync.addDoneListener(Runnable {
                             try {
                                 if (dAsync.isDone) {
-                                    DialogNormal(context!!, "提示", "删除成功!").show()
+                                    showInformation("删除成功!")
                                 }
                             } catch (e: java.lang.IllegalArgumentException) {
-                                DialogNormal(context!!, "错误", "删除错误!").show()
+                                showError("删除错误!")
                             }
                         })
                     }
@@ -1310,7 +1391,7 @@ class FragmentMap : CrAnimationFragment() {
                         features.add(element as Feature)
                     }
                     if (features.size > 0) {
-                        var dig = DialogNormal(context!!)
+                        var dig = DialogNormal(CrApplication.getContext())
                         dig.setTitle("提示")
                         dig.setMessage("删除后将无法恢复,确定删除吗?")
                         dig.setButtonsText("删除", "取消")
@@ -1552,7 +1633,7 @@ class FragmentMap : CrAnimationFragment() {
      * 保存截图
      * @param joinCaseName String 关联的案件名称
      */
-    private fun captures(joinCaseName:String) {
+    private fun captures(joinCaseName: String) {
         // todo: 2023/8/14 显示等待框
         showLoading("初始化...")
         // todo: 2023/8/14 初始化图片信息
@@ -1582,7 +1663,7 @@ class FragmentMap : CrAnimationFragment() {
         ovLayerList.add(ovLayersXZ)
         // todo: 2023/8/14 截图-规划图
         var opNamesGH = mutableListOf<String>(
-            LAYER_NAME_GH,LAYER_NAME_CONFIG_VILLAGE,LAYER_NAME_CONFIG_TOWNS,LAYER_NAME_CASE
+            LAYER_NAME_GH, LAYER_NAME_CONFIG_VILLAGE, LAYER_NAME_CONFIG_TOWNS, LAYER_NAME_CASE
         )
         var ovLayersGH = mutableListOf<GraphicsOverlay>(gLayerIco!!)
         opNameList.add(opNamesGH)
@@ -1593,15 +1674,21 @@ class FragmentMap : CrAnimationFragment() {
                 updateLoading("保存地图状态...")
                 saveMapLayerState()
                 updateLoading("截取影像图...")
-                capturesByName(opNameList[0],ovLayerList[0],captureNames[0])
+                capturesByName(opNameList[0], ovLayerList[0], captureNames[0])
                 updateLoading("截取现状图...")
-                capturesByName(opNameList[1],ovLayerList[1],captureNames[1])
+                capturesByName(opNameList[1], ovLayerList[1], captureNames[1])
                 updateLoading("截取规划图...")
-                capturesByName(opNameList[2],ovLayerList[2],captureNames[2])
+                capturesByName(opNameList[2], ovLayerList[2], captureNames[2])
                 updateLoading("恢复地图状态...")
                 restoreMapLayerState()
                 // todo: 2023/8/14 发送截图完成事件
-                CrApplication.getEventBus().post(EventMapCapture(EventMapCapture.CaptureAction.CAPTURE_ACTION_COMPLETE,null,captureNames))
+                CrApplication.getEventBus().post(
+                    EventMapCapture(
+                        EventMapCapture.CaptureAction.CAPTURE_ACTION_COMPLETE,
+                        null,
+                        captureNames
+                    )
+                )
                 // todo: 2023/8/14 关闭等待框
                 closeLoading()
             }
@@ -1706,6 +1793,87 @@ class FragmentMap : CrAnimationFragment() {
         bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream)
     }
 
+    /**
+     * 飞行器位置超边界剧中
+     * @param longitude Double 经度
+     * @param latitude Double 纬度
+     */
+    private fun aircraftCenter(longitude:Double,latitude:Double){
+        var visiblePolygon = mapView?.visibleArea
+        var airPoint = Point(longitude,latitude,spatialReferenceWGS84)
+        var targetPoint = GeometryEngine.project(airPoint,mapView?.spatialReference) as Point
+        if(!GeometryEngine.within(targetPoint,visiblePolygon)){
+            setMapCenter(longitude,latitude,0.0)
+        }
+    }
+
+    /**
+     * 初始化订阅
+     */
+    private fun initObserver(){
+        flightControlVm.flightControlInfo.observe(requireActivity()){
+            it?.let {
+                if(it.longitude > 10 && it.latitude > 10){
+                    // todo: 2023/8/17 更新位置
+                    updateAirplaneLocation(it)
+                    // todo: 2023/8/17 更新返航点
+                    updateAirplaneHomeLocation(it)
+                    // todo: 2023/8/17 更新连接线
+                    updateAirplaneLinkLine(it)
+                }
+            }
+        }
+    }
+
+    /**
+     * 更新飞行器位置
+     * @param obj CrFlightControlInfo 飞行器信息
+     */
+    private fun updateAirplaneLocation(obj:CrFlightControlInfo){
+        // todo: 2023/8/17 更新飞行器位置
+        builderAirplaneLocation?.setXY(obj.longitude,obj.latitude)
+        graAirplaneLocation?.geometry = builderAirplaneLocation!!.toGeometry()
+        // todo: 2023/8/17 更新角度
+        symbolAirplaneLocation?.angle = obj.yaw.toFloat()
+        // todo: 2023/8/17 超边界更新
+        aircraftCenter(obj.longitude,obj.latitude)
+        // todo: 2023/8/17 更新航线
+        builderAirplaneLine?.addPoint(Point(obj.longitude,obj.latitude))
+        graAirplaneLine?.geometry = builderAirplaneLine!!.toGeometry()
+    }
+
+    /**
+     * 更新返航位置
+     * @param obj CrFlightControlInfo 飞行器信息
+     */
+    private fun updateAirplaneHomeLocation(obj:CrFlightControlInfo){
+        if(obj.isUpdateHomeLocation){
+            CrUtil.print("返航点已刷新,请留意返航位置!")
+            CrAudioUtil.getInstance().play("返航点已刷新,请留意返航位置!")
+            builderAirplaneHomeLocation?.setXY(obj.homeLongitude,obj.homeLatitude)
+            graAirplaneHomeLocation?.geometry = builderAirplaneHomeLocation!!.toGeometry()
+            // todo: 2023/8/17 如果返航点已刷新 则认为是更换了起飞位置 则重新初始化航线
+            builderAirplaneLine = PolylineBuilder(spatialReferenceWGS84)
+            builderAirplaneLine?.addPoint(Point(obj.homeLongitude,obj.homeLatitude))
+            graAirplaneLine?.geometry = builderAirplaneLine!!.toGeometry()
+            // todo: 2023/8/17 设置更新标志 否则一直更新
+            obj.isUpdateHomeLocation = false
+        }
+    }
+
+    /**
+     * 更新连接线
+     * @param obj CrFlightControlInfo 飞行器信息
+     */
+    private fun updateAirplaneLinkLine(obj:CrFlightControlInfo){
+        if(obj.isHomeLocationValid && obj.isLocationValid){
+            builderAirplaneLink = PolylineBuilder(spatialReferenceWGS84)
+            builderAirplaneLink?.addPoint(Point(obj.longitude,obj.latitude))
+            builderAirplaneLink?.addPoint(Point(obj.homeLongitude,obj.homeLatitude))
+            graAirplaneLink?.geometry = builderAirplaneLink!!.toGeometry()
+        }
+    }
+
 
     /**
      * 订阅地图事件执行动作
@@ -1806,7 +1974,7 @@ class FragmentMap : CrAnimationFragment() {
             }
             // todo: 2023/6/7 输入坐标定位
             MapAction.EventInputLocationToMap -> {
-                var dialogInput: DialogInput = DialogInput(context!!, "输入位置信息")
+                var dialogInput: DialogInput = DialogInput(requireContext(), "输入位置信息")
                 dialogInput.setButtonsText("确定", "关闭")
                 dialogInput.setHints("输入经度,例118.70687", "输入纬度,例35.218991")
                 dialogInput.setFonts(
@@ -1862,9 +2030,9 @@ class FragmentMap : CrAnimationFragment() {
      * 订阅截屏事件
      */
     @Subscribe
-    fun onCapture(event:EventMapCapture){
+    fun onCapture(event: EventMapCapture) {
         event?.let {
-            if(it.action == EventMapCapture.CaptureAction.CAPTURE_ACTION_START){
+            if (it.action == EventMapCapture.CaptureAction.CAPTURE_ACTION_START) {
                 captures(it.joinCaseName!!)
             }
         }
@@ -1885,5 +2053,15 @@ class FragmentMap : CrAnimationFragment() {
         super.onDestroy()
     }
 
+    /**
+     * 生命周期
+     * 后台转前台
+     */
+    override fun onResume() {
+        super.onResume()
+        // todo: 2023/8/17 初始化订阅
+        initObserver()
+    }
+
 
 }

+ 82 - 28
app/src/main/java/com/cr/pages/FragmentTopInfo.kt

@@ -5,8 +5,12 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.LifecycleOwner
+import com.cr.cruav.CrApplication
 import com.cr.cruav.R
 import com.cr.data.CrUtil
 import com.cr.data.DEFAULT_STR
@@ -21,7 +25,7 @@ import kotlinx.android.synthetic.main.frag_top_info.*
  * 创建日期:2023/3/8 15:52
  * 描述:大疆顶部信息视图
  */
-open class FragmentTopInfo : Fragment() {
+open class FragmentTopInfo : CrFragment() {
     // define: 2023/3/9 APP注册信息
     private val msdkRegisterVm: CrMSDKRegisterVM by activityViewModels()
 
@@ -61,6 +65,23 @@ open class FragmentTopInfo : Fragment() {
         Level.LEVEL4 to ContextUtil.getContext().getDrawable(R.drawable.dji_link_symbol6),
     )
 
+    // todo: 2023/8/17 定义控件
+    private var lblSDKVersion:TextView?=null
+    private var lblGPSCount:TextView?= null
+    private var lblRCConnection:TextView?=null
+    private var lblProductName:TextView?=null
+    private var lblIMUState:TextView?=null
+    private var lblLongitude:TextView?=null
+    private var lblLatitude:TextView?=null
+    private var lblSignal:TextView?= null
+    private var imgSignal:ImageView?=null
+    private var lblRCBattery:TextView?=null
+    private var imgRCBattery:ImageView?=null
+    private var lblFCBattery:TextView?=null
+    private var imgFCBattery:ImageView?=null
+    private var lblCompassState:TextView?=null
+
+
     /**
      * 覆写创建视图方法
      * @param inflater LayoutInflater
@@ -73,7 +94,35 @@ open class FragmentTopInfo : Fragment() {
         container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return inflater.inflate(R.layout.frag_top_info, container, false)
+        self = this
+        mainView = inflater.inflate(R.layout.frag_top_info, container, false)
+        // todo: 2023/8/17 挂载控件
+        joinControls()
+        // todo: 2023/8/17 订阅
+        initObserver()
+        return mainView
+    }
+
+    /**
+     * 关联控件
+     */
+    override fun joinControls() {
+        mainView?.let {
+            lblSDKVersion = it.findViewById(R.id.dji_sdk_version)
+            lblGPSCount = it.findViewById(R.id.dji_gps_count)
+            lblIMUState = it.findViewById(R.id.dji_imu_state)
+            lblRCConnection = it.findViewById(R.id.dji_rc_connection)
+            lblProductName = it.findViewById(R.id.dji_product_connection)
+            lblLongitude = it.findViewById(R.id.dji_gps_longitude)
+            lblLatitude = it.findViewById(R.id.dji_gps_latitude)
+            lblSignal = it.findViewById(R.id.dji_link_value)
+            imgSignal = it.findViewById(R.id.dji_link_symbol)
+            lblRCBattery = it.findViewById(R.id.dji_rc_battery_value)
+            imgRCBattery = it.findViewById(R.id.dji_rc_battery_symbol)
+            lblFCBattery = it.findViewById(R.id.dji_battery_value)
+            imgFCBattery = it.findViewById(R.id.dji_battery_symbol)
+            lblCompassState = it.findViewById(R.id.dji_compass)
+        }
     }
 
     /**
@@ -90,29 +139,30 @@ open class FragmentTopInfo : Fragment() {
      */
     override fun onResume() {
         super.onResume()
-        // todo: 2023/3/9 初始化订阅
-        initObserver()
     }
 
+
+
     /**
      * 初始化订阅
      */
     private fun initObserver() {
         // todo: 2023/3/9 订阅App注册信息
-        msdkRegisterVm.registerInfo.observe(requireActivity()) {
-            dji_sdk_version.text = it.registerInfo
+        msdkRegisterVm.registerInfo.observe(viewLifecycleOwner) {
+            lblSDKVersion?.text = it.registerInfo
         }
         // todo: 2023/3/9 订阅MSDK版本信息
-        msdkInfoVm.msdkInfo.observe(requireActivity()) {
+        msdkInfoVm.msdkInfo.observe(viewLifecycleOwner) {
             if (msdkRegisterVm.registerInfo.value?.isRegister == true) {
-                dji_sdk_version?.text = it.SDKVersion
+                lblSDKVersion?.text = it.SDKVersion
             }
         }
-
+        // todo: 2023/8/17 订阅遥控器
         observerRemoteControl()
+        // todo: 2023/8/17 订阅飞行器
         observerFlightControl()
+        // todo: 2023/8/17 订阅链路
         observerLink()
-
     }
 
     /**
@@ -120,13 +170,17 @@ open class FragmentTopInfo : Fragment() {
      */
     private fun observerRemoteControl() {
         // todo: 2023/3/9 订阅遥控器信息
-        remoteControlVm.remoteControlInfo.observe(requireActivity()) {
+        remoteControlVm.remoteControlInfo.observe(viewLifecycleOwner) {
             it?.let {
                 if (msdkRegisterVm.registerInfo.value?.isRegister == true) {
-                    dji_rc_connection.text = it.connectionInfo
-                    dji_rc_battery_value.text =
-                        resources.getString(R.string.value_battery_percent, it.batteryPercent)
-                    dji_rc_battery_symbol.setImageDrawable(
+                    lblRCConnection?.text = it.connectionInfo
+                    if(it.batteryPercent>0){
+                        lblRCBattery?.text =
+                            resources.getString(R.string.value_battery_percent, it.batteryPercent)
+                    }else{
+                        lblRCBattery?.text = DEFAULT_STR
+                    }
+                    imgRCBattery?.setImageDrawable(
                         remoteControlBatteryIcon[CrUtil.getLevel(
                             it.batteryPercent
                         )]
@@ -140,23 +194,23 @@ open class FragmentTopInfo : Fragment() {
      * 订阅飞行器信息
      */
     private fun observerFlightControl() {
-        flightControlVm.flightControlInfo.observe(requireActivity()) {
+        flightControlVm.flightControlInfo.observe(viewLifecycleOwner) {
             it?.let {
                 if (msdkRegisterVm.registerInfo.value?.isRegister == true) {
-                    dji_product_connection?.text = it.productName
+                    lblProductName?.text = it.productName
                     if (it.batteryPercent > 0) {
-                        dji_battery_value.text =
+                        lblFCBattery?.text =
                             resources.getString(R.string.value_battery_percent, it.batteryPercent)
                     } else {
-                        dji_battery_value.text = DEFAULT_STR
+                        lblFCBattery?.text = DEFAULT_STR
                     }
-                    dji_battery_symbol.setImageDrawable(flightControlBatteryIcon[CrUtil.getLevel(it.batteryPercent)])
-                    dji_gps_count.text = it.gpsCount
-                    dji_imu_state.text = it.imuState
-                    dji_compass.text = it.compassState
+                    imgFCBattery?.setImageDrawable(flightControlBatteryIcon[CrUtil.getLevel(it.batteryPercent)])
+                    lblGPSCount?.text = it.gpsCount
+                    lblIMUState?.text = it.imuState
+                    lblCompassState?.text = it.compassState
                     // todo: 2023/8/15 更新经纬度
-                    dji_gps_longitude?.text = it.longitudeStr
-                    dji_gps_latitude?.text = it.latitudeStr
+                    lblLongitude?.text = it.longitudeStr
+                    lblLatitude?.text = it.latitudeStr
                     if(!it.isConnection){
                         linkVm.reset()
                     }
@@ -169,11 +223,11 @@ open class FragmentTopInfo : Fragment() {
      * 订阅链路
      */
     private fun observerLink(){
-        linkVm.linkInfo.observe(requireActivity()){
+        linkVm.linkInfo.observe(viewLifecycleOwner){
             if (msdkRegisterVm.registerInfo.value?.isRegister == true) {
                 it?.let {
-                    dji_link_symbol?.setImageDrawable(linkSignalQualityIcon[CrUtil.getLinkSignalQuality(it.signalQuality)])
-                    dji_link_value?.text = it.frequencyBand
+                    imgSignal?.setImageDrawable(linkSignalQualityIcon[CrUtil.getLinkSignalQuality(it.signalQuality)])
+                    lblSignal?.text = it.frequencyBand
                 }
             }
         }

+ 230 - 0
app/src/main/java/com/cr/pages/FragmentUploadAction.kt

@@ -0,0 +1,230 @@
+package com.cr.pages
+
+import android.graphics.Color
+import android.os.Bundle
+import android.provider.Settings.Global
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.TextView
+import com.bigkoo.pickerview.adapter.ArrayWheelAdapter
+import com.contrarywind.listener.OnItemSelectedListener
+import com.cr.common.CrUnitManager
+import com.cr.common.DataManager
+import com.cr.cruav.CrApplication
+import com.cr.cruav.R
+import com.cr.data.CrConfig
+import com.cr.data.CrUtil
+import com.cr.models.SelModel
+import com.cr.network.NetManager
+import com.cr.network.TCPDataTask
+import com.cr.view.CrViewWheel
+import dji.v5.utils.common.ContextUtil
+import okhttp3.internal.notify
+import org.json.JSONArray
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/8/18 10:26
+ * 描述:案件上传页面
+ */
+class FragmentUploadAction:CrNavigationFragment(), View.OnClickListener {
+    // todo: 2023/8/18 控件定义
+    private var btnAsyncCaseType:Button?= null // define: 2023/8/18 同步案件类型按钮
+    private var btnAsyncCaseDesc:Button?= null // define: 2023/8/18 同步案件描述信息按钮
+    private var wheelCaseType:CrViewWheel?= null // define: 2023/8/18 案件类型选择器
+    private var wheelCaseDesc:CrViewWheel?=null // define: 2023/8/18 案件描述选择器
+    private var lblMessage:TextView?=null  // define: 2023/8/23 信息显示
+
+    // todo: 2023/8/23 变量定义
+    private var caseSubmitDescriptionList:List<SelModel>?=null // define: 2023/8/23 案件上传描述信息列表
+    private var caseTypeList:List<SelModel>?=null // define: 2023/8/24 案件类型列表
+    private var adapterCaseType:ArrayWheelAdapter<String>?= null // define: 2023/8/24 案件类型适配器
+    private var adapterCaseDesc:ArrayWheelAdapter<String>?=null // define: 2023/8/24 案件描述适配器
+    private var itemsCaseType:MutableList<String>?= null // define: 2023/8/24 案件类型数据集
+    private var itemsCaseDesc:MutableList<String>?=null // define: 2023/8/24 案件描述信息数据集
+    /**
+     * 初始化
+     * @param inflater LayoutInflater
+     * @param container ViewGroup?
+     * @param savedInstanceState Bundle?
+     * @return View?
+     */
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        self = this
+        mainView = inflater.inflate(R.layout.frag_case_upload_upload,null)
+        // todo: 2023/8/18 挂载控件
+        joinControls()
+        // todo: 2023/8/24 初始化页面
+        initPage()
+        return mainView
+    }
+
+    /**
+     * 挂载控件 覆写
+     */
+    override fun joinControls() {
+        super.joinControls()
+        mainView?.let {
+            btnAsyncCaseType = it.findViewById(R.id.btn_async_case_type)
+            btnAsyncCaseDesc = it.findViewById(R.id.btn_async_desc)
+            btnAsyncCaseType?.setOnClickListener(this)
+            btnAsyncCaseDesc?.setOnClickListener(this)
+            wheelCaseType = it.findViewById(R.id.wheel_case_type)
+            wheelCaseDesc = it.findViewById(R.id.wheel_case_desc)
+            setWheel(wheelCaseType!!,listenerWheelCaseType)
+            setWheel(wheelCaseDesc!!,listenerWheelCaseDesc)
+            lblMessage = it.findViewById(R.id.lbl_message)
+        }
+    }
+
+    /**
+     * 页面初始化
+     */
+    override fun initPage() {
+        super.initPage()
+        // todo: 2023/8/24 初始化选择器
+        itemsCaseDesc = mutableListOf()
+        adapterCaseDesc = ArrayWheelAdapter(itemsCaseDesc)
+        wheelCaseDesc?.adapter = adapterCaseDesc
+        syncLocalCaseDescription()
+
+        itemsCaseType = mutableListOf()
+        adapterCaseType = ArrayWheelAdapter(itemsCaseType)
+        wheelCaseType?.adapter = adapterCaseType
+        syncLocalCaseType()
+    }
+
+    /**
+     * 设置选择器
+     * @param wheel CrViewWheel 选择器
+     * @param listener OnItemSelectedListener 监听
+     */
+    private fun setWheel(wheel:CrViewWheel,listener: OnItemSelectedListener){
+        wheel?.setTextColorCenter(Color.YELLOW) // TODO: 4/17/21 设置选中项颜色
+        wheel?.setItemsVisibleCount(5)
+        wheel?.setTextSize(CrUtil.getDimens(R.dimen.sp_6))
+        wheel?.setTypeface(CrUtil.getFont(ContextUtil.getContext()))
+        wheel?.setCyclic(false) // TODO: 6/9/21 禁止循环
+        wheel?.setOnItemSelectedListener(listener)
+    }
+
+    /**
+     * 案件类型选择器监听
+     */
+    private val listenerWheelCaseType = OnItemSelectedListener {
+
+    }
+
+    /**
+     * 案件描述选择器监听
+     */
+    private val listenerWheelCaseDesc = OnItemSelectedListener {
+
+    }
+
+    /**
+     * 显示消息
+     * @param message String 消息内容
+     */
+    private fun setMessage(message:String){
+        mainHandler.post {
+            lblMessage?.text = "${CrUnitManager.toSystemYMDHMSDate()} $message"
+        }
+    }
+
+    /**
+     * 同步本地案件描述信息
+     */
+    private fun syncLocalCaseDescription(){
+        caseSubmitDescriptionList = DataManager.getCaseSubmitDescription()
+        itemsCaseDesc!!.clear()
+        for (model in caseSubmitDescriptionList!!) {
+            itemsCaseDesc?.add(model.name!!)
+        }
+        wheelCaseDesc?.setSelectItem(itemsCaseDesc!![0])
+    }
+
+    /**
+     * 同步本地案件类型
+     */
+    private fun syncLocalCaseType(){
+        caseTypeList = DataManager.getCaseType()
+        itemsCaseType!!.clear()
+        for (model in caseTypeList!!) {
+            itemsCaseType?.add(model.name!!)
+        }
+        wheelCaseType?.setSelectItem("违章建筑")
+    }
+
+    /**
+     * 同步案件描述信息
+     */
+    private fun asyncCaseDescription(){
+        TCPDataTask.getInstance().sendJSON(NetManager.getServerUrl("appQueryCaseDescription"),CrConfig.user!!,object:TCPDataTask.OnChangeListener{
+            // todo: 2023/8/23 成功
+            override fun onSuccess(jsonArray: JSONArray) {
+                var list = SelModel.fromJSONArray(jsonArray)
+                if(DataManager.saveCaseSubmitDescription(list!!)){
+                    setMessage("案件描述信息同步成功!")
+                    syncLocalCaseDescription()
+                }else{
+                    setMessage("案件描述信息同步成功,本地化存储失败!")
+                }
+            }
+
+            // todo: 2023/8/23 失败
+            override fun onFailed(message: String) {
+                showError(message)
+            }
+
+        },CrApplication.getContext(),"获取中...")
+    }
+
+    /**
+     * 同步案件类型信息
+     */
+    private fun asyncCaseType(){
+        TCPDataTask.getInstance().sendJSON(NetManager.getServerUrl("appQueryCaseSource"),CrConfig.user!!,object:TCPDataTask.OnChangeListener{
+            // todo: 2023/8/23 成功
+            override fun onSuccess(jsonArray: JSONArray) {
+                var list = SelModel.fromJSONArray(jsonArray)
+                if(DataManager.saveCaseType(list!!)){
+                    setMessage("案件类型同步成功!")
+                    syncLocalCaseType()
+                }else{
+                    setMessage("案件类型同步成功,本地化存储失败!")
+                }
+            }
+
+            // todo: 2023/8/23 失败
+            override fun onFailed(message: String) {
+                showError(message)
+            }
+
+        },CrApplication.getContext(),"获取中...")
+    }
+
+    /**
+     * 重写点击事件
+     * @param view View 视图
+     */
+    override fun onClick(view: View?) {
+        when(view?.id){
+            R.id.btn_async_desc->{
+                // todo: 2023/8/23 同步描述信息
+                asyncCaseDescription()
+            }
+            R.id.btn_async_case_type->{
+                // todo: 2023/8/24 同步案件类型
+                asyncCaseType()
+            }
+        }
+    }
+}

+ 14 - 0
app/src/main/java/com/cr/pages/FragmentUploadCase.kt

@@ -30,6 +30,9 @@ class FragmentUploadCase : CrNavigationFragment() {
     // todo: 2023/6/20 编辑照片页面
     private var fragmentImageEditor: FragmentImageEditor? = null
 
+    // todo: 2023/8/18 上传案件页面
+    private var fragmentUploadCaseAction:FragmentUploadAction?=null
+
     /**
      * 初始化
      * @param inflater LayoutInflater
@@ -121,6 +124,17 @@ class FragmentUploadCase : CrNavigationFragment() {
             // todo: 2023/6/20 显示页面
             showPage(fragmentImageEditor!!)
         }
+
+        // todo: 2023/8/18 案件上传
+        override fun onUploadCase(joinCase: CaseModel) {
+            nvBar?.crSetTitle(R.string.upload_case_title_main)
+            nvBar?.crSetVisible(backIsVisible = true, dismissIsVisible = false)
+            // todo: 2023/8/18 初始化页面
+            fragmentUploadCaseAction = FragmentUploadAction()
+            adapter?.addFragment(fragmentUploadCaseAction!!)
+            // todo: 2023/8/18 显示页面
+            showPage(fragmentUploadCaseAction!!)
+        }
     }
 
     /**

+ 3 - 1
app/src/main/java/com/cr/pages/FragmentUploadCaseMain.kt

@@ -33,6 +33,8 @@ class FragmentUploadCaseMain : CrNavigationFragment(), View.OnClickListener {
     interface IOperationListener {
         // todo: 2023/6/20 编辑照片
         fun onEditImage(imagePath: String)
+        // todo: 2023/8/18
+        fun onUploadCase(joinCase:CaseModel)
     }
 
     companion object {
@@ -134,7 +136,7 @@ class FragmentUploadCaseMain : CrNavigationFragment(), View.OnClickListener {
             }
             // todo: 2023/6/15 上传
             R.id.case_btn_upload -> {
-
+                if(listener != null) listener?.onUploadCase(this.joinCase!!)
             }
         }
     }

+ 43 - 0
app/src/main/java/com/cr/view/CrICON.kt

@@ -0,0 +1,43 @@
+package com.cr.view
+
+import android.content.Context
+import android.util.AttributeSet
+import com.cr.common.CrFontManager
+import com.cr.cruav.R
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/8/18 14:15
+ * 描述:图标控件
+ */
+class CrICON @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet?=null,
+) :androidx.appcompat.widget.AppCompatTextView(context,attrs){
+    /**
+     * 初始化
+     */
+    init {
+        attrs?.let {
+            var attributes = context!!.obtainStyledAttributes(it, R.styleable.CrICON)
+            if(attributes != null){
+                var font = attributes.getString(R.styleable.CrICON_cr_font)
+                if(font != null){
+                    CrFontManager.setTextView(context,this,font!!)
+                }
+            }
+        }
+    }
+
+    /**
+     * 设置字体
+     * @param fontId Int 字体资源Id
+     */
+    fun crSetFont(fontId:Int){
+        var font = context!!.resources.getString(fontId)
+        if(font != null){
+            CrFontManager.setTextView(context,this,font!!)
+        }
+    }
+}

+ 94 - 46
app/src/main/java/com/cr/viewmodel/CrFlightControlVM.kt

@@ -5,6 +5,7 @@ import com.cr.common.CrFlightControlInfo
 import com.cr.common.CrJTMManager
 import com.cr.common.CrUnitManager
 import com.cr.cruav.R
+import com.cr.data.CrUtil
 import dji.sdk.keyvalue.key.BatteryKey
 import dji.sdk.keyvalue.key.FlightControllerKey
 import dji.sdk.keyvalue.key.KeyTools
@@ -41,10 +42,15 @@ class CrFlightControlVM : CrViewModel() {
     /**
      * 计算距离
      */
-    private fun calculateDistance(){
+    private fun calculateDistance() {
         flightControlInfo.value?.let {
-            if(it.homeLongitude > 0 && it.homeLatitude>0 && it.longitude>0 && it.latitude>0){
-                val distance = CrJTMManager.calculateDistance(it.homeLongitude,it.homeLatitude,it.longitude,it.latitude)
+            if (it.homeLongitude > 0 && it.homeLatitude > 0 && it.longitude > 0 && it.latitude > 0) {
+                val distance = CrJTMManager.calculateDistance(
+                    it.homeLongitude,
+                    it.homeLatitude,
+                    it.longitude,
+                    it.latitude
+                )
                 it.homeDistance = distance
                 it.homeDistanceStr = CrUnitManager.formatLength(distance)
             }
@@ -54,50 +60,52 @@ class CrFlightControlVM : CrViewModel() {
     /**
      * 初始化监听
      */
-    override fun initListener(){
+    override fun initListener() {
         // todo: 2023/3/9 飞行器链接监听
-        FlightControllerKey.KeyConnection.create().listen(this){
+        FlightControllerKey.KeyConnection.create().listen(this) {
             it?.let {
-                if(it){
+                if (it) {
                     flightControlInfo.value?.isConnection = true
-                    var type = KeyManager.getInstance().getValue(KeyTools.createKey(ProductKey.KeyProductType),
-                        ProductType.UNKNOWN)
+                    var type = KeyManager.getInstance().getValue(
+                        KeyTools.createKey(ProductKey.KeyProductType),
+                        ProductType.UNKNOWN
+                    )
                     flightControlInfo.value?.productName = type.toString()
                     refresh(flightControlInfo)
-                }else{
+                } else {
                     flightControlInfo.value?.reset()
                     refresh(flightControlInfo)
                 }
             }
         }
         // todo: 2023/3/9 飞行器电池监听
-        BatteryKey.KeyConnection.create().listen(this){
+        BatteryKey.KeyConnection.create().listen(this) {
             it?.let {
-                if(!it){
+                if (!it) {
                     flightControlInfo.value?.batteryPercent = 0
                     refresh(flightControlInfo)
                 }
             }
         }
         // todo: 2023/3/9 飞行器电池电量百分比监听
-        BatteryKey.KeyChargeRemainingInPercent.create().listen(this){
+        BatteryKey.KeyChargeRemainingInPercent.create().listen(this) {
             it?.let {
                 flightControlInfo.value?.batteryPercent = it
                 refresh(flightControlInfo)
             }
         }
         // todo: 2023/3/9 卫星数量监听
-        FlightControllerKey.KeyGPSSatelliteCount.create().listen(this){
+        FlightControllerKey.KeyGPSSatelliteCount.create().listen(this) {
             it?.let {
                 flightControlInfo.value?.gpsCount = it.toString()
                 refresh(flightControlInfo)
             }
         }
         // todo: 2023/3/9 IMU校准监听
-        FlightControllerKey.KeyIMUCalibrationInfo.create().listen(this){
+        FlightControllerKey.KeyIMUCalibrationInfo.create().listen(this) {
             it?.let {
                 var state = it.getCalibrationState()
-                when(state){
+                when (state) {
                     IMUCalibrationState.CALIBRATING ->
                         flightControlInfo.value?.imuState = "校准中"
                     IMUCalibrationState.SUCCESSFUL ->
@@ -106,54 +114,67 @@ class CrFlightControlVM : CrViewModel() {
                         flightControlInfo.value?.imuState = "失败"
                     IMUCalibrationState.NONE ->
                         flightControlInfo.value?.imuState = "正常"
-                    else->
+                    else ->
                         flightControlInfo.value?.imuState = "未知"
                 }
                 refresh(flightControlInfo)
             }
         }
         // todo: 2023/3/14 指南针状态监听
-        FlightControllerKey.KeyCompassCalibrationStatus.create().listen(this){
+        FlightControllerKey.KeyCompassCalibrationStatus.create().listen(this) {
             it?.let {
-                when(it){
-                    CompassCalibrationState.FAILED->
-                        flightControlInfo.value?.compassState = StringUtils.getResStr(ContextUtil.getContext(),
-                            R.string.value_compass_status_failed)
-                    CompassCalibrationState.IDLE->
-                        flightControlInfo.value?.compassState = StringUtils.getResStr(ContextUtil.getContext(),
-                            R.string.value_compass_status_idle)
-                    CompassCalibrationState.SUCCEEDED->
-                        flightControlInfo.value?.compassState = StringUtils.getResStr(ContextUtil.getContext(),
-                            R.string.value_compass_status_success)
-                    CompassCalibrationState.HORIZONTAL->
-                        flightControlInfo.value?.compassState = StringUtils.getResStr(ContextUtil.getContext(),
-                            R.string.value_compass_status_horizontal)
-                    CompassCalibrationState.VERTICAL->
-                        flightControlInfo.value?.compassState = StringUtils.getResStr(ContextUtil.getContext(),
-                            R.string.value_compass_status_vertical)
-                    else->
-                        flightControlInfo.value?.compassState = StringUtils.getResStr(ContextUtil.getContext(),
-                            R.string.value_compass_status_idle)
+                when (it) {
+                    CompassCalibrationState.FAILED ->
+                        flightControlInfo.value?.compassState = StringUtils.getResStr(
+                            ContextUtil.getContext(),
+                            R.string.value_compass_status_failed
+                        )
+                    CompassCalibrationState.IDLE ->
+                        flightControlInfo.value?.compassState = StringUtils.getResStr(
+                            ContextUtil.getContext(),
+                            R.string.value_compass_status_idle
+                        )
+                    CompassCalibrationState.SUCCEEDED ->
+                        flightControlInfo.value?.compassState = StringUtils.getResStr(
+                            ContextUtil.getContext(),
+                            R.string.value_compass_status_success
+                        )
+                    CompassCalibrationState.HORIZONTAL ->
+                        flightControlInfo.value?.compassState = StringUtils.getResStr(
+                            ContextUtil.getContext(),
+                            R.string.value_compass_status_horizontal
+                        )
+                    CompassCalibrationState.VERTICAL ->
+                        flightControlInfo.value?.compassState = StringUtils.getResStr(
+                            ContextUtil.getContext(),
+                            R.string.value_compass_status_vertical
+                        )
+                    else ->
+                        flightControlInfo.value?.compassState = StringUtils.getResStr(
+                            ContextUtil.getContext(),
+                            R.string.value_compass_status_idle
+                        )
                 }
                 refresh(flightControlInfo)
             }
         }
         // todo: 2023/8/15 飞行器位置监听
-        FlightControllerKey.KeyAircraftLocation3D.create().listen(this){
+        FlightControllerKey.KeyAircraftLocation3D.create().listen(this) {
             it?.let {
                 flightControlInfo.value?.longitude = it.longitude
                 flightControlInfo.value?.latitude = it.latitude
                 flightControlInfo.value?.altitude = it.altitude
-                flightControlInfo.value?.longitudeStr = String.format("%.5f",it.longitude)
-                flightControlInfo.value?.latitudeStr = String.format("%.5f",it.latitude)
-                flightControlInfo.value?.altitudeStr = String.format("%.1f米",it.altitude)
+                flightControlInfo.value?.longitudeStr = String.format("%.5f", it.longitude)
+                flightControlInfo.value?.latitudeStr = String.format("%.5f", it.latitude)
+                flightControlInfo.value?.altitudeStr = String.format("%.1f米", it.altitude)
+                flightControlInfo.value?.isLocationValid = it.longitude > 30 && it.latitude > 10
                 // todo: 2023/8/16 计算返航距离
                 calculateDistance()
                 refresh(flightControlInfo)
             }
         }
         // todo: 2023/8/15 速度监听
-        FlightControllerKey.KeyAircraftVelocity.create().listen(this){
+        FlightControllerKey.KeyAircraftVelocity.create().listen(this) {
             it?.let {
                 flightControlInfo.value?.speedX = it.x
                 flightControlInfo.value?.speedY = it.y
@@ -162,30 +183,57 @@ class CrFlightControlVM : CrViewModel() {
             }
         }
         // todo: 2023/8/15 返航点
-        FlightControllerKey.KeyHomeLocation.create().listen(this){
+        FlightControllerKey.KeyHomeLocation.create().listen(this) {
             it?.let {
                 flightControlInfo.value?.homeLongitude = it.longitude
                 flightControlInfo.value?.homeLatitude = it.latitude
+                flightControlInfo.value?.isHomeLocationValid = it.longitude > 30 && it.latitude > 10
+                flightControlInfo.value?.isUpdateHomeLocation = false
+                // todo: 2023/8/17 返航点有效 则通过计算确定是否需要更新返航位置
+                if (flightControlInfo.value?.isHomeLocationValid == true) {
+                    var dis = CrJTMManager.calculateDistance(
+                        it.longitude,
+                        it.latitude,
+                        flightControlInfo.value?.homeOldLatitude!!,
+                        flightControlInfo.value?.homeOldLatitude!!
+                    )
+                    // todo: 2023/8/17 大于30米 则更新
+                    if(dis > 30){
+                        flightControlInfo.value?.isUpdateHomeLocation = true
+                        flightControlInfo.value?.homeOldLongitude = it.longitude
+                        flightControlInfo.value?.homeOldLatitude = it.latitude
+                    }else{
+                        flightControlInfo.value?.isUpdateHomeLocation = false
+                    }
+                }
                 // todo: 2023/8/16 计算返航距离
                 calculateDistance()
                 refresh(flightControlInfo)
             }
         }
         // todo: 2023/8/15 起飞海拔高度
-        FlightControllerKey.KeyTakeoffLocationAltitude.create().listen(this){
+        FlightControllerKey.KeyTakeoffLocationAltitude.create().listen(this) {
             it?.let {
                 flightControlInfo.value?.takeoffAltitude = it
-                flightControlInfo.value?.takeoffAltitudeStr = String.format("%.1f米",it)
+                flightControlInfo.value?.takeoffAltitudeStr = String.format("%.1f米", it)
                 refresh(flightControlInfo)
             }
         }
         // todo: 2023/8/16 返航高度
-        FlightControllerKey.KeyGoHomeHeight.create().listen(this){
+        FlightControllerKey.KeyGoHomeHeight.create().listen(this) {
             it?.let {
                 flightControlInfo.value?.homeAltitude = it
-                flightControlInfo.value?.homeAltitudeStr = String.format("%d米",it)
+                flightControlInfo.value?.homeAltitudeStr = String.format("%d米", it)
                 refresh(flightControlInfo)
             }
         }
+        // todo: 2023/8/17 飞行器姿态
+        FlightControllerKey.KeyAircraftAttitude.create().listen(this) {
+            it?.let {
+                flightControlInfo.value?.yaw = it.yaw
+                flightControlInfo.value?.roll = it.roll
+                flightControlInfo.value?.pitch = it.pitch
+            }
+        }
     }
 }

+ 1 - 1
app/src/main/java/com/cr/viewmodel/CrLinkVM.kt

@@ -77,7 +77,7 @@ class CrLinkVM :CrViewModel(){
                             R.string.value_link_frequency_band_52)
                     else->
                         linkInfo.value?.frequencyBand = StringUtils.getResStr(ContextUtil.getContext(),
-                            R.string.cr_string_default_value)
+                            R.string.default_value)
                 }
                 refresh(linkInfo)
             }

BIN
app/src/main/res/drawable/ico_air.png


BIN
app/src/main/res/drawable/ico_home.png


+ 5 - 0
app/src/main/res/drawable/shape_circle.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="@dimen/common_radius"/>
+    <solid android:color="@color/common_back_a"/>
+</shape>

+ 13 - 0
app/src/main/res/drawable/shape_trapezoid_left.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <rotate
+            android:fromDegrees="30"
+            android:pivotX="10%"
+            android:pivotY="100%">
+            <shape android:shape="rectangle">
+                <solid android:color="#7d72ff"/>
+            </shape>
+        </rotate>
+    </item>
+</layer-list>

+ 1 - 1
app/src/main/res/layout/av_login.xml

@@ -60,7 +60,7 @@
                 android:layout_height="wrap_content"
                 android:id="@+id/login_username"
                 app:crHint="@string/login_hint_username"
-                app:crLeftImg="@drawable/ico_my"/>
+                app:crLeftImg="@drawable/ico_my" />
             <com.cr.widget.CrEditTextWidget
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"

+ 9 - 10
app/src/main/res/layout/av_main.xml

@@ -13,7 +13,7 @@
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        android:background="@color/common_back"/>
+        android:background="@color/common_back_a"/>
     <!--地图容器-->
     <LinearLayout
         android:layout_width="match_parent"
@@ -26,29 +26,28 @@
         android:background="@color/cardview_shadow_start_color"/>
     <!--FPV容器-->
     <FrameLayout
-        android:layout_width="@dimen/cr_240_dp"
-        android:layout_height="@dimen/cr_200_dp"
+        android:layout_width="@dimen/cr_180_dp"
+        android:layout_height="@dimen/cr_160_dp"
         android:id="@+id/av_fragment_fpv"
         app:layout_constraintBottom_toTopOf="@id/av_main_panel_bottom"
         app:layout_constraintRight_toRightOf="parent"
         android:layout_marginBottom="@dimen/cr_6_dp"
         android:layout_marginRight="@dimen/cr_6_dp"
-        android:background="@color/common_back"/>
+        android:background="@drawable/shape_circle"/>
     <!--动态信息容器-->
     <FrameLayout
         android:layout_width="@dimen/cr_450_dp"
-        android:layout_height="@dimen/cr_150_dp"
+        android:layout_height="@dimen/cr_120_dp"
         android:id="@+id/av_fragment_dynamic_info"
         app:layout_constraintBottom_toTopOf="@id/av_main_panel_bottom"
         app:layout_constraintLeft_toLeftOf="parent"
         android:layout_marginBottom="@dimen/cr_6_dp"
-        android:layout_marginLeft="@dimen/cr_6_dp"
-        android:background="@color/common_back"/>
+        android:layout_marginLeft="@dimen/cr_6_dp"/>
     <!--底部信息栏-->
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="@dimen/common_height"
-        android:background="@color/common_back"
+        android:background="@color/common_back_a"
         android:id="@+id/av_main_panel_bottom"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
@@ -65,7 +64,7 @@
                 android:padding="@dimen/common_padding"/>
             <TextView
                 style="@style/lbl_title_main_bottom"
-                android:text="@string/cr_string_default_value"
+                android:text="@string/default_value"
                 android:textStyle="bold"
                 android:id="@+id/av_main_lbl_user"/>
         </LinearLayout>
@@ -88,7 +87,7 @@
                 android:padding="@dimen/common_padding"/>
             <TextView
                 style="@style/lbl_title_main_bottom"
-                android:text="@string/cr_string_default_value"
+                android:text="@string/default_value"
                 android:textStyle="bold"
                 android:id="@+id/av_main_lbl_server"/>
         </LinearLayout>

+ 5 - 5
app/src/main/res/layout/frag_camera_params.xml

@@ -21,7 +21,7 @@
                 android:text="@string/title_camera_iso"/>
             <TextView
                 style="@style/dji_top_text_value_style"
-                android:text="@string/cr_string_default_value"
+                android:text="@string/default_value"
                 android:id="@+id/vd_camera_iso"/>
         </LinearLayout>
         <View style="@style/view_split_v1"/>
@@ -35,7 +35,7 @@
                 android:text="@string/title_camera_speed"/>
             <TextView
                 style="@style/dji_top_text_value_style"
-                android:text="@string/cr_string_default_value"
+                android:text="@string/default_value"
                 android:id="@+id/vd_camera_speed"/>
         </LinearLayout>
         <View style="@style/view_split_v1"/>
@@ -49,7 +49,7 @@
                 android:text="@string/title_camera_focal"/>
             <TextView
                 style="@style/dji_top_text_value_style"
-                android:text="@string/cr_string_default_value"
+                android:text="@string/default_value"
                 android:id="@+id/vd_camera_focal"/>
         </LinearLayout>
         <View style="@style/view_split_v1"/>
@@ -63,7 +63,7 @@
                 android:text="@string/title_camera_ev"/>
             <TextView
                 style="@style/dji_top_text_value_style"
-                android:text="@string/cr_string_default_value"
+                android:text="@string/default_value"
                 android:id="@+id/vd_camera_ev"/>
         </LinearLayout>
         <View style="@style/view_split_v1"/>
@@ -77,7 +77,7 @@
                 android:text="@string/title_camera_photo"/>
             <TextView
                 style="@style/dji_top_text_value_style"
-                android:text="@string/cr_string_default_value"
+                android:text="@string/default_value"
                 android:id="@+id/vd_camera_photo_count"/>
         </LinearLayout>
         <View style="@style/view_split_v1"/>

+ 262 - 0
app/src/main/res/layout/frag_case_upload_upload.xml

@@ -0,0 +1,262 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/shape_back_fragment">
+    <!--上部容器-->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1">
+        <!--上部左侧容器-->
+        <LinearLayout
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:orientation="vertical">
+            <!--位置信息-->
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/cr_30_dp"
+                android:gravity="center">
+                <TextView
+                    style="@style/lbl_title_common"
+                    android:text="@string/up_longitude"/>
+                <TextView
+                    style="@style/lbl_value_common"
+                    android:text="@string/value_6"/>
+                <TextView
+                    style="@style/lbl_title_common"
+                    android:text="@string/up_latitude"
+                    android:layout_marginStart="@dimen/cr_10_dp"/>
+                <TextView
+                    style="@style/lbl_value_common"
+                    android:text="@string/value_6"/>
+                <TextView
+                    style="@style/lbl_title_common"
+                    android:text="@string/up_yaw"
+                    android:layout_marginStart="@dimen/cr_10_dp"/>
+                <TextView
+                    style="@style/lbl_value_common"
+                    android:text="@string/value_3"/>
+                <TextView
+                    style="@style/lbl_title_common"
+                    android:text="@string/up_altitude"
+                    android:layout_marginStart="@dimen/cr_10_dp"/>
+                <TextView
+                    style="@style/lbl_value_common"
+                    android:text="@string/value_3"/>
+            </LinearLayout>
+            <View style="@style/view_split_h1"/>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1">
+                <LinearLayout
+                    android:layout_width="@dimen/cr_200_dp"
+                    android:layout_height="match_parent"
+                    android:orientation="vertical"
+                    android:gravity="center_horizontal">
+                    <TextView
+                        style="@style/up_lbl_common"
+                        android:text="@string/up_join_net_case" />
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="0dp"
+                        android:layout_weight="1">
+                        <com.cr.view.CrViewWheel
+                            android:layout_width="match_parent"
+                            android:layout_height="match_parent"/>
+                    </LinearLayout>
+                    <View style="@style/view_split_h1"/>
+                    <TextView
+                        style="@style/up_lbl_common"
+                        android:text="@string/up_submit_type"/>
+                    <cn.carbs.android.segmentcontrolview.library.SegmentControlView
+                        android:layout_width="wrap_content"
+                        android:layout_height="@dimen/cr_24_dp"
+                        app:scv_FrameWidth="@dimen/cr_1_dp"
+                        app:scv_FrameCornerRadius="@dimen/cr_5_dp"
+                        app:scv_Gradient="true"
+                        app:scv_SegmentPaddingVertical="@dimen/cr_5_dp"
+                        app:scv_TextArray="@array/up_submit_type_value"
+                        app:scv_TextSize="@dimen/sp_10"
+                        app:scv_TextSelectedColor="@color/yellow"
+                        app:scv_TextNormalColor="@color/common_back"
+                        android:layout_marginTop="@dimen/cr_8_dp"
+                        android:layout_marginBottom="@dimen/cr_8_dp" />
+                    <TextView
+                        style="@style/lbl_value_common"
+                        android:text="@string/up_submit_type_description"
+                        android:textSize="@dimen/sp_8"
+                        android:layout_marginLeft="@dimen/common_margin"
+                        android:layout_marginRight="@dimen/common_margin"/>
+                    <View style="@style/view_split_h1"/>
+                    <TextView
+                        style="@style/up_lbl_common"
+                        android:text="@string/up_construct_progress"/>
+                    <cn.carbs.android.segmentcontrolview.library.SegmentControlView
+                        android:layout_width="wrap_content"
+                        android:layout_height="@dimen/cr_24_dp"
+                        app:scv_FrameWidth="@dimen/cr_1_dp"
+                        app:scv_FrameCornerRadius="@dimen/cr_5_dp"
+                        app:scv_Gradient="true"
+                        app:scv_SegmentPaddingVertical="@dimen/cr_5_dp"
+                        app:scv_TextArray="@array/up_construct_progress_value"
+                        app:scv_TextSize="@dimen/sp_10"
+                        app:scv_TextSelectedColor="@color/yellow"
+                        app:scv_TextNormalColor="@color/common_back"
+                        android:layout_marginTop="@dimen/cr_8_dp"
+                        android:layout_marginBottom="@dimen/cr_8_dp" />
+                    <TextView
+                        style="@style/lbl_value_common"
+                        android:text="@string/up_construct_progress_description"
+                        android:textSize="@dimen/sp_8"
+                        android:layout_marginLeft="@dimen/common_margin"
+                        android:layout_marginRight="@dimen/common_margin"/>
+                </LinearLayout>
+                <View style="@style/view_split_v1"/>
+                <!--图片容器-->
+                <LinearLayout
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:layout_weight="1">
+                    <com.cr.widget.CrImageBrowserWidget
+                        android:layout_width="match_parent"
+                        android:layout_height="match_parent"/>
+                </LinearLayout>
+            </LinearLayout>
+        </LinearLayout>
+        <View style="@style/view_split_v1"/>
+        <!--上部右侧容器-->
+        <LinearLayout
+            android:layout_width="@dimen/cr_160_dp"
+            android:layout_height="match_parent"
+            android:gravity="center_horizontal"
+            android:orientation="vertical">
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:layout_marginTop="@dimen/common_margin"
+                android:layout_marginBottom="@dimen/common_margin">
+                <TextView
+                    style="@style/lbl_title_common"
+                    android:text="@string/up_attribute_description"/>
+                <Button
+                    style="@style/lbl_button_common"
+                    android:text="@string/up_attribute_description_async"
+                    android:background="@drawable/btn_blue_selector"
+                    android:id="@+id/btn_async_desc"/>
+            </LinearLayout>
+            <View style="@style/view_split_h1"/>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:gravity="center">
+                <com.cr.view.CrViewWheel
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:id="@+id/wheel_case_desc"/>
+            </LinearLayout>
+            <View style="@style/view_split_h1"/>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:layout_marginTop="@dimen/common_margin"
+                android:layout_marginBottom="@dimen/common_margin">
+                <TextView
+                    style="@style/lbl_title_common"
+                    android:text="@string/up_attribute_case_type"/>
+                <Button
+                    style="@style/lbl_button_common"
+                    android:text="@string/up_attribute_case_type_async"
+                    android:background="@drawable/btn_blue_selector"
+                    android:id="@+id/btn_async_case_type"/>
+            </LinearLayout>
+            <View style="@style/view_split_h1"/>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1">
+                <com.cr.view.CrViewWheel
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:id="@+id/wheel_case_type"/>
+            </LinearLayout>
+        </LinearLayout>
+    </LinearLayout>
+    <View style="@style/view_split_h1"/>
+    <!--下部容器-->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/cr_60_dp"
+        android:orientation="vertical">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1">
+            <!--上传信息相关-->
+            <LinearLayout
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:orientation="vertical"
+                android:paddingLeft="@dimen/common_padding"
+                android:paddingRight="@dimen/common_padding">
+                <TextView
+                    style="@style/lbl_value_common"
+                    android:layout_width="match_parent"
+                    android:text="@string/default_value"
+                    android:gravity="end"
+                    android:paddingEnd="@dimen/cr_10_dp"
+                    android:paddingStart="@dimen/cr_10_dp"
+                    android:textSize="@dimen/sp_10"
+                    android:layout_marginTop="@dimen/common_margin"
+                    android:layout_marginBottom="@dimen/common_margin"/>
+                <ProgressBar
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/cr_10_dp"
+                    style="@style/Widget.AppCompat.ProgressBar.Horizontal"
+                    android:progressDrawable="@drawable/progress_bar"
+                    android:id="@+id/item_down_bar"/>
+            </LinearLayout>
+            <LinearLayout
+                android:layout_width="@dimen/cr_60_dp"
+                android:layout_height="match_parent"
+                android:gravity="center"
+                android:layout_marginLeft="@dimen/common_margin"
+                android:layout_marginRight="@dimen/common_margin"
+                android:background="@drawable/btn_red_selector"
+                android:clickable="true">
+                <com.cr.view.CrICON
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/default_a"
+                    android:textColor="@color/white"
+                    app:cr_font="@string/ico_upload"
+                    android:textSize="@dimen/sp_16"/>
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="@color/yellow"
+                    android:text="@string/up_action_submit"
+                    android:textSize="@dimen/sp_14"/>
+            </LinearLayout>
+        </LinearLayout>
+        <View style="@style/view_split_h1"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/cr_20_dp"
+            android:text="@string/default_value"
+            android:layout_gravity="center"
+            android:textSize="@dimen/sp_10"
+            android:gravity="center_vertical"
+            android:textColor="@color/yellow"
+            android:id="@+id/lbl_message"/>
+    </LinearLayout>
+</LinearLayout>

+ 18 - 16
app/src/main/res/layout/frag_dynamic_info.xml

@@ -4,11 +4,12 @@
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@drawable/shape_back_fragment">
+    android:background="@drawable/shape_circle"
+    android:clipToOutline="true">
     <!--顶部相机信息-->
     <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="@dimen/cr_40_dp"
+        android:layout_height="@dimen/cr_30_dp"
         android:orientation="horizontal">
         <LinearLayout
             style="@style/dji_camera_component">
@@ -19,7 +20,7 @@
                     android:text="@string/title_camera_iso"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"
+                    android:text="@string/default_value"
                     android:id="@+id/camera_iso"/>
             </LinearLayout>
         </LinearLayout>
@@ -33,7 +34,7 @@
                     android:text="@string/title_camera_speed"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"
+                    android:text="@string/default_value"
                     android:id="@+id/camera_speed"/>
             </LinearLayout>
         </LinearLayout>
@@ -46,7 +47,7 @@
                     android:text="@string/title_camera_focal"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"
+                    android:text="@string/default_value"
                     android:id="@+id/camera_focal"/>
             </LinearLayout>
         </LinearLayout>
@@ -59,7 +60,7 @@
                     android:text="@string/title_camera_ev"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"
+                    android:text="@string/default_value"
                     android:id="@+id/camera_ev"/>
             </LinearLayout>
         </LinearLayout>
@@ -87,7 +88,7 @@
                     android:text="@string/title_camera_photo"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"
+                    android:text="@string/default_value"
                     android:id="@+id/sd_photo_count"/>
             </LinearLayout>
         </LinearLayout>
@@ -130,7 +131,7 @@
                     android:text="@string/title_login_dji"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"
+                    android:text="@string/default_value"
                     android:id="@+id/dji_login"/>
             </LinearLayout>
         </LinearLayout>
@@ -142,13 +143,14 @@
         android:layout_weight="1">
         <!--飞行器方位-->
         <LinearLayout
-            android:layout_width="@dimen/cr_100_dp"
+            android:layout_width="@dimen/cr_80_dp"
             android:layout_height="match_parent"
             android:layout_margin="@dimen/common_margin">
             <com.cr.widget.CrCompassWidget
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"/>
         </LinearLayout>
+        <View style="@style/view_split_v1"/>
         <LinearLayout
             android:layout_width="0dp"
             android:layout_height="match_parent"
@@ -204,14 +206,14 @@
                         android:text="@string/title_takeoff_altitude"/>
                     <TextView
                         style="@style/lbl_value_common_match"
-                        android:text="@string/cr_string_default_value"
+                        android:text="@string/default_value"
                         android:id="@+id/lbl_takeoff_altitude"/>
                     <TextView
                         style="@style/lbl_title_common_match"
                         android:text="@string/title_altitude"/>
                     <TextView
                         style="@style/lbl_value_common_match"
-                        android:text="@string/cr_string_default_value"
+                        android:text="@string/default_value"
                         android:id="@+id/lbl_altitude"/>
                 </LinearLayout>
                 <View style="@style/view_split_v1"/>
@@ -226,14 +228,14 @@
                         android:text="@string/title_go_home_altitude"/>
                     <TextView
                         style="@style/lbl_value_common_match"
-                        android:text="@string/cr_string_default_value"
+                        android:text="@string/default_value"
                         android:id="@+id/lbl_home_altitude"/>
                     <TextView
                         style="@style/lbl_title_common_match"
                         android:text="@string/title_go_home_distance"/>
                     <TextView
                         style="@style/lbl_value_common_match"
-                        android:text="@string/cr_string_default_value"
+                        android:text="@string/default_value"
                         android:id="@+id/lbl_home_distance"/>
                 </LinearLayout>
             </LinearLayout>
@@ -241,10 +243,10 @@
             <!--消息-->
             <TextView
                 android:layout_width="match_parent"
-                android:layout_height="@dimen/cr_30_dp"
-                android:text="@string/cr_string_default_value"
+                android:layout_height="@dimen/cr_16_dp"
+                android:text="@string/default_value"
                 android:textColor="@color/white"
-                android:textSize="@dimen/sp_14"
+                android:textSize="@dimen/sp_10"
                 android:gravity="center"
                 android:id="@+id/lbl_message"/>
         </LinearLayout>

+ 3 - 1
app/src/main/res/layout/frag_fpv.xml

@@ -4,7 +4,9 @@
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:id="@+id/fpv_layout">
+    android:id="@+id/fpv_layout"
+    android:background="@drawable/shape_circle"
+    android:clipToOutline="true">
     <SurfaceView
         android:layout_width="match_parent"
         android:layout_height="match_parent"

+ 3 - 2
app/src/main/res/layout/frag_map.xml

@@ -4,8 +4,9 @@
     android:layout_height="match_parent"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:clipChildren="false"
-    android:clipToPadding="false">
-
+    android:clipToPadding="false"
+    android:background="@drawable/shape_circle"
+    android:clipToOutline="true">
     <com.esri.arcgisruntime.mapping.view.MapView
         android:id="@+id/map_mapView"
         android:layout_width="match_parent"

+ 8 - 8
app/src/main/res/layout/frag_top_info.xml

@@ -19,7 +19,7 @@
                 android:src="@drawable/logo_blue"/>
             <TextView
                 style="@style/dji_top_text_value_style"
-                android:text="@string/cr_string_default_value"
+                android:text="@string/default_value"
                 android:id="@+id/dji_sdk_version"/>
         </LinearLayout>
         <View style="@style/view_split_v1"/>
@@ -37,7 +37,7 @@
                     android:text="@string/title_gps"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"
+                    android:text="@string/default_value"
                     android:id="@+id/dji_gps_count"/>
             </LinearLayout>
         </LinearLayout>
@@ -56,7 +56,7 @@
                     android:text="@string/title_imu"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"
+                    android:text="@string/default_value"
                     android:id="@+id/dji_imu_state"/>
             </LinearLayout>
         </LinearLayout>
@@ -78,7 +78,7 @@
                     android:id="@+id/dji_product_connection"
                     style="@style/dji_top_text_title_style"
                     android:layout_width="wrap_content"
-                    android:text="@string/cr_string_default_value" />
+                    android:text="@string/default_value" />
             </LinearLayout>
         </LinearLayout>
         <View style="@style/view_split_v1"/>
@@ -113,7 +113,7 @@
                     android:text="@string/title_link"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"
+                    android:text="@string/default_value"
                     android:id="@+id/dji_link_value"/>
             </LinearLayout>
         </LinearLayout>
@@ -132,7 +132,7 @@
                     android:text="@string/title_flight_controller"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"
+                    android:text="@string/default_value"
                     android:id="@+id/dji_battery_value"/>
             </LinearLayout>
         </LinearLayout>
@@ -151,7 +151,7 @@
                     android:text="@string/title_remote_controller"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"
+                    android:text="@string/default_value"
                     android:id="@+id/dji_rc_battery_value"/>
             </LinearLayout>
         </LinearLayout>
@@ -169,7 +169,7 @@
                     android:text="@string/title_compass"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"
+                    android:text="@string/default_value"
                     android:id="@+id/dji_compass"/>
             </LinearLayout>
         </LinearLayout>

+ 13 - 0
app/src/main/res/values/array.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!--案件上报方式-->
+    <array name="up_submit_type_value">
+        <item>@string/up_submit_type_new</item>
+        <item>@string/up_submit_type_update</item>
+    </array>
+    <!--案件建设方式-->
+    <array name="up_construct_progress_value">
+        <item>@string/up_construct_progress_ing</item>
+        <item>@string/up_construct_progress_complete</item>
+    </array>
+</resources>

+ 1 - 0
app/src/main/res/values/colors.xml

@@ -12,6 +12,7 @@
     
     <color name="title">#FFd4f12c</color>
     <color name="common_back">#0a3474</color>
+    <color name="common_back_a">#E00a3474</color>
 
     <!--登录页面相关-->
     <color name="login_txt_color">#0099ff</color>

+ 27 - 3
app/src/main/res/values/strings.xml

@@ -5,7 +5,8 @@
     <string name="registered">Cr</string>
 
     <!--默认字符串显示-->
-    <string name="cr_string_default_value">N/A</string>
+    <string name="default_value">N/A</string>
+    <string name="default_a">A</string>
     <string name="title_compass" translatable="false">指南针</string>
     <string name="title_remote_controller" translatable="false">遥控器</string>
     <string name="title_flight_controller" translatable="false">飞行器</string>
@@ -28,7 +29,7 @@
     <string name="title_camera_photo" translatable="false">拍照数量</string>
     <string name="title_camera_video" translatable="false">视频时长</string>
     <string name="value_camera_video" translatable="false">00:00:00</string>
-    <string name="title_login_dji" translatable="false">大疆登录</string>
+    <string name="title_login_dji" translatable="false">UAV账号登录</string>
     <!--信号质量-->
     <string name="value_link_level_1" translatable="false">优</string>
     <string name="value_link_level_2" translatable="false">良</string>
@@ -83,7 +84,7 @@
     <string name="nv_title_image_editor">图片编辑</string>
     <string name="nv_title_set_ip_and_com">设置IP和COM</string>
     <string name="nv_title_dji_initialize">飞行器自检</string>
-    <string name="nv_title_simulator">大疆模拟器</string>
+    <string name="nv_title_simulator">UAV模拟器</string>
 
     <!--对话框-->
     <string name="dig_normal_btn_ok">确定</string>
@@ -171,6 +172,28 @@
 
     <!-- 说明 -->
     <string name="des_head">说明</string>
+    
+    <!--案件上传页面-->
+    <string name="up_longitude">经度</string>
+    <string name="up_latitude">纬度</string>
+    <string name="up_yaw">方位</string>
+    <string name="up_altitude">高度</string>
+    <string name="value_6">000.000000</string>
+    <string name="value_3">000.000</string>
+    <string name="up_join_net_case">关联的网络案件</string>
+    <string name="up_submit_type">案件上报方式</string>
+    <string name="up_submit_type_description">说明:当选择【新增案件】时,必须挂绘制的案件图斑,否则上传失败,选择【更新案件】时,必须选择对应的网络案件。</string>
+    <string name="up_submit_type_new">新增案件</string>
+    <string name="up_submit_type_update">更新案件</string>
+    <string name="up_construct_progress">案件建设程度</string>
+    <string name="up_construct_progress_description">说明:表示案件的建设情况。</string>
+    <string name="up_construct_progress_ing">在建</string>
+    <string name="up_construct_progress_complete">完工</string>
+    <string name="up_attribute_description">案件描述</string>
+    <string name="up_attribute_description_async">同步描述信息</string>
+    <string name="up_attribute_case_type">案件类型</string>
+    <string name="up_attribute_case_type_async">同步案件类型</string>
+    <string name="up_action_submit">上传</string>
 
     <!--字体-->
     <string name="ico_nv_left" translatable="false">&#xe60b;</string>
@@ -179,6 +202,7 @@
     <string name="ico_ip" translatable="false">&#xe632;</string>
     <string name="ico_com" translatable="false">&#xe8b0;</string>
     <string name="ico_server" translatable="false">&#xe821;</string>
+    <string name="ico_upload">&#xec23;</string>
 
     <string name="ico_clear">&#xe69e;</string>
     <string name="ico_save">&#xe8bb;</string>

+ 20 - 1
app/src/main/res/values/themes.xml

@@ -232,6 +232,16 @@
         <item name="android:layout_marginRight">@dimen/common_margin</item>
         <item name="android:textColor">@color/white</item>
     </style>
+    <!--通用按钮样式-->
+    <style name="lbl_button_common">
+        <item name="background">@drawable/btn_red_selector</item>
+        <item name="android:layout_height">@dimen/cr_30_dp</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:paddingLeft">@dimen/cr_8_dp</item>
+        <item name="android:paddingRight">@dimen/cr_8_dp</item>
+        <item name="android:textSize">@dimen/sp_12</item>
+        <item name="android:textColor">@color/white</item>
+    </style>
 
     <!--主页面底部信息框文字样式-->
     <style name="lbl_title_main_bottom" parent="lbl_title_common">
@@ -386,7 +396,11 @@
         <item name="android:textSize">@dimen/sp_10</item>
         <item name="android:layout_weight">1</item>
     </style>
-
+    <!--案件上传页面title样式-->
+    <style name="up_lbl_common" parent="lbl_title_common">
+        <item name="android:layout_marginBottom">@dimen/cr_5_dp</item>
+        <item name="android:layout_marginTop">@dimen/cr_5_dp</item>
+    </style>
     <style name="Theme">Theme.NoTitleBar.Fullscreen</style>
 
     <!-- ConstraintLayout 布局中通用内容 上下占满 -->
@@ -428,4 +442,9 @@
         <attr name="speedTitle" format="string"/>
         <attr name="speedProgress" format="integer"/>
     </declare-styleable>
+
+    <!--图标控件属性-->
+    <declare-styleable name="CrICON">
+        <attr name="cr_font" format="string"></attr>
+    </declare-styleable>
 </resources>

+ 1 - 1
gradle.properties

@@ -6,7 +6,7 @@
 # http://www.gradle.org/docs/current/userguide/build_environment.html
 # Specifies the JVM arguments used for the daemon process.
 # The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+org.gradle.jvmargs=-Xmx8192m -Dfile.encoding=UTF-8
 # When configured, Gradle will run in incubating parallel mode.
 # This option should only be used with decoupled projects. More details, visit
 # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects