Selaa lähdekoodia

1、航点上传及航点管理器页面完成

不会爬树的猴 1 vuosi sitten
vanhempi
commit
e3ed1be6ce
36 muutettua tiedostoa jossa 1301 lisäystä ja 263 poistoa
  1. 1 1
      .idea/deploymentTargetDropDown.xml
  2. 52 0
      app/src/main/java/com/cr/adapter/CrWaypointDetailAdapter.kt
  3. 103 0
      app/src/main/java/com/cr/common/CrDialogManager.kt
  4. 155 0
      app/src/main/java/com/cr/common/CrInterfaceManager.kt
  5. 9 0
      app/src/main/java/com/cr/common/CrUnitManager.kt
  6. 165 35
      app/src/main/java/com/cr/common/DataManager.kt
  7. 8 13
      app/src/main/java/com/cr/cruav/AvLogin.kt
  8. 18 6
      app/src/main/java/com/cr/cruav/AvMain.kt
  9. 7 44
      app/src/main/java/com/cr/cruav/CrActivity.kt
  10. 17 4
      app/src/main/java/com/cr/dialog/DialogNormal.kt
  11. 53 0
      app/src/main/java/com/cr/models/AircraftLineCountModel.kt
  12. 58 0
      app/src/main/java/com/cr/models/AircraftWaypointModel.kt
  13. 21 6
      app/src/main/java/com/cr/models/CompletionModel.kt
  14. 2 12
      app/src/main/java/com/cr/models/SetItemModel.kt
  15. 68 14
      app/src/main/java/com/cr/network/TCPDataTask.kt
  16. 6 30
      app/src/main/java/com/cr/pages/CrFragment.kt
  17. 146 0
      app/src/main/java/com/cr/pages/FragmentAirLineManager.kt
  18. 156 0
      app/src/main/java/com/cr/pages/FragmentInformationBar.kt
  19. 14 0
      app/src/main/java/com/cr/pages/FragmentSet.kt
  20. 14 33
      app/src/main/java/com/cr/pages/FragmentSetMain.kt
  21. 2 2
      app/src/main/java/com/cr/pages/FragmentSimulator.kt
  22. 0 3
      app/src/main/java/com/cr/pages/FragmentUploadAction.kt
  23. 1 1
      app/src/main/java/com/cr/viewmodel/CrCameraVM.kt
  24. 0 1
      app/src/main/java/com/cr/viewmodel/CrLinkVM.kt
  25. BIN
      app/src/main/res/drawable/ico_error.png
  26. BIN
      app/src/main/res/drawable/ico_information.png
  27. BIN
      app/src/main/res/drawable/ico_waning.png
  28. 9 50
      app/src/main/res/layout/av_main.xml
  29. 3 2
      app/src/main/res/layout/dig_normal.xml
  30. 68 0
      app/src/main/res/layout/frag_air_line_manager.xml
  31. 51 0
      app/src/main/res/layout/frag_infomation_bar.xml
  32. 1 5
      app/src/main/res/layout/frag_layer_control.xml
  33. 30 0
      app/src/main/res/layout/item_waypoint_detail.xml
  34. 23 0
      app/src/main/res/values/strings.xml
  35. 39 0
      app/src/main/res/values/themes.xml
  36. 1 1
      build.gradle

+ 1 - 1
.idea/deploymentTargetDropDown.xml

@@ -12,7 +12,7 @@
         </deviceKey>
       </Target>
     </runningDeviceTargetSelectedWithDropDown>
-    <timeTargetWasSelectedWithDropDown value="2023-09-13T00:36:24.238874Z" />
+    <timeTargetWasSelectedWithDropDown value="2023-09-20T05:46:38.221795Z" />
     <runningDeviceTargetsSelectedWithDialog>
       <Target>
         <type value="RUNNING_DEVICE_TARGET" />

+ 52 - 0
app/src/main/java/com/cr/adapter/CrWaypointDetailAdapter.kt

@@ -0,0 +1,52 @@
+package com.cr.adapter
+
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import com.cr.cruav.R
+import com.cr.models.AircraftLineCountModel
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/9/19 14:31
+ * 描述:航点明细适配器
+ */
+class CrWaypointDetailAdapter @JvmOverloads constructor(
+    context:Context,
+    dataList:MutableList<AircraftLineCountModel.WaypointDetailModel>
+) : CrAdapter<AircraftLineCountModel.WaypointDetailModel>(context,dataList) {
+    companion object{
+        class ViewHolder{
+            var lblCount:TextView?= null // define: 2023/9/19 数量
+            var lblDate:TextView?= null // define: 2023/9/19 日期
+        }
+    }
+
+    /**
+     * 重写获取视图方法
+     * @param position Int 索引位置
+     * @param convertView View?  视图
+     * @param p2 ViewGroup? 视图组
+     * @return View? 视图
+     */
+    override fun getView(position: Int, convertView: View?, p2: ViewGroup?): View? {
+        var holder: ViewHolder?=null
+        var view = convertView
+        if(convertView == null){
+            holder = ViewHolder()
+            view = inflater?.inflate(R.layout.item_waypoint_detail,null)
+            holder.lblCount = view?.findViewById(R.id.lbl_count)
+            holder.lblDate = view?.findViewById(R.id.lbl_date)
+            view?.tag = holder
+        }else{
+            holder = view?.tag as ViewHolder
+        }
+        // todo: 2023/9/19 获取数据
+        var model = dataList!![position]
+        holder.lblDate?.text = model.date
+        holder.lblCount?.text = "${model.count}个"
+        return view
+    }
+}

+ 103 - 0
app/src/main/java/com/cr/common/CrDialogManager.kt

@@ -0,0 +1,103 @@
+package com.cr.common
+
+import android.os.Handler
+import android.os.Looper
+import com.cr.cruav.CrApplication
+import com.cr.cruav.R
+import com.cr.dialog.DialogNormal
+import com.cr.models.CompletionModel
+import com.cr.models.ICompletion
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/9/20 14:27
+ * 描述:对话框管理器
+ */
+class CrDialogManager {
+    // define: 2023/9/20 主线程
+    private var mainHandler = Handler(Looper.getMainLooper())
+
+    /**
+     * 单例必备
+     */
+    object InstanceHelper{
+        var self = CrDialogManager()
+    }
+
+    companion object{
+        /**
+         * 获取单例
+         * @return CrDialogManager
+         */
+        fun getInstance() = InstanceHelper.self
+    }
+
+    /**
+     * 显示警告消息
+     * @param warning String 消息内容
+     */
+    fun showWarning(warning: String) {
+        mainHandler.post {
+            val dialog = DialogNormal(CrApplication.getContext(), "警告", warning)
+            dialog.setHeadImage(R.drawable.ico_waning)
+            dialog.show()
+        }
+    }
+
+    /**
+     * 显示错误消息
+     * @param error String 错误消息
+     */
+    fun showError(error: String) {
+        mainHandler.post{
+            val dialog = DialogNormal(CrApplication.getContext(), "错误", error)
+            dialog.setHeadImage(R.drawable.ico_error)
+            dialog.show()
+        }
+    }
+
+    /**
+     * 显示提示消息
+     * @param information String 提示信息
+     */
+    fun showInformation(information: String) {
+        mainHandler.post {
+            val dialog = DialogNormal(CrApplication.getContext(), "提示", information)
+            dialog.setHeadImage(R.drawable.ico_information)
+            dialog.show()
+        }
+    }
+
+    /**
+     * 确认对话框
+     * @param message String 显示的消息内容
+     * @param actionButtonContent Array<String> 按钮文字数组 大小必须是2
+     * @param callback ICompletion<String> 回调 可以传null
+     */
+     fun showConfirm(message:String,actionButtonContent:Array<String>,callback: ICompletion<String>?){
+        if(actionButtonContent.size != 2) return
+        mainHandler.post {
+            var dialog = DialogNormal(CrApplication.getContext(),"确认",message)
+            dialog.setHeadImage(R.drawable.ico_information)
+            dialog.setButtonsText(actionButtonContent[0],actionButtonContent[1])
+            dialog.setListener(object:DialogNormal.DialogNormalListener{
+                // todo: 2023/8/15 确认操作
+                override fun completion() {
+                    callback?.let {
+                        it.onCompletion(CompletionModel(true,""))
+                    }
+                }
+
+                // todo: 2023/8/15 关闭操作
+                override fun close() {
+                    callback?.let {
+                        it.onCompletion(CompletionModel(false,""))
+                    }
+                }
+
+            })
+            dialog.show()
+        }
+    }
+}

+ 155 - 0
app/src/main/java/com/cr/common/CrInterfaceManager.kt

@@ -0,0 +1,155 @@
+package com.cr.common
+
+import android.os.Handler
+import android.os.Looper
+import com.cr.cruav.CrApplication
+import com.cr.data.CrUtil
+import com.cr.dialog.DialogNormal
+import com.cr.models.AircraftWaypointModel
+import com.cr.models.CompletionModel
+import com.cr.models.ICompletion
+import com.cr.models.UserModel
+import com.cr.network.NetManager
+import com.cr.network.TCPDataTask
+import org.json.JSONArray
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/9/20 09:04
+ * 描述:接口管理(所有与服务器的交互均放置该管理类中,统一管理)
+ */
+class CrInterfaceManager {
+    private var mainHandler = Handler(Looper.getMainLooper())
+
+    /**
+     * 单例必备
+     */
+    object InstanceHelper {
+        var self = CrInterfaceManager()
+    }
+
+    /**
+     * 初始化
+     */
+    init {
+        this.mainHandler = Handler(Looper.getMainLooper())
+    }
+
+    /**
+     * 静态方法集合
+     */
+    companion object {
+        /**
+         * 获取实例
+         * @return CrInterfaceManager
+         */
+        fun getInstance() = InstanceHelper.self
+    }
+
+    /**
+     * 获取API接口访问的URL地址
+     * @param subUrl String 子URL地址
+     * @return String 完整的URL地址
+     */
+    private fun getNetworkUrl(subUrl: String): String {
+        return NetManager.getServerUrl(subUrl)
+    }
+
+    /**
+     * 显示错误信息
+     * @param error String 错误消息
+     */
+    private fun showError(error: String) {
+        mainHandler.post {
+            DialogNormal(CrApplication.getContext(), "错误", error).show()
+        }
+    }
+
+    /**
+     * 用户登录认证
+     * @param user UserModel 登录账号
+     * @param callback ICompletion<UserModel>? 回调
+     */
+    fun userLogin(user: UserModel, callback: ICompletion<UserModel>?) {
+        TCPDataTask.getInstance().sendJSON(
+            getNetworkUrl("appQueryUser"),
+            user,
+            object : TCPDataTask.IChangeCallback {
+                // todo: 2023/4/10 成功
+                override fun onSuccess(jsonArray: JSONArray) {
+                    var resUser = UserModel.toModel(jsonArray.optString(0))
+                    callback?.let { it.onCompletion(CompletionModel(true, resUser)) }
+                }
+
+                // todo: 2023/4/10 失败
+                override fun onFailed(message: String) {
+                    showError(message)
+                }
+            },"账号登录认证中..."
+        )
+    }
+
+    /**
+     * 上传航点数据
+     * @param ptList List<AircraftWaypointModel>
+     * @param callback ICompletion<List<AircraftWaypointModel>>?
+     */
+    fun uploadAirlineWaypoint(ptList:List<AircraftWaypointModel>,callback: ICompletion<List<AircraftWaypointModel>>?){
+        // todo: 2023/9/20 组装JSON字符串
+        var jsonData = JSONManager.transformToString(ptList)
+        // todo: 2023/9/20 上传
+        TCPDataTask.getInstance().sendJSON(
+            getNetworkUrl("appSubmitPath"),
+            jsonData,
+            object : TCPDataTask.IChangeCallback {
+                // todo: 2023/4/10 成功
+                override fun onSuccess(jsonArray: JSONArray) {
+                    var resList = mutableListOf<AircraftWaypointModel>()
+                    for(index in 0 until jsonArray.length()){
+                        resList.add(AircraftWaypointModel.toModel(jsonArray.optJSONObject(index).toString())!!)
+                    }
+                    callback?.let { it.onCompletion(CompletionModel(true, resList)) }
+                }
+
+                // todo: 2023/4/10 失败
+                override fun onFailed(message: String) {
+                    showError(message)
+                }
+            }, "航点数据上传中..."
+        )
+    }
+
+    /**
+     * 上传航点数据(不显示等待消息)
+     * @param ptList List<AircraftWaypointModel>
+     * @param callback ICompletion<List<AircraftWaypointModel>>?
+     */
+    fun uploadAirlineWaypointNoLoading(
+        ptList:List<AircraftWaypointModel>,
+        callback: ICompletion<List<AircraftWaypointModel>>?
+    ){
+        // todo: 2023/9/20 组装JSON字符串
+        var jsonData = JSONManager.transformToString(ptList)
+        // todo: 2023/9/20 上传
+        TCPDataTask.getInstance().sendJSON(
+            getNetworkUrl("appSubmitPath"),
+            jsonData,
+            object : TCPDataTask.IChangeCallback {
+                // todo: 2023/4/10 成功
+                override fun onSuccess(jsonArray: JSONArray) {
+                    var resList = mutableListOf<AircraftWaypointModel>()
+                    for(index in 0 until jsonArray.length()){
+                        resList.add(AircraftWaypointModel.toModel(jsonArray.optJSONObject(index).toString())!!)
+                    }
+                    callback?.let { it.onCompletion(CompletionModel(true, resList)) }
+                }
+
+                // todo: 2023/4/10 失败
+                override fun onFailed(message: String) {
+                    callback?.let { it.onCompletion(CompletionModel(false,null,message)) }
+                }
+            }
+        )
+    }
+}

+ 9 - 0
app/src/main/java/com/cr/common/CrUnitManager.kt

@@ -230,5 +230,14 @@ class CrUnitManager {
             wheel.setOnItemSelectedListener(listener)
             wheel.setDividerColor(CrColorManager.getColor(R.color.cadetblue))
         }
+
+        /**
+         * 获取资源对应的内容
+         * @param resourceId Int
+         * @return String
+         */
+        fun getStringFromResource(resourceId:Int):String{
+            return CrApplication.getContext().getString(resourceId)
+        }
     }
 }

+ 165 - 35
app/src/main/java/com/cr/common/DataManager.kt

@@ -1,6 +1,5 @@
 package com.cr.common
 
-import com.cr.data.CrUtil
 import com.cr.map.CaseModel
 import com.cr.map.LayerConfigModel
 import com.cr.map.LayerModel
@@ -15,6 +14,7 @@ import com.cr.models.*
 class DataManager {
     // todo: 2023/4/3 静态方法及属性封装
     companion object {
+        private const val TABLE_AIR_LINE: String = "AIRLINE"  // define: 2023/9/19 航线表
 
         /**
          * 获取网络服务连接信息
@@ -186,14 +186,18 @@ class DataManager {
          * @param model CaseModel 案件点模型
          * @param callback iCompletion 完成回调
          */
-        fun appAppendImages(model:CaseModel,callback:ICompletion<String>){
+        fun appAppendImages(model: CaseModel, callback: ICompletion<String>) {
             // todo: 2023/6/19 先查询是否已经存在
-            var SQL = String.format("select * from WAYIMAGES where wayid='%s' and imgname='%s'",model.name,model.imgName)
+            var SQL = String.format(
+                "select * from WAYIMAGES where wayid='%s' and imgname='%s'",
+                model.name,
+                model.imgName
+            )
             var queryList = DatabaseAppUAVManager.getInstance().query(SQL)
-            if(queryList.isNotEmpty()){
-                if(callback != null) callback?.onCompletion(CompletionModel(false,"该照片已经存储!"))
-            }else{
-                var values = HashMap<String,String>()
+            if (queryList.isNotEmpty()) {
+                if (callback != null) callback?.onCompletion(CompletionModel(false, "该照片已经存储!"))
+            } else {
+                var values = HashMap<String, String>()
                 values["wayid"] = model!!.name!!
                 values["imgname"] = model!!.imgName!!
                 values["lat"] = model!!.latitude!!.toString()
@@ -202,11 +206,11 @@ class DataManager {
                 values["ang"] = model!!.angle!!.toString()
                 values["isdown"] = "0"
                 values["date"] = model!!.date!!.toString()
-                var res = DatabaseAppUAVManager.getInstance().insert("WAYIMAGES",values)
-                if(res){
-                    if(callback != null) callback?.onCompletion(CompletionModel(true,""))
-                }else{
-                    if(callback != null) callback?.onCompletion(CompletionModel(false,"该照片已经存储!"))
+                var res = DatabaseAppUAVManager.getInstance().insert("WAYIMAGES", values)
+                if (res) {
+                    if (callback != null) callback?.onCompletion(CompletionModel(true, ""))
+                } else {
+                    if (callback != null) callback?.onCompletion(CompletionModel(false, "该照片已经存储!"))
                 }
             }
         }
@@ -216,17 +220,22 @@ class DataManager {
          * @param caseId String 案件Id
          * @param callback iCompletion<List<String>> 回调
          */
-        fun appQueryImages(caseId:String,callback: ICompletion<List<String>>){
-            var querySQL = String.format("select * from WAYIMAGES where wayid='%s'",caseId)
+        fun appQueryImages(caseId: String, callback: ICompletion<List<String>>) {
+            var querySQL = String.format("select * from WAYIMAGES where wayid='%s'", caseId)
             var queryList = DatabaseAppUAVManager.getInstance().query(querySQL)
-            if(queryList.isNotEmpty()){
+            if (queryList.isNotEmpty()) {
                 var resList = mutableListOf<String>()
-                for(map in queryList){
+                for (map in queryList) {
                     resList.add(map["imgname"].toString())
                 }
-                if(callback != null) callback.onCompletion(CompletionModel(true,resList))
-            }else{
-                if(callback != null) callback.onCompletion(CompletionModel(false, mutableListOf("未查询到任何信息!")))
+                if (callback != null) callback.onCompletion(CompletionModel(true, resList))
+            } else {
+                if (callback != null) callback.onCompletion(
+                    CompletionModel(
+                        false,
+                        mutableListOf("未查询到任何信息!")
+                    )
+                )
             }
         }
 
@@ -235,14 +244,15 @@ class DataManager {
          * @param dataList List<SelModel> 快捷信息列表
          * @return Boolean 存储是否成功
          */
-        fun saveCaseSubmitDescription(dataList:List<SelModel>):Boolean{
+        fun saveCaseSubmitDescription(dataList: List<SelModel>): Boolean {
             var isReturn = true;
-            DatabaseAppUAVManager.getInstance().delete("CASEKjInput","")
-            for (model in dataList){
-                var value:HashMap<String,String> = hashMapOf()
+            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)
+                isReturn =
+                    isReturn && DatabaseAppUAVManager.getInstance().insert("CASEKjInput", value)
             }
             return isReturn
         }
@@ -251,12 +261,12 @@ class DataManager {
          * 获取案件提报快捷描述信息
          * @return List<SelModel> 快捷描述信息列表
          */
-        fun getCaseSubmitDescription():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"]!!))
+            for (map in qList) {
+                resList.add(SelModel(map["kjid"]!!, map["kjnr"]!!))
             }
             return resList
         }
@@ -266,14 +276,14 @@ class DataManager {
          * @param dataList List<SelModel> 案件类型列表
          * @return Boolean
          */
-        fun saveCaseType(dataList:List<SelModel>):Boolean{
+        fun saveCaseType(dataList: List<SelModel>): Boolean {
             var isReturn = true;
-            DatabaseAppUAVManager.getInstance().delete("CASEType","")
-            for (model in dataList){
-                var value:HashMap<String,String> = hashMapOf()
+            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)
+                isReturn = isReturn && DatabaseAppUAVManager.getInstance().insert("CASEType", value)
             }
             return isReturn
         }
@@ -282,14 +292,134 @@ class DataManager {
          * 获取案件类型快捷描述信息
          * @return List<SelModel> 类型信息列表
          */
-        fun getCaseType():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"]!!))
+            for (map in qList) {
+                resList.add(SelModel(map["lxid"]!!, map["lxname"]!!))
             }
             return resList
         }
+
+        /**
+         * 保存航线点
+         * @param model CrAircraftLineModel 航线点模型
+         * @return Int 返回-1表示失败 其他表示保存的Id标识
+         */
+        fun saveAircraftLine(model: AircraftWaypointModel): Int {
+            var resInt: Int = -1
+            var values: HashMap<String, String> = hashMapOf()
+            values["date"] = model.createDate
+            values["lng"] = model.longitude
+            values["lat"] = model.latitude
+            values["alt"] = model.altitude
+            values["angle"] = model.angle
+            values["type"] = model.type
+            values["flag"] = model.userId
+            var isInsert = DatabaseAppUAVManager.getInstance().insert(TABLE_AIR_LINE, values)
+            if (isInsert) {
+                var sql = String.format(
+                    "SELECT max(ID) maxid FROM %s where FLAG='%s'",
+                    TABLE_AIR_LINE, model.userId
+                );
+                var qList = DatabaseAppUAVManager.getInstance().query(sql)
+                resInt = qList[0]["maxid"]!!.toInt()
+            }
+            return resInt
+        }
+
+        /**
+         * 查询指定用户的航线统计信息
+         * @param userId String 用户Id
+         * @return AircraftLineCountModel 统计信息
+         */
+        fun queryAircraftStatisticsInfo(userId: String): AircraftLineCountModel {
+            var resModel = AircraftLineCountModel()
+            // todo: 2023/9/19 查询航点总数
+            var sql = String.format(
+                "select count(*) count from %s where flag='%s'",
+                TABLE_AIR_LINE,
+                userId
+            )
+            var qList = DatabaseAppUAVManager.getInstance().query(sql)
+            resModel.waypointAllCount = qList[0]["count"]!!.toInt()
+            // todo: 2023/9/19 查询待传航点数
+            sql = String.format(
+                "select count(*) count from %s where flag='%s' and type='0'",
+                TABLE_AIR_LINE, userId
+            )
+            qList = DatabaseAppUAVManager.getInstance().query(sql)
+            resModel.waitUploadWaypointCount = qList[0]["count"]!!.toInt()
+            // todo: 2023/9/19 查询已上传航点数
+            sql = String.format(
+                "select count(*) count from %s where flag='%s' and type='1'",
+                TABLE_AIR_LINE, userId
+            )
+            qList = DatabaseAppUAVManager.getInstance().query(sql)
+            resModel.yesUploadWaypointCount = qList[0]["count"]!!.toInt()
+            // todo: 2023/9/19 查询统计信息
+            sql = String.format(
+                "SELECT date,COUNT(*) count from (select date(date) date from %s WHERE FLAG = '%s' and TYPE = '0') GROUP BY date",
+                TABLE_AIR_LINE, userId
+            )
+            qList = DatabaseAppUAVManager.getInstance().query(sql)
+            for (data in qList) {
+                resModel.appendWaypointDetailInfo(data["date"]!!, data["count"]!!.toInt())
+            }
+            return resModel
+        }
+
+        /**
+         * 查询所有待上传航点数据
+         * @param userId String 用户Id
+         * @return List<AircraftWaypointModel>
+         */
+        fun queryAllWaitUploadWaypoint(userId:String):List<AircraftWaypointModel>{
+            val sql = String.format("select * from %s where flag='%s' and type='0'", TABLE_AIR_LINE,userId)
+            val qList = DatabaseAppUAVManager.getInstance().query(sql)
+            var resModel = mutableListOf<AircraftWaypointModel>()
+            for (map in qList){
+                var model = AircraftWaypointModel(userId)
+                model.ptId = map["id"]!!
+                model.longitude = map["lng"]!!
+                model.latitude = map["lat"]!!
+                model.altitude = map["alt"]!!
+                model.angle = map["angle"]!!
+                resModel.add(model)
+            }
+            return resModel
+        }
+
+        /**
+         * 更新指定航点状态
+         * @param userId String 用户Id
+         * @param ptList List<AircraftWaypointModel> 航点集合
+         * @return Boolean
+         */
+        fun updateWaypointState(userId: String,ptList:List<AircraftWaypointModel>):Boolean{
+            // todo: 2023/9/20 更新的Id集合
+            var arrayInt = mutableListOf<Int>()
+            for (pt in ptList){
+                arrayInt.add(pt.ptId.toInt())
+            }
+            // todo: 2023/9/20 组合条件
+            val strWhere = "flag = '${userId}' and id in (${arrayInt.joinToString(",")})"
+            // todo: 2023/9/20 更新内容
+            var valueMap = HashMap<String,String>()
+            valueMap["type"] = "1"
+            // todo: 2023/9/20 更新
+            return DatabaseAppUAVManager.getInstance().update(TABLE_AIR_LINE,valueMap,strWhere)
+        }
+
+        /**
+         * 删除航点信息
+         * @param userId String 用户Id
+         * @return Boolean 删除是否成功
+         */
+        fun deleteAircraftPoint(userId: String): Boolean {
+            val sqlWhere = String.format("flag='%s'", userId)
+            return DatabaseAppUAVManager.getInstance().delete(TABLE_AIR_LINE,sqlWhere)
+        }
     }
 }

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

@@ -19,6 +19,8 @@ import com.cr.data.CrUtil.Companion.onStart
 import com.cr.dialog.DialogNormal
 import com.cr.dialog.DialogNormal.DialogNormalListener
 import com.cr.event.EventFragmentBarAction
+import com.cr.models.CompletionModel
+import com.cr.models.ICompletion
 import com.cr.models.UserModel
 import com.cr.network.NetManager
 import com.cr.network.TCPDataTask
@@ -178,22 +180,15 @@ class AvLogin : CrActivity(), OnClickListener {
     private fun login(userName: String, password: String) {
         var user = UserModel(userName, password)
         // todo: 2023/4/10 向服务器发起认证消息
-        TCPDataTask.getInstance().sendJSON(
-            NetManager.getServerUrl("appQueryUser"),
-            user,
-            object : TCPDataTask.IChangeCallback {
-                // todo: 2023/4/10 成功
-                override fun onSuccess(jsonArray: JSONArray) {
-                    CrConfig.user = UserModel.toModel(jsonArray.optString(0))
+        CrInterfaceManager.getInstance().userLogin(user,object:ICompletion<UserModel>{
+            override fun onCompletion(completion: CompletionModel<UserModel>) {
+                if(completion.isSuccess == true){
+                    CrConfig.user = completion.result
                     context!!.onStart<AvMain>()
                     finish()
                 }
-
-                // todo: 2023/4/10 失败
-                override fun onFailed(message: String) {
-                    showError(message)
-                }
-            },context,"认证中...")
+            }
+        })
     }
 
 

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

@@ -1,24 +1,24 @@
 package com.cr.cruav
 
 import android.annotation.SuppressLint
-import android.app.ActivityManager
 import android.content.ComponentName
-import android.content.Context
 import android.content.Intent
 import android.os.Bundle
 import android.view.View
 import android.view.WindowManager
 import androidx.activity.viewModels
 import androidx.fragment.app.commit
-import com.cr.common.CrTimerManager
+import com.cr.common.DataManager
 import com.cr.data.CrConfig
 import com.cr.data.CrUtil
 import com.cr.event.*
 import com.cr.map.CaseModel
 import com.cr.map.EventMap
 import com.cr.map.MapAction
+import com.cr.models.AircraftWaypointModel
 import com.cr.pages.*
 import com.cr.viewmodel.*
+import com.cr.pages.FragmentInformationBar
 import com.squareup.otto.Subscribe
 import dji.v5.common.error.IDJIError
 import dji.v5.common.register.DJISDKInitEvent
@@ -26,7 +26,6 @@ import dji.v5.manager.interfaces.SDKManagerCallback
 import kotlinx.android.synthetic.main.av_main.*
 import kotlinx.android.synthetic.main.tools_top.*
 import java.util.*
-import kotlin.concurrent.scheduleAtFixedRate
 
 class AvMain : CrActivity(), View.OnClickListener {
     // todo: 2023/9/14 视图模型绑定
@@ -51,6 +50,7 @@ class AvMain : CrActivity(), View.OnClickListener {
     private var fragmentUploadCase: FragmentUploadCase? = null // define: 2023/6/15 案件上传页面
     private var fragmentDynamicInfo:FragmentDynamicInfo?= null  // define: 2023/7/29 大疆动态信息
     private var fragmentLiveStream:FragmentLiveStream?= null  // define: 2023/9/13 直播页面
+    private var fragmentInformationBar:FragmentInformationBar?= null // define: 2023/9/19 信息栏
 
     // todo: 2023/9/14 变量定义
     private var isFpvSmallWindow: Boolean = true  // define: 2023/3/14 图传窗口是不是小窗口
@@ -109,7 +109,7 @@ class AvMain : CrActivity(), View.OnClickListener {
      */
     private fun initPage() {
         // todo: 2023/4/10 显示登录账号
-        av_main_lbl_user.text = CrConfig.user?.userName
+        fragmentInformationBar!!.setUserAccount(CrConfig.user?.userName!!)
         // todo: 2023/4/11 初始化设置页面
         fragmentSet = FragmentSet()
         fragmentSet?.let {
@@ -207,6 +207,11 @@ class AvMain : CrActivity(), View.OnClickListener {
         supportFragmentManager.commit {
             replace(R.id.av_fragment_dynamic_info,fragmentDynamicInfo!!)
         }
+        // todo: 2023/9/19 加入信息栏视
+        fragmentInformationBar = FragmentInformationBar()
+        supportFragmentManager.commit {
+            replace(R.id.av_information_bar,fragmentInformationBar!!)
+        }
     }
 
     /**
@@ -321,7 +326,14 @@ class AvMain : CrActivity(), View.OnClickListener {
             }
             R.id.tools_case_net->{
                 // todo: 2023/8/14 网络案件查询
-
+                // todo: 2023/9/18 保存航点测试
+                var model = AircraftWaypointModel(CrConfig.user!!.userId!!)
+                model.longitude = "118.35678"
+                model.latitude = "35.67890"
+                model.altitude = "14.567"
+                model.angle = "216.6"
+                val resId = DataManager.saveAircraftLine(model)
+                CrUtil.print("存储Id:${resId}")
             }
             R.id.tools_live->{
                 // todo: 2023/9/13 打开直播设置

+ 7 - 44
app/src/main/java/com/cr/cruav/CrActivity.kt

@@ -9,6 +9,7 @@ import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentActivity
 import androidx.fragment.app.FragmentManager
 import androidx.fragment.app.FragmentTransaction
+import com.cr.common.CrDialogManager
 import com.cr.dialog.DialogNormal
 import com.cr.models.CompletionModel
 import com.cr.models.ICompletion
@@ -20,20 +21,8 @@ import com.cr.models.ICompletion
  * 描述:窗体基类
  */
 open class CrActivity : AppCompatActivity() {
-    // define: 2023/4/10 信息标识符号
-    val MSG_INFO_SHOW_DIALOG:Int = 1
-    val MSG_ERROR_SHOW_DIALOG:Int =2
     // define: 2023/3/10 创建主线程Looper
-    protected var mainHandler = object:Handler(Looper.getMainLooper()){
-        // todo: 2023/4/10 接收消息
-        override fun handleMessage(msg: Message) {
-            if(msg.what == MSG_INFO_SHOW_DIALOG){
-                DialogNormal(context!!,"提示",msg.obj.toString()).show()
-            }else if(msg.what == MSG_ERROR_SHOW_DIALOG){
-                DialogNormal(context!!,"错误",msg.obj.toString()).show()
-            }
-        }
-    }
+    protected var mainHandler = Handler(Looper.getMainLooper())
     // define: 2023/4/10 上下文
     protected var context:Context?= null
 
@@ -42,7 +31,7 @@ open class CrActivity : AppCompatActivity() {
      * @receiver FragmentManager
      * @param func [@kotlin.ExtensionFunctionType] Function1<FragmentTransaction, Unit>
      */
-    inline fun FragmentManager.inTransaction(func:FragmentTransaction.()->Unit){
+    private inline fun FragmentManager.inTransaction(func:FragmentTransaction.()->Unit){
         var fragmentTransaction = beginTransaction()
         fragmentTransaction.func()
         fragmentTransaction.commit()
@@ -105,9 +94,7 @@ open class CrActivity : AppCompatActivity() {
      * @param warning String 警告消息
      */
     protected fun showWarning(warning: String) {
-        mainHandler.post {
-            DialogNormal(CrApplication.getContext(), "警告", warning).show()
-        }
+        CrDialogManager.getInstance().showWarning(warning)
     }
 
     /**
@@ -115,9 +102,7 @@ open class CrActivity : AppCompatActivity() {
      * @param error String 错误消息
      */
     protected fun showError(error: String) {
-        mainHandler.post{
-            DialogNormal(CrApplication.getContext(), "错误", error).show()
-        }
+        CrDialogManager.getInstance().showError(error)
     }
 
     /**
@@ -128,27 +113,7 @@ open class CrActivity : AppCompatActivity() {
      */
     protected fun showConfirm(message:String,actionButtonContent:Array<String>,callback: ICompletion<String>?){
         if(actionButtonContent.size != 2) return
-        mainHandler.post {
-            var dialog = DialogNormal(CrApplication.getContext(),"确认",message)
-            dialog.setButtonsText(actionButtonContent[0],actionButtonContent[1])
-            dialog.setListener(object:DialogNormal.DialogNormalListener{
-                // todo: 2023/8/15 确认操作
-                override fun completion() {
-                    callback?.let {
-                        it.onCompletion(CompletionModel(true,""))
-                    }
-                }
-
-                // todo: 2023/8/15 关闭操作
-                override fun close() {
-                    callback?.let {
-                        it.onCompletion(CompletionModel(false,""))
-                    }
-                }
-
-            })
-            dialog.show()
-        }
+        CrDialogManager.getInstance().showConfirm(message,actionButtonContent,callback)
     }
 
     /**
@@ -156,9 +121,7 @@ open class CrActivity : AppCompatActivity() {
      * @param information String 提示消息
      */
     protected fun showInformation(information: String) {
-        mainHandler.post {
-            DialogNormal(CrApplication.getContext(), "提示", information).show()
-        }
+        CrDialogManager.getInstance().showInformation(information)
     }
 
     /**

+ 17 - 4
app/src/main/java/com/cr/dialog/DialogNormal.kt

@@ -6,7 +6,10 @@ import android.view.Gravity
 import android.view.View
 import android.view.ViewGroup
 import android.widget.Button
+import android.widget.ImageView
 import android.widget.TextView
+import com.cr.common.CrPictureManager
+import com.cr.cruav.CrApplication
 import com.cr.cruav.R
 
 /**
@@ -35,10 +38,11 @@ class DialogNormal : Dialog, View.OnClickListener {
     private var listener: DialogNormalListener? = null
 
     // define: 2023/3/31 定义控件
-    var btnCompletion: Button? = null
-    var btnClose: Button? = null
-    var lblTitle: TextView? = null
-    var lblMessage: TextView? = null
+    private var btnCompletion: Button? = null
+    private var btnClose: Button? = null
+    private var lblTitle: TextView? = null
+    private var lblMessage: TextView? = null
+    private var imgHead:ImageView?= null
 
     /**
      * 初始化
@@ -100,6 +104,7 @@ class DialogNormal : Dialog, View.OnClickListener {
         btnClose?.setOnClickListener(this)
         lblTitle = findViewById(R.id.dig_title)
         lblMessage = findViewById(R.id.dig_message)
+        imgHead = findViewById(R.id.dig_image_head)
         // todo: 2023/3/31 默认不显示取消按钮
         btnClose?.visibility = View.GONE
     }
@@ -157,6 +162,14 @@ class DialogNormal : Dialog, View.OnClickListener {
     fun setListener(listener: DialogNormalListener){
         this.listener = listener
     }
+
+    /**
+     * 设置显示的提示图片
+     * @param resourceId Int
+     */
+    fun setHeadImage(resourceId:Int){
+        imgHead?.setImageDrawable(CrApplication.getContext().getDrawable(resourceId))
+    }
     /**
      * 覆写点击事件
      * @param p0 View

+ 53 - 0
app/src/main/java/com/cr/models/AircraftLineCountModel.kt

@@ -0,0 +1,53 @@
+package com.cr.models
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/9/19 10:47
+ * 描述:航线统计模型
+ */
+class AircraftLineCountModel {
+    var waypointAllCount:Int = 0  // define: 2023/9/19 航点总数
+    var waitUploadWaypointCount:Int=0  // define: 2023/9/19 等待上传的航点总数
+    var yesUploadWaypointCount:Int = 0  // define: 2023/9/19 已上传航点总数
+    var waypointList:MutableList<WaypointDetailModel>? = null // define: 2023/9/19 航点数据集合
+
+    /**
+     * 初始化
+     */
+    init {
+        this.waypointList = mutableListOf()
+    }
+
+    /**
+     * 添加航点统计信息
+     * @param date String 日期分组
+     * @param count Int 航点数量
+     */
+    fun appendWaypointDetailInfo(date:String,count:Int){
+        var info = WaypointDetailModel(date,count)
+        this.waypointList!!.add(info)
+    }
+
+    /**
+     * 内部航点类
+     * @property date String
+     * @property count Int
+     * @constructor
+     */
+    inner class WaypointDetailModel @JvmOverloads constructor(
+        date:String = "",
+        count:Int = 0
+    ){
+        var date:String = ""  // define: 2023/9/19 分组日期
+        var count:Int = 0  // define: 2023/9/19 该日期的航点数量
+
+        /**
+         * 初始化
+         */
+        init {
+            this.date = date
+            this.count = count
+        }
+    }
+}

+ 58 - 0
app/src/main/java/com/cr/models/AircraftWaypointModel.kt

@@ -0,0 +1,58 @@
+package com.cr.models
+
+import com.cr.common.ClassManager
+import com.cr.common.CrUnitManager
+import com.cr.common.JSONManager
+import org.json.JSONObject
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/9/18 16:57
+ * 描述:航线航点模型
+ */
+class AircraftWaypointModel @JvmOverloads constructor(
+    userId:String
+):iNetDataModel<AircraftWaypointModel>{
+    var ptId:String = ""  // define: 2023/9/18 唯一标识
+    var userId:String = ""   // define: 2023/9/18 关联用户Id
+    var createDate:String = ""  // define: 2023/9/18 创建日期
+    var longitude:String = ""  // define: 2023/9/18 经度
+    var latitude:String = ""  // define: 2023/9/18 纬度
+    var altitude:String = ""  // define: 2023/9/18 高度
+    var angle:String = ""  // define: 2023/9/18 方位角
+    var type:String = ""  // define: 2023/9/18 类型 1--代表已上传 0--代表未上传
+
+    /**
+     * 初始化
+     */
+    init {
+        this.userId = userId
+        this.createDate = CrUnitManager.toSystemYMDHMSDate()
+        this.type = "0"
+    }
+
+    companion object:iJSONModel<AircraftWaypointModel>{
+        /**
+         * 覆写转换为实例
+         * @param json String JSON字符串
+         * @return AircraftWaypointModel?
+         */
+        override fun toModel(json: String): AircraftWaypointModel? {
+            var obj = JSONObject(json)
+            var resModel = AircraftWaypointModel("")
+            resModel.ptId = JSONManager.getStringValue(obj,"name")
+            return resModel
+        }
+    }
+
+    /**
+     * 转换为JSON字符串
+     * @return String JSON字符串
+     */
+    override fun toJSON(): String {
+        var obj = ClassManager.fieldsToJSONObject(this)
+        return obj.toString()
+    }
+
+}

+ 21 - 6
app/src/main/java/com/cr/models/CompletionModel.kt

@@ -7,25 +7,40 @@ package com.cr.models
  * 描述:返回结果
  */
 class CompletionModel<T> {
-    var isSuccess:Boolean?=false  // define: 2023/6/13 是否成功
-    var result:T?=null // define: 2023/6/13 消息内容
+    var isSuccess: Boolean = false  // define: 2023/6/13 是否成功
+    var result: T? = null // define: 2023/6/13 消息内容
+    var message: String = ""  // define: 2023/9/20 消息
 
     /**
      * 初始化
      * @param isSuccess Boolean
+     * @param result String
+     * @constructor
+     */
+    constructor(isSuccess: Boolean, result: T?) {
+        this.isSuccess = isSuccess
+        this.result = result
+        this.message = ""
+    }
+
+    /**
+     * 初始化
+     * @param isSuccess Boolean
+     * @param result T?
      * @param message String
      * @constructor
      */
-    constructor(isSuccess:Boolean,message:T?){
+    constructor(isSuccess: Boolean,result: T?,message:String){
         this.isSuccess = isSuccess
-        this.result = message
+        this.result = result
+        this.message = message
     }
 }
 
 /**
  * 完成接口调用
  */
-interface ICompletion<T>{
+interface ICompletion<T> {
     // todo: 2023/6/13 完成回调
-    fun onCompletion(completion:CompletionModel<T>)
+    fun onCompletion(completion: CompletionModel<T>)
 }

+ 2 - 12
app/src/main/java/com/cr/models/SetItemModel.kt

@@ -81,9 +81,9 @@ enum class SettingAction {
     SA_DEL_MAP_CACHE,
 
     /**
-     * 查看大疆飞行记录
+     * 飞行管线管理
      */
-    SA_SHOW_DJI_LOG,
+    SA_AIR_LINE_MANAGER,
 
     /**
      * 删除取证数据
@@ -91,21 +91,11 @@ enum class SettingAction {
     SA_DEL_QZ_DATA,
 
     /**
-     * 删除航线数据
-     */
-    SA_DEL_LINE_DATA,
-
-    /**
      * 删除资源数据
      */
     SA_DEL_RESOURCE_DATA,
 
     /**
-     * 上传断网航点
-     */
-    SA_UPLOAD_NO_UP_AIR_POINT,
-
-    /**
      * 模拟器
      */
     SA_SIMULATOR,

+ 68 - 14
app/src/main/java/com/cr/network/TCPDataTask.kt

@@ -4,6 +4,7 @@ import android.content.Context
 import android.os.Handler
 import android.os.Looper
 import android.os.Message
+import com.cr.cruav.CrApplication
 import com.cr.data.*
 import com.cr.dialog.DialogLoadingUtil
 import com.cr.dialog.DialogNormal
@@ -34,9 +35,6 @@ class TCPDataTask {
     val PROGRESS_CLOSE: Int = 1002
     val SHOW_MESSAGE: Int = 1003
 
-    // define: 2023/4/10 定义变量
-    var context: Context? = null
-
     /**
      * 多线程管理器
      */
@@ -45,13 +43,13 @@ class TCPDataTask {
         override fun handleMessage(msg: Message) {
             when (msg.what) {
                 PROGRESS_SHOW -> {
-                    DialogLoadingUtil.show(context!!, msg.obj.toString())
+                    DialogLoadingUtil.show(CrApplication.getContext(), msg.obj.toString())
                 }
                 PROGRESS_CLOSE -> {
                     DialogLoadingUtil.dismiss()
                 }
                 SHOW_MESSAGE -> {
-                    DialogNormal(context!!, "警告", msg.obj.toString()).show()
+                    DialogNormal(CrApplication.getContext(), "警告", msg.obj.toString()).show()
                 }
             }
         }
@@ -150,7 +148,17 @@ class TCPDataTask {
      * @param callback OnChangeListener 回调
      */
     fun <T> sendJSON(url: String, iModel: iNetDataModel<T>, callback: IChangeCallback) {
-        sendJSON(url, iModel, callback, null, null)
+        sendJSON(url, iModel, callback, null)
+    }
+
+    /**
+     *
+     * @param url String 服务地址
+     * @param jsonString String 发送数据 JSON字符串
+     * @param callback OnChangeListener 回调
+     */
+    fun sendJSON(url: String, jsonString: String, callback: IChangeCallback) {
+        sendJSON(url, jsonString, callback, null)
     }
 
     /**
@@ -158,17 +166,14 @@ class TCPDataTask {
      * @param url String 服务地址
      * @param iModel iNetDataModel<T> 发送数据
      * @param callback OnChangeListener 回调
-     * @param context Context 上下文  如果不显示等待框 可以传null
      * @param loadingMessage String 等待消息内容
      */
     fun <T> sendJSON(
         url: String,
         iModel: iNetDataModel<T>,
         callback: IChangeCallback,
-        context: Context?,
         loadingMessage: String?
     ) {
-        this.context = context
         // todo: 2023/4/8 确定传输类型
         var mediaType: MediaType = "application/json;charset=utf-8".toMediaType()
         // todo: 2023/4/8 创建数据传输内容
@@ -211,8 +216,61 @@ class TCPDataTask {
     }
 
     /**
+     * 发送JSON数据
+     * @param url String 服务地址
+     * @param jsonString String 发送数据 JSON字符串
+     * @param callback OnChangeListener 回调
+     * @param loadingMessage String 等待消息内容
+     */
+    fun sendJSON(
+        url: String,
+        jsonString:String,
+        callback: IChangeCallback,
+        loadingMessage: String?
+    ) {
+        // todo: 2023/4/8 确定传输类型
+        var mediaType: MediaType = "application/json;charset=utf-8".toMediaType()
+        // todo: 2023/4/8 创建数据传输内容
+        var requestBody: RequestBody = jsonString.toRequestBody(mediaType)
+        var request: Request = Request.Builder().url(url).post(requestBody).build()
+        // todo: 2023/4/10 判断是否需要显示等待框
+        if (loadingMessage != null) {
+            showLoading(loadingMessage)
+        }
+        // todo: 2023/4/8 连接发送
+        okHttp?.newCall(request)?.enqueue(object : Callback {
+            // todo: 2023/4/8 失败
+            override fun onFailure(call: Call, e: IOException) {
+                // todo: 2023/4/10 关闭等待框
+                dismissLoading()
+                if (e is ConnectException) {
+                    if (callback != null) callback.onFailed("服务器异常,连接超时!")
+                } else {
+                    var errMessage: String? = e.message
+                    if (callback != null) callback.onFailed(errMessage!!)
+                }
+            }
+
+            // todo: 2023/4/8 成功
+            override fun onResponse(call: Call, response: Response) {
+                // todo: 2023/4/10 关闭等待框
+                dismissLoading()
+                if (response.code == 200) {
+                    try {
+                        var successMessage: String = response.body!!.string()
+                        checkJSON(successMessage, callback)
+                    } catch (e: java.lang.Exception) {
+                        if (callback != null) callback.onFailed(e.message!!)
+                    }
+                } else {
+                    if (callback != null) callback.onFailed("服务器连接异常,异常代码${response.code}")
+                }
+            }
+        })
+    }
+
+    /**
      * 下载文件
-     * @param context Context 上下文
      * @param fullName String 下载文件名称
      * @param url String 下载地址
      * @param callBack OnDownloadListener 回调
@@ -224,8 +282,6 @@ class TCPDataTask {
         callBack: IProgressCallback
     ) {
         if (callBack != null) callBack.onStart()
-        // todo: 2023/4/12 上下文
-        this.context = context
         // todo: 2023/4/12 定义下载的Url
         var request: Request = Request.Builder().url(url).build()
         // todo: 2023/4/12 开始调用下载
@@ -281,14 +337,12 @@ class TCPDataTask {
 
     /**
      * 上传文件及文字内容
-     * @param context Context 上下文
      * @param url String 接口地址
      * @param filePathList List<String> 文件路径数据集
      * @param iModel iNetDataModel<T> 文字内容
      * @param callback IProgressCallback? 回调
      */
     fun <T> sendUploadFiles(
-        context: Context,
         url: String,
         filePathList: List<String>,
         iModel: iNetDataModel<T>,

+ 6 - 30
app/src/main/java/com/cr/pages/CrFragment.kt

@@ -5,8 +5,10 @@ import android.os.Handler
 import android.os.Looper
 import android.view.View
 import androidx.fragment.app.Fragment
+import com.cr.common.CrDialogManager
 import com.cr.common.CrKeyManager
 import com.cr.cruav.CrApplication
+import com.cr.cruav.R
 import com.cr.data.CrUtil
 import com.cr.dialog.DialogLoadingUtil
 import com.cr.dialog.DialogNormal
@@ -56,9 +58,7 @@ open class CrFragment :Fragment(){
      * @param warning String 警告消息
      */
     protected fun showWarning(warning: String) {
-        mainHandler.post {
-            DialogNormal(CrApplication.getContext(), "警告", warning).show()
-        }
+       CrDialogManager.getInstance().showWarning(warning)
     }
 
     /**
@@ -66,9 +66,7 @@ open class CrFragment :Fragment(){
      * @param error String 错误消息
      */
     protected fun showError(error: String) {
-        mainHandler.post{
-            DialogNormal(CrApplication.getContext(), "错误", error).show()
-        }
+        CrDialogManager.getInstance().showError(error)
     }
 
     /**
@@ -79,27 +77,7 @@ open class CrFragment :Fragment(){
      */
     protected fun showConfirm(message:String,actionButtonContent:Array<String>,callback:ICompletion<String>?){
         if(actionButtonContent.size != 2) return
-        mainHandler.post {
-            var dialog = DialogNormal(CrApplication.getContext(),"确认",message)
-            dialog.setButtonsText(actionButtonContent[0],actionButtonContent[1])
-            dialog.setListener(object:DialogNormal.DialogNormalListener{
-                // todo: 2023/8/15 确认操作
-                override fun completion() {
-                    callback?.let {
-                        it.onCompletion(CompletionModel(true,""))
-                    }
-                }
-
-                // todo: 2023/8/15 关闭操作
-                override fun close() {
-                    callback?.let {
-                        it.onCompletion(CompletionModel(false,""))
-                    }
-                }
-
-            })
-            dialog.show()
-        }
+        CrDialogManager.getInstance().showConfirm(message,actionButtonContent,callback)
     }
 
     /**
@@ -107,9 +85,7 @@ open class CrFragment :Fragment(){
      * @param information String 提示消息
      */
     protected fun showInformation(information: String) {
-        mainHandler.post {
-            DialogNormal(CrApplication.getContext(), "提示", information).show()
-        }
+        CrDialogManager.getInstance().showInformation(information)
     }
 
     /**

+ 146 - 0
app/src/main/java/com/cr/pages/FragmentAirLineManager.kt

@@ -0,0 +1,146 @@
+package com.cr.pages
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.ListView
+import android.widget.TextView
+import com.cr.adapter.CrWaypointDetailAdapter
+import com.cr.common.CrInterfaceManager
+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.AircraftWaypointModel
+import com.cr.models.CompletionModel
+import com.cr.models.ICompletion
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/9/19 10:02
+ * 描述:航点管理器页面
+ */
+class FragmentAirLineManager : CrNavigationFragment() ,View.OnClickListener{
+    // todo: 2023/9/19 控件定义
+    private var lblAllCount: TextView? = null // define: 2023/9/19 航点总数
+    private var lblYesCount: TextView? = null // define: 2023/9/19 已上传航点数
+    private var lblNoCount: TextView? = null  // define: 2023/9/19 未上传航点数
+    private var listView: ListView? = null // define: 2023/9/19 待上传航点统计信息
+    private var btnUpdate: Button? = null // define: 2023/9/19 上传航点
+    private var btnDelete:Button?=null // define: 2023/9/19 删除航点
+
+    /**
+     * 初始化
+     * @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_air_line_manager, null)
+        // todo: 2023/9/19 挂载控件
+        joinControls()
+        // todo: 2023/9/19 初始化页面
+        initPage()
+        return mainView
+    }
+
+    /**
+     * 覆写初始化页面
+     */
+    override fun initPage() {
+        // todo: 2023/9/19 显示统计信息
+        var countInfo = DataManager.queryAircraftStatisticsInfo(CrConfig.user!!.userId!!)
+        lblAllCount?.text = "${countInfo.waypointAllCount}个"
+        lblYesCount?.text = "${countInfo.yesUploadWaypointCount}个"
+        lblNoCount?.text = "${countInfo.waitUploadWaypointCount}个"
+        // todo: 2023/9/19 更新待上传航点视图
+        var adapter = CrWaypointDetailAdapter(CrApplication.getContext(), countInfo.waypointList!!)
+        listView?.adapter = adapter
+    }
+
+    /**
+     * 覆写挂载控件
+     */
+    override fun joinControls() {
+        mainView?.let {
+            // todo: 2023/9/19 挂载统计信息控件
+            lblAllCount = it.findViewById(R.id.lbl_all_count)
+            lblYesCount = it.findViewById(R.id.lbl_yes_count)
+            lblNoCount = it.findViewById(R.id.lbl_no_count)
+            // todo: 2023/9/19 挂载明细视图
+            listView = it.findViewById(R.id.list_view)
+            // todo: 2023/9/19 挂载按钮
+            btnUpdate = it.findViewById(R.id.btn_update)
+            btnUpdate?.setOnClickListener(this)
+            btnDelete = it.findViewById(R.id.btn_delete)
+            btnDelete?.setOnClickListener(this)
+        }
+    }
+
+    /**
+     * 覆写视图点击事件
+     * @param view View
+     */
+    override fun onClick(view: View?) {
+        when(view?.id){
+            R.id.btn_update->{
+                // todo: 2023/9/20 先查询待上传航点数据
+                var waitWaypointList = DataManager.queryAllWaitUploadWaypoint(CrConfig.user!!.userId!!)
+                if(waitWaypointList == null || waitWaypointList.isEmpty()){
+                    showWarning("未查询到需要上传的航点!")
+                    return
+                }
+                // todo: 2023/9/19 上传航点
+                showConfirm("确定上传所有待上传航点吗?", arrayOf("上传","取消"),object:ICompletion<String>{
+                    // todo: 2023/9/19 回调
+                    override fun onCompletion(completion: CompletionModel<String>) {
+                        if(completion.isSuccess == true){
+                            CrInterfaceManager.getInstance().uploadAirlineWaypoint(waitWaypointList,object:ICompletion<List<AircraftWaypointModel>>{
+                                // todo: 2023/9/20 执行成功回调
+                                override fun onCompletion(completion: CompletionModel<List<AircraftWaypointModel>>) {
+                                    if (completion.result!!.isNotEmpty()){
+                                        // todo: 2023/9/20 更新航点存储状态
+                                        DataManager.updateWaypointState(CrConfig.user!!.userId!!,completion.result!!)
+                                        mainHandler.post { initPage() }
+                                        showInformation("成功上传航点${completion.result!!.size}个!!")
+                                    }else{
+                                        showWarning("航点未全部上传成功!")
+                                    }
+                                }
+                            })
+                        }
+                    }
+                })
+            }
+            R.id.btn_delete->{
+                // todo: 2023/9/19 删除航点
+                showConfirm("删除后无法恢复,确定要删除吗?", arrayOf("删除","取消"),object:ICompletion<String>{
+                    // todo: 2023/9/19 回调
+                    override fun onCompletion(completion: CompletionModel<String>) {
+                        if(completion.isSuccess == true){
+                            deleteAllWaypoint()
+                        }
+                    }
+                })
+            }
+        }
+    }
+
+    /**
+     * 删除全部航点数据
+     */
+    private fun deleteAllWaypoint(){
+        DataManager.deleteAircraftPoint(CrConfig.user!!.userId!!)
+        initPage()
+    }
+}

+ 156 - 0
app/src/main/java/com/cr/pages/FragmentInformationBar.kt

@@ -0,0 +1,156 @@
+package com.cr.pages
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.fragment.app.activityViewModels
+import com.cr.common.CrInterfaceManager
+import com.cr.common.CrJTMManager
+import com.cr.common.DataManager
+import com.cr.cruav.R
+import com.cr.data.CrConfig
+import com.cr.data.CrUtil
+import com.cr.models.AircraftWaypointModel
+import com.cr.models.CompletionModel
+import com.cr.models.ICompletion
+import com.cr.viewmodel.CrFlightControlVM
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/9/19 15:28
+ * 描述:信息栏组件
+ */
+class FragmentInformationBar :CrFragment(){
+    // todo: 2023/9/19 控件定义
+    private var lblAccount:TextView?= null  // define: 2023/9/19 账号信息
+    private var lblServer:TextView?= null // define: 2023/9/19 航线点上传信息
+
+    // todo: 2023/9/19 绑定模型
+    private val flightControlVm:CrFlightControlVM by activityViewModels()
+
+    // todo: 2023/9/19 变量定义
+    private var oldLongitude:Double = 0.0  // define: 2023/9/19 前一经度
+    private var oldLatitude:Double = 0.0  // define: 2023/9/19 前一纬度
+    private val IMPOSE_DIS:Double = 100.0  // define: 2023/9/19 限制距离
+    private var countSave:Long = 0  // define: 2023/9/19 存储计数
+    private var countUpdate:Long = 0  // define: 2023/9/19 上传计数
+
+    private var userName:String?= null // define: 2023/9/20 登录的用户名称
+
+    /**
+     * 初始化
+     * @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_infomation_bar,null)
+        // todo: 2023/9/19 挂载控件
+        joinControls()
+        // todo: 2023/9/19 初始化页面
+        initPage()
+        return mainView
+    }
+
+    /**
+     * 覆写挂载控件
+     */
+    override fun joinControls() {
+        mainView?.let {
+            lblAccount = it.findViewById(R.id.lbl_account)
+            userName?.let {
+                lblAccount?.text = userName
+            }
+            lblServer = it.findViewById(R.id.lbl_server)
+        }
+    }
+
+    /**
+     * 页面初始化
+     */
+    override fun initPage() {
+        // todo: 2023/9/19 订阅
+        mainHandler.post {
+            flightControlVm.flightControlInfo.observe(requireActivity()){
+                it?.let {
+                    calculateAndSave(it.longitude,it.latitude,it.altitude,it.yaw)
+                }
+            }
+        }
+        // todo: 2023/9/19 更新信息
+        updateInfo()
+    }
+
+    /**
+     * 计算并保存
+     * @param longitude Double 经度
+     * @param latitude Double 纬度
+     * @param altitude Double 高度
+     * @param angle Double 角度
+     */
+    private fun calculateAndSave(longitude:Double,latitude:Double,altitude:Double,angle:Double){
+        // todo: 2023/9/19 计算距离
+        var dis = CrJTMManager.calculateDistance(longitude,latitude,oldLongitude,oldLatitude)
+        if(dis>= IMPOSE_DIS){
+            oldLongitude = longitude
+            oldLatitude = latitude
+            // todo: 2023/9/19 创建存储模型
+            var saveModel = AircraftWaypointModel(CrConfig.user!!.userId!!)
+            saveModel.longitude = String.format("%.6f",longitude)
+            saveModel.latitude = String.format("%.6f",latitude)
+            saveModel.altitude = String.format("%.2f",altitude)
+            saveModel.angle = String.format("%.2f",angle)
+            // todo: 2023/9/20 保存至数据库
+            val ptId = DataManager.saveAircraftLine(saveModel)
+            if(ptId != -1) {
+                countSave++
+                saveModel.ptId = "$ptId"
+                // todo: 2023/9/20 上传数据
+                var ptList = mutableListOf<AircraftWaypointModel>()
+                ptList.add(saveModel)
+                CrInterfaceManager.getInstance().uploadAirlineWaypointNoLoading(ptList,object:ICompletion<List<AircraftWaypointModel>>{
+                    // todo: 2023/9/20 上传后回调
+                    override fun onCompletion(completion: CompletionModel<List<AircraftWaypointModel>>) {
+                        if(completion.isSuccess){
+                            var isUpdate = DataManager.updateWaypointState(CrConfig.user!!.userId!!,completion.result!!)
+                            CrUtil.print("更新${isUpdate}")
+                            if(isUpdate){
+                                countUpdate ++
+                            }
+                        }else{
+                            CrUtil.print("航点上传失败!${completion.message}")
+                        }
+                        updateInfo()
+                    }
+                })
+            }
+        }
+    }
+
+    /**
+     * 更新信息
+     */
+    private fun updateInfo(){
+        mainHandler.post {
+            lblServer?.text = String.format("%d - %d",countSave,countUpdate)
+        }
+    }
+
+    /**
+     * 设置显示账号
+     * @param userAccount String 账号
+     */
+    fun setUserAccount(userAccount:String){
+        this.userName = userAccount
+        lblAccount?.text = userAccount
+    }
+}

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

@@ -39,6 +39,7 @@ class FragmentSet : CrNavigationFragment() {
     private var pageSetIpAndCom:FragmentSetIpAndCom? = null    // define: 2023/9/12 设置Ip和端口页面
     private var pageDownloadData:FragmentSetDataDownload? = null   // define: 2023/9/12 下载数据页面
     private var pageSimulator:FragmentSimulator?= null   // define: 2023/9/12 模拟器页面
+    private var pageAirLineManager:FragmentAirLineManager?=null  // define: 2023/9/19 航线管理器页面
 
     // define: 2023/4/11 定义控件
     private var viewPager: ViewPager2?=null
@@ -95,11 +96,18 @@ class FragmentSet : CrNavigationFragment() {
         pageDownloadData = FragmentSetDataDownload()
         adapter?.addFragment(pageDownloadData!!)
 
+        // todo: 2023/9/19 初始化航线管理器页面
+        pageAirLineManager = FragmentAirLineManager()
+        pageAirLineManager?.setAnimationDirection(AnimationDirection.RIGHT)
+        adapter?.addFragment(pageAirLineManager!!)
+
         // todo: 2023/8/15 初始化模拟器页面
         pageSimulator = FragmentSimulator()
         pageSimulator?.setAnimationDirection(AnimationDirection.RIGHT)
         adapter?.addFragment(pageSimulator!!)
 
+
+
         // todo: 2023/4/11 设置监听
         viewPager?.adapter = adapter
 
@@ -150,6 +158,12 @@ class FragmentSet : CrNavigationFragment() {
                     nvBar?.crSetVisible(backIsVisible = true, dismissIsVisible = false)
                     nvBar?.crSetTitle(R.string.nv_title_simulator)
                 }
+                SettingAction.SA_AIR_LINE_MANAGER->{
+                    // todo: 2023/9/19 航线管理器
+                    showPage(pageAirLineManager!!)
+                    nvBar?.crSetVisible(backIsVisible = true, dismissIsVisible = false)
+                    nvBar?.crSetTitle(R.string.nv_title_air_line)
+                }
             }
         }
 

+ 14 - 33
app/src/main/java/com/cr/pages/FragmentSetMain.kt

@@ -7,6 +7,7 @@ import android.view.ViewGroup
 import android.widget.ListView
 import com.cr.adapter.SettingAdapter
 import com.cr.common.CrSaveManager
+import com.cr.common.CrUnitManager
 import com.cr.cruav.CrApplication
 import com.cr.cruav.R
 import com.cr.event.BarAction
@@ -63,7 +64,7 @@ class FragmentSetMain : CrNavigationFragment() {
         menuList.add(
             SetItemModel(
                 R.drawable.ico_user,
-                "登录大疆账号",
+                CrUnitManager.getStringFromResource(R.string.set_title_dji_login),
                 isArrow = false,
                 isSwitch = false,
                 action = SettingAction.SA_DJI_LOGIN,
@@ -73,7 +74,7 @@ class FragmentSetMain : CrNavigationFragment() {
         menuList.add(
             SetItemModel(
                 R.drawable.tools_download,
-                "数据下载",
+                CrUnitManager.getStringFromResource(R.string.set_title_download_data),
                 isArrow = true,
                 isSwitch = false,
                 action = SettingAction.SA_DOWNLOAD_DATA,
@@ -85,7 +86,7 @@ class FragmentSetMain : CrNavigationFragment() {
         menuList.add(
             SetItemModel(
                 R.drawable.ico_old_map,
-                "飞行器地图居中",
+                CrUnitManager.getStringFromResource(R.string.set_title_map_center),
                 isArrow = false,
                 isSwitch = true,
                 action = SettingAction.SA_MAP_CENTER,
@@ -95,7 +96,7 @@ class FragmentSetMain : CrNavigationFragment() {
         menuList.add(
             SetItemModel(
                 R.drawable.tools_set,
-                "设置服务器的IP和端口",
+                CrUnitManager.getStringFromResource(R.string.set_title_set_ip_and_com),
                 isArrow = true,
                 isSwitch = false,
                 action = SettingAction.SA_SET_IP_COM,
@@ -105,7 +106,7 @@ class FragmentSetMain : CrNavigationFragment() {
         menuList.add(
             SetItemModel(
                 R.drawable.dji_aircraft,
-                "历史航线",
+                CrUnitManager.getStringFromResource(R.string.set_title_old_air_line),
                 isArrow = true,
                 isSwitch = false,
                 action = SettingAction.SA_OLD_AIRLINE,
@@ -115,7 +116,7 @@ class FragmentSetMain : CrNavigationFragment() {
         menuList.add(
             SetItemModel(
                 R.drawable.goto_back,
-                "重新登录系统",
+                CrUnitManager.getStringFromResource(R.string.set_title_reset_login),
                 isArrow = false,
                 isSwitch = false,
                 action = SettingAction.SA_RE_LOGIN,
@@ -125,7 +126,7 @@ class FragmentSetMain : CrNavigationFragment() {
         menuList.add(
             SetItemModel(
                 R.drawable.tools_deleteall,
-                "清除地图缓存",
+                CrUnitManager.getStringFromResource(R.string.set_title_clear_map_cache),
                 isArrow = false,
                 isSwitch = false,
                 action = SettingAction.SA_DEL_MAP_CACHE,
@@ -135,27 +136,17 @@ class FragmentSetMain : CrNavigationFragment() {
         menuList.add(
             SetItemModel(
                 R.drawable.tools_mession,
-                "查看飞行记录",
+                CrUnitManager.getStringFromResource(R.string.set_title_air_line_manager),
                 isArrow = true,
                 isSwitch = false,
-                action = SettingAction.SA_SHOW_DJI_LOG,
-                switchIsOn = false
-            )
-        )
-        menuList.add(
-            SetItemModel(
-                R.drawable.tools_upload,
-                "上传断网航点",
-                isArrow = false,
-                isSwitch = false,
-                action = SettingAction.SA_UPLOAD_NO_UP_AIR_POINT,
+                action = SettingAction.SA_AIR_LINE_MANAGER,
                 switchIsOn = false
             )
         )
         menuList.add(
             SetItemModel(
                 R.drawable.ico_multimage,
-                "删除取证数据",
+                CrUnitManager.getStringFromResource(R.string.set_title_delete_data),
                 isArrow = false,
                 isSwitch = false,
                 action = SettingAction.SA_DEL_QZ_DATA,
@@ -164,18 +155,8 @@ class FragmentSetMain : CrNavigationFragment() {
         )
         menuList.add(
             SetItemModel(
-                R.drawable.ty_save,
-                "删除航线数据",
-                isArrow = false,
-                isSwitch = false,
-                action = SettingAction.SA_DEL_LINE_DATA,
-                switchIsOn = false
-            )
-        )
-        menuList.add(
-            SetItemModel(
                 R.drawable.ty_delete,
-                "删除资源数据",
+                CrUnitManager.getStringFromResource(R.string.set_title_delete_resource),
                 isArrow = false,
                 isSwitch = false,
                 action = SettingAction.SA_DEL_RESOURCE_DATA,
@@ -184,8 +165,8 @@ class FragmentSetMain : CrNavigationFragment() {
         )
         menuList.add(SetItemModel(
             R.drawable.ico_aircraft,
-            "模拟器",
-            isArrow = false,
+            CrUnitManager.getStringFromResource(R.string.set_title_simple),
+            isArrow = true,
             isSwitch = false,
             action = SettingAction.SA_SIMULATOR,
             switchIsOn = false

+ 2 - 2
app/src/main/java/com/cr/pages/FragmentSimulator.kt

@@ -76,8 +76,8 @@ class FragmentSimulator:CrNavigationFragment(), View.OnClickListener {
      * 覆写初始化页面
      */
     override fun initPage() {
-        txtLongitude?.setContent("118.167")
-        txtLatitude?.setContent("35.155")
+        txtLongitude?.setContent("118.714")
+        txtLatitude?.setContent("35.226")
     }
 
     /**

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

@@ -234,7 +234,6 @@ class FragmentUploadAction : CrNavigationFragment(), View.OnClickListener {
                 }
 
             },
-            CrApplication.getContext(),
             "获取中..."
         )
     }
@@ -264,7 +263,6 @@ class FragmentUploadAction : CrNavigationFragment(), View.OnClickListener {
                 }
 
             },
-            CrApplication.getContext(),
             "获取中..."
         )
     }
@@ -361,7 +359,6 @@ class FragmentUploadAction : CrNavigationFragment(), View.OnClickListener {
             submitCaseModel?.submitImages += "${name};"
         }
         TCPDataTask.getInstance().sendUploadFiles(
-            CrApplication.getContext(),
             NetManager.getServerUrl("appUploadCase"),
             filePathList,
             submitCaseModel!!,

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

@@ -140,7 +140,7 @@ class CrCameraVM : CrViewModel() {
             it?.let {
                 if (it.type == MediaFileType.JPEG) {
                     mediaInfo.value?.name = "FX_${CrUnitManager.toSystemDate()}"
-                    mediaInfo.value?.size = CrUnitManager.toFileSize(it.fileSize)
+                    mediaInfo.value?.size = CrUnitManager.toFileSize(it.fileSize.toInt())
                     mediaInfo.value?.time =
                         "${it.createTime.year}-${it.createTime.month}-${it.createTime.day} ${it.createTime.hour}:${it.createTime.minute}:${it.createTime.second}"
                 }

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

@@ -49,7 +49,6 @@ class CrLinkVM :CrViewModel(){
         AirLinkKey.KeyLinkSignalQuality.create().listen(this){
             it?.let {
                 linkInfo.value?.signalQuality = it*10
-                CrUtil.print("链路质量" + linkInfo.value?.signalQuality)
                 refresh(linkInfo)
             }
         }

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


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


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


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

@@ -22,14 +22,14 @@
         android:orientation="vertical"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@id/av_fragment_top"
-        app:layout_constraintBottom_toBottomOf="@id/av_main_panel_bottom"
+        app:layout_constraintBottom_toBottomOf="@id/av_information_bar"
         android:background="@color/cardview_shadow_start_color"/>
     <!--FPV容器-->
     <FrameLayout
         android:layout_width="@dimen/cr_200_dp"
         android:layout_height="@dimen/cr_140_dp"
         android:id="@+id/av_fragment_fpv"
-        app:layout_constraintBottom_toTopOf="@id/av_main_panel_bottom"
+        app:layout_constraintBottom_toTopOf="@id/av_information_bar"
         app:layout_constraintRight_toRightOf="parent"
         android:layout_marginBottom="@dimen/cr_6_dp"
         android:layout_marginRight="@dimen/cr_6_dp"
@@ -39,59 +39,18 @@
         android:layout_width="@dimen/cr_450_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_constraintBottom_toTopOf="@id/av_information_bar"
         app:layout_constraintLeft_toLeftOf="parent"
         android:layout_marginBottom="@dimen/cr_6_dp"
         android:layout_marginLeft="@dimen/cr_6_dp"/>
     <!--底部信息栏-->
-    <LinearLayout
+    <FrameLayout
         android:layout_width="match_parent"
         android:layout_height="@dimen/common_height"
-        android:background="@color/common_back_a"
-        android:id="@+id/av_main_panel_bottom"
+        app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
-        android:orientation="horizontal">
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_weight="2"
-            android:gravity="center_vertical">
-            <ImageView
-                android:layout_width="@dimen/common_height"
-                android:layout_height="@dimen/common_height"
-                android:src="@drawable/ico_user"
-                android:padding="@dimen/common_padding"/>
-            <TextView
-                style="@style/lbl_title_main_bottom"
-                android:text="@string/default_value"
-                android:textStyle="bold"
-                android:id="@+id/av_main_lbl_user"/>
-        </LinearLayout>
-        <TextView
-            style="@style/lbl_title_v"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            android:gravity="center"
-            android:text="@string/login_technical_support"/>
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_weight="2"
-            android:gravity="center_vertical">
-            <ImageView
-                android:layout_width="@dimen/common_height"
-                android:layout_height="@dimen/common_height"
-                android:src="@drawable/upload_server"
-                android:padding="@dimen/common_padding"/>
-            <TextView
-                style="@style/lbl_title_main_bottom"
-                android:text="@string/default_value"
-                android:textStyle="bold"
-                android:id="@+id/av_main_lbl_server"/>
-        </LinearLayout>
-    </LinearLayout>
+        android:id="@+id/av_information_bar"/>
     <!--顶部工具-->
     <LinearLayout
         android:layout_width="wrap_content"
@@ -119,7 +78,7 @@
         style="@style/common_match_panel_v"
         android:id="@+id/av_frm_right_panel"
         android:layout_width="@dimen/cr_240_dp"
-        app:layout_constraintBottom_toTopOf="@+id/av_main_panel_bottom"
+        app:layout_constraintBottom_toTopOf="@+id/av_information_bar"
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintTop_toBottomOf="@id/av_fragment_top" />
     <!--左侧弹窗容器 大-->
@@ -129,7 +88,7 @@
         android:layout_width="@dimen/cr_200_dp"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@id/av_fragment_top"
-        app:layout_constraintBottom_toTopOf="@+id/av_main_panel_bottom"
+        app:layout_constraintBottom_toTopOf="@+id/av_information_bar"
         />
     <!--左侧弹窗容器 小-->
     <FrameLayout
@@ -138,7 +97,7 @@
         android:layout_width="@dimen/cr_120_dp"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@id/av_fragment_top"
-        app:layout_constraintBottom_toTopOf="@+id/av_main_panel_bottom"
+        app:layout_constraintBottom_toTopOf="@+id/av_information_bar"
         />
     <!--中间弹窗-->
     <FrameLayout

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

@@ -13,9 +13,10 @@
         <ImageView
             android:layout_width="@dimen/cr_24_dp"
             android:layout_height="@dimen/cr_24_dp"
-            android:src="@drawable/ico_info"
+            android:src="@drawable/ico_information"
             android:layout_gravity="center"
-            android:layout_margin="@dimen/common_margin"/>
+            android:layout_margin="@dimen/common_margin"
+            android:id="@+id/dig_image_head"/>
         <TextView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"

+ 68 - 0
app/src/main/res/layout/frag_air_line_manager.xml

@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/shape_back_fragment">
+    <TextView
+        style="@style/lbl_common_title_left"
+        android:text="@string/air_line_collect_info"/>
+    <View style="@style/view_split_h1"/>
+    <LinearLayout
+        style="@style/air_line_row_panel">
+        <TextView
+            style="@style/air_line_row_title"
+            android:text="@string/air_line_all_count"/>
+        <TextView
+            style="@style/air_line_row_value"
+            android:text="@string/default_value"
+            android:id="@+id/lbl_all_count"/>
+    </LinearLayout>
+    <LinearLayout
+        style="@style/air_line_row_panel">
+        <TextView
+            style="@style/air_line_row_title"
+            android:text="@string/air_line_upload_yes"/>
+        <TextView
+            style="@style/air_line_row_value"
+            android:text="@string/default_value"
+            android:id="@+id/lbl_yes_count"/>
+    </LinearLayout>
+    <LinearLayout
+        style="@style/air_line_row_panel">
+        <TextView
+            style="@style/air_line_row_title"
+            android:text="@string/air_line_upload_no"/>
+        <TextView
+            style="@style/air_line_row_value"
+            android:text="@string/default_value"
+            android:id="@+id/lbl_no_count"/>
+    </LinearLayout>
+    <View style="@style/view_split_h1"/>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/cr_10_dp"
+        android:layout_marginTop="@dimen/cr_5_dp"
+        android:layout_marginBottom="@dimen/cr_5_dp">
+        <Button
+            style="@style/btn_default"
+            android:text="@string/air_line_action_upload"
+            android:layout_weight="1"
+            android:id="@+id/btn_update"/>
+        <Button
+            style="@style/btn_default"
+            android:text="@string/air_line_action_delete"
+            android:layout_weight="1"
+            android:background="@drawable/btn_set_selector"
+            android:id="@+id/btn_delete"/>
+    </LinearLayout>
+    <View style="@style/view_split_h1"/>
+    <TextView
+        style="@style/lbl_common_title_left"
+        android:text="@string/air_line_detail_info"/>
+    <View style="@style/view_split_h1"/>
+    <ListView
+        style="@style/list_view_common"
+        android:id="@+id/list_view"/>
+</LinearLayout>

+ 51 - 0
app/src/main/res/layout/frag_infomation_bar.xml

@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@color/common_back_a"
+        android:orientation="horizontal"
+        android:gravity="center_vertical">
+        <LinearLayout
+            android:layout_width="@dimen/cr_120_dp"
+            android:layout_height="match_parent"
+            android:gravity="center_vertical"
+            android:layout_marginStart="@dimen/cr_10_dp">
+            <ImageView
+                android:layout_width="@dimen/common_height"
+                android:layout_height="@dimen/common_height"
+                android:src="@drawable/ico_user"
+                android:padding="@dimen/common_padding"/>
+            <TextView
+                style="@style/lbl_title_main_bottom"
+                android:text="@string/default_value"
+                android:textStyle="bold"
+                android:id="@+id/lbl_account"/>
+        </LinearLayout>
+        <TextView
+            style="@style/lbl_title_v"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:text="@string/login_technical_support"/>
+        <LinearLayout
+            android:layout_width="@dimen/cr_100_dp"
+            android:layout_height="match_parent"
+            android:gravity="center_vertical">
+            <ImageView
+                android:layout_width="@dimen/common_height"
+                android:layout_height="@dimen/common_height"
+                android:src="@drawable/upload_server"
+                android:padding="@dimen/common_padding"/>
+            <TextView
+                style="@style/lbl_title_main_bottom"
+                android:text="@string/default_value"
+                android:textStyle="bold"
+                android:id="@+id/lbl_server"/>
+        </LinearLayout>
+    </LinearLayout>
+</LinearLayout>

+ 1 - 5
app/src/main/res/layout/frag_layer_control.xml

@@ -18,11 +18,7 @@
             android:id="@+id/nv"
             android:layout_weight="0"/>
         <ListView
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            android:divider="@null"
-            android:dividerHeight="0dp"
+           style="@style/list_view_common"
             android:id="@+id/list_view"/>
     </LinearLayout>
 </RelativeLayout>

+ 30 - 0
app/src/main/res/layout/item_waypoint_detail.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/cr_24_dp">
+        <TextView
+            style="@style/lbl_title_common"
+            android:text="@string/default_value"
+            android:layout_height="match_parent"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_marginStart="@dimen/cr_10_dp"
+            android:gravity="center_vertical"
+            android:textSize="@dimen/sp_14"
+            android:id="@+id/lbl_date"/>
+        <TextView
+            style="@style/lbl_value_common"
+            android:text="@string/default_value"
+            android:layout_marginEnd="@dimen/cr_10_dp"
+            android:textSize="@dimen/sp_12"
+            android:layout_height="match_parent"
+            android:gravity="center_vertical"
+            android:id="@+id/lbl_count"/>
+    </LinearLayout>
+    <View style="@style/view_split_h1"/>
+</LinearLayout>

+ 23 - 0
app/src/main/res/values/strings.xml

@@ -92,6 +92,7 @@
     <string name="nv_title_dji_initialize">飞行器自检</string>
     <string name="nv_title_simulator">飞行模拟器</string>
     <string name="nv_title_live">直播相关</string>
+    <string name="nv_title_air_line">飞行航线管理</string>
 
     <!--对话框-->
     <string name="dig_normal_btn_ok">确定</string>
@@ -216,6 +217,28 @@
     <string name="fpv_action_trigger_channel_type">切换视频通道</string>
     <string name="fpv_video_info">帧率:30 宽:1280 高:960</string>
 
+    <!--航线管理页面相关-->
+    <string name="air_line_all_count">航点总数</string>
+    <string name="air_line_upload_yes">已上传航点数</string>
+    <string name="air_line_upload_no">未上传航点数</string>
+    <string name="air_line_collect_info">航线汇总信息</string>
+    <string name="air_line_detail_info">待上传航点明细</string>
+    <string name="air_line_action_upload">航点上传</string>
+    <string name="air_line_action_delete">删除全部</string>
+
+    <!--设置页面动作标题-->
+    <string name="set_title_dji_login">登录大疆账号</string>
+    <string name="set_title_download_data">配置数据下载</string>
+    <string name="set_title_map_center">飞行器地图居中</string>
+    <string name="set_title_old_air_line">历史航线</string>
+    <string name="set_title_reset_login">重新登录系统</string>
+    <string name="set_title_clear_map_cache">清除地图缓存</string>
+    <string name="set_title_air_line_manager">飞行航线管理</string>
+    <string name="set_title_delete_data">删除取证数据</string>
+    <string name="set_title_delete_resource">删除资源数据</string>
+    <string name="set_title_simple">模拟飞行</string>
+    <string name="set_title_set_ip_and_com">设置网络Ip和端口</string>
+
     <!--字体-->
     <string name="ico_nv_left" translatable="false">&#xe60b;</string>
     <string name="ico_nv_right" translatable="false">&#xe81a;</string>

+ 39 - 0
app/src/main/res/values/themes.xml

@@ -422,6 +422,13 @@
         <item name="android:orientation">vertical</item>
     </style>
 
+    <!--通用左侧文本标题-->
+    <style name="lbl_common_title_left" parent="lbl_title_common">
+        <item name="android:textColor">@color/white</item>
+        <item name="android:textSize">@dimen/sp_12</item>
+        <item name="android:layout_margin">@dimen/cr_6_dp</item>
+    </style>
+
     <!--直播页面布局-->
     <!--标题头标题文字样式-->
     <style name="live_head_title" parent="lbl_title_common">
@@ -466,6 +473,38 @@
         <item name="android:layout_marginRight">@dimen/cr_20_dp</item>
     </style>
 
+    <!--航线管理器样式集合-->
+    <!--行容器样式-->
+    <style name="air_line_row_panel">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">@dimen/cr_24_dp</item>
+    </style>
+    <!--行容器标题样式-->
+    <style name="air_line_row_title" parent="lbl_title_common">
+        <item name="android:layout_width">@dimen/cr_80_dp</item>
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:gravity">center_vertical|right</item>
+        <item name="android:textSize">@dimen/sp_12</item>
+        <item name="android:layout_marginRight">@dimen/cr_8_dp</item>
+    </style>
+    <!--行容器值样式-->
+    <style name="air_line_row_value" parent="air_line_row_title">
+        <item name="android:layout_width">0dp</item>
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:layout_weight">1</item>
+        <item name="android:gravity">center_vertical|left</item>
+        <item name="android:textColor">@color/white</item>
+    </style>
+
+    <!--ListView通用样式-->
+    <style name="list_view_common">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">0dp</item>
+        <item name="android:layout_weight">1</item>
+        <item name="android:divider">@null</item>
+        <item name="android:dividerHeight">0dp</item>
+    </style>
+
     <!--自定义文本框属性-->
     <declare-styleable name="ViewEditTextProperty">
         <attr name="crHint" />

+ 1 - 1
build.gradle

@@ -1,7 +1,7 @@
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
 buildscript {
     ext.kotlin_version = '1.6.10'
-    ext.djisdk_version = '5.5.0'
+    ext.djisdk_version = '5.6.0'
     ext.arcgissdk_version = '100.8.0'
     repositories {
         google()