Browse Source

1、编辑页面设计完成,功能尚未编写
2、图片缩放、平移、绘制组件基本功能编写完成,回调及调用尚未编写

不会爬树的猴 1 year ago
parent
commit
52f85d1be0

+ 13 - 0
app/src/main/java/com/cr/adapter/CrPageAdapter.kt

@@ -2,6 +2,7 @@ package com.cr.adapter
 
 
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentActivity
 import androidx.fragment.app.FragmentActivity
+import androidx.viewpager.widget.PagerAdapter
 import androidx.viewpager2.adapter.FragmentStateAdapter
 import androidx.viewpager2.adapter.FragmentStateAdapter
 import com.cr.pages.CrNavigationFragment
 import com.cr.pages.CrNavigationFragment
 
 
@@ -22,6 +23,18 @@ class CrPageAdapter@JvmOverloads constructor(
      */
      */
     fun addFragment(fragment: CrNavigationFragment){
     fun addFragment(fragment: CrNavigationFragment){
         mFragmentList.add(fragment)
         mFragmentList.add(fragment)
+        // todo: 2023/6/20 此方法必须执行 否则会导致由于利用缓存而出问题
+        notifyDataSetChanged()
+    }
+
+    /**
+     * 移除最有一个页面
+     */
+    fun removeLastFragment(){
+        if(mFragmentList.size == 0) return
+        mFragmentList.removeAt(mFragmentList.size -1)
+        // todo: 2023/6/20 此方法必须执行 否则会导致由于利用缓存而出问题
+        notifyDataSetChanged()
     }
     }
 
 
     /**
     /**

+ 63 - 11
app/src/main/java/com/cr/common/DataManager.kt

@@ -1,9 +1,12 @@
 package com.cr.common
 package com.cr.common
 
 
+import com.cr.map.CaseModel
 import com.cr.map.LayerConfigModel
 import com.cr.map.LayerConfigModel
 import com.cr.map.LayerModel
 import com.cr.map.LayerModel
 import com.cr.models.IPAndComModel
 import com.cr.models.IPAndComModel
+import com.cr.models.CompletionModel
 import com.cr.models.UserModel
 import com.cr.models.UserModel
+import com.cr.models.ICompletion
 
 
 /**
 /**
  * 操作系统:MAC系统
  * 操作系统:MAC系统
@@ -21,7 +24,7 @@ class DataManager {
          */
          */
         fun getNetworkLinkInfo(): IPAndComModel {
         fun getNetworkLinkInfo(): IPAndComModel {
             var sql: String = "SELECT * FROM ipcom where CHECKED = '1'"
             var sql: String = "SELECT * FROM ipcom where CHECKED = '1'"
-            var res: List<HashMap<String, String>> = DatabaseAppManager.getInstance().query(sql)
+            var res: List<HashMap<String, String>> = DatabaseBaseManager.getInstance().query(sql)
             var map = res[0]
             var map = res[0]
             map.let {
             map.let {
                 return IPAndComModel.initByMap(it)
                 return IPAndComModel.initByMap(it)
@@ -35,7 +38,7 @@ class DataManager {
         fun getNetworkLinks(): List<IPAndComModel> {
         fun getNetworkLinks(): List<IPAndComModel> {
             var res = mutableListOf<IPAndComModel>()
             var res = mutableListOf<IPAndComModel>()
             var sql: String = "SELECT * FROM ipcom order by id"
             var sql: String = "SELECT * FROM ipcom order by id"
-            var qList: List<HashMap<String, String>> = DatabaseAppManager.getInstance().query(sql)
+            var qList: List<HashMap<String, String>> = DatabaseBaseManager.getInstance().query(sql)
             for (map in qList) {
             for (map in qList) {
                 var item = IPAndComModel.initByMap(map)
                 var item = IPAndComModel.initByMap(map)
                 res.add(item)
                 res.add(item)
@@ -51,7 +54,7 @@ class DataManager {
         fun queryNetworkLink(queryItem: IPAndComModel): Boolean {
         fun queryNetworkLink(queryItem: IPAndComModel): Boolean {
             var sql =
             var sql =
                 "select * from ipcom where ip='${queryItem.ip}' and com='${queryItem.com}' and server='${queryItem.serverName}'"
                 "select * from ipcom where ip='${queryItem.ip}' and com='${queryItem.com}' and server='${queryItem.serverName}'"
-            var qList: List<HashMap<String, String>> = DatabaseAppManager.getInstance().query(sql)
+            var qList: List<HashMap<String, String>> = DatabaseBaseManager.getInstance().query(sql)
             return qList != null && qList.isNotEmpty()
             return qList != null && qList.isNotEmpty()
         }
         }
 
 
@@ -65,7 +68,7 @@ class DataManager {
             var where = "ip='${item.ip}' and com='${item.com}' and server='${item.serverName}'"
             var where = "ip='${item.ip}' and com='${item.com}' and server='${item.serverName}'"
             var checkedValue = if (isChecked) "1" else "0"
             var checkedValue = if (isChecked) "1" else "0"
             var values = hashMapOf("checked" to checkedValue)
             var values = hashMapOf("checked" to checkedValue)
-            return DatabaseAppManager.getInstance().update("ipcom", values, where)
+            return DatabaseBaseManager.getInstance().update("ipcom", values, where)
         }
         }
 
 
         /**
         /**
@@ -80,7 +83,7 @@ class DataManager {
                 "com" to item.com,
                 "com" to item.com,
                 "server" to item.serverName
                 "server" to item.serverName
             )
             )
-            return DatabaseAppManager.getInstance().insert("ipcom", values)
+            return DatabaseBaseManager.getInstance().insert("ipcom", values)
         }
         }
 
 
         /**
         /**
@@ -89,7 +92,7 @@ class DataManager {
          */
          */
         fun cancelNetworkChecked(): Boolean {
         fun cancelNetworkChecked(): Boolean {
             var values = hashMapOf("checked" to "0")
             var values = hashMapOf("checked" to "0")
-            return DatabaseAppManager.getInstance().update("ipcom", values, "")
+            return DatabaseBaseManager.getInstance().update("ipcom", values, "")
         }
         }
 
 
         /**
         /**
@@ -106,7 +109,7 @@ class DataManager {
             userMap["name"] = userName
             userMap["name"] = userName
             userMap["password"] = password
             userMap["password"] = password
             userMap["issave"] = "1"
             userMap["issave"] = "1"
-            return DatabaseAppManager.getInstance().insert("user", userMap)
+            return DatabaseBaseManager.getInstance().insert("user", userMap)
         }
         }
 
 
         /**
         /**
@@ -114,7 +117,7 @@ class DataManager {
          * @return Boolean
          * @return Boolean
          */
          */
         fun deleteUser(): Boolean {
         fun deleteUser(): Boolean {
-            return DatabaseAppManager.getInstance().delete("user", "")
+            return DatabaseBaseManager.getInstance().delete("user", "")
         }
         }
 
 
         /**
         /**
@@ -124,7 +127,7 @@ class DataManager {
         fun getUser(): UserModel {
         fun getUser(): UserModel {
             var user = UserModel()
             var user = UserModel()
             var sql = "SELECT * FROM user"
             var sql = "SELECT * FROM user"
-            var qList: List<HashMap<String, String>> = DatabaseAppManager.getInstance().query(sql)
+            var qList: List<HashMap<String, String>> = DatabaseBaseManager.getInstance().query(sql)
             if (qList != null && qList.isNotEmpty()) {
             if (qList != null && qList.isNotEmpty()) {
                 user.userId = qList[0]["name"]
                 user.userId = qList[0]["name"]
                 user.userPwd = qList[0]["password"]
                 user.userPwd = qList[0]["password"]
@@ -141,7 +144,7 @@ class DataManager {
             var layers: MutableList<LayerModel> = mutableListOf()
             var layers: MutableList<LayerModel> = mutableListOf()
             var sql = "select * from TileLayerConfig order by id"
             var sql = "select * from TileLayerConfig order by id"
             var qList: List<HashMap<String, String>> =
             var qList: List<HashMap<String, String>> =
-                DatabaseConfigManager.getInstance().query(sql)
+                DatabaseAppConfigManager.getInstance().query(sql)
             if (qList != null && qList.isNotEmpty()) {
             if (qList != null && qList.isNotEmpty()) {
                 for (map in qList) {
                 for (map in qList) {
                     var lyrName = map["lyrname"]
                     var lyrName = map["lyrname"]
@@ -164,7 +167,7 @@ class DataManager {
             var layerList: MutableList<LayerConfigModel> = mutableListOf()
             var layerList: MutableList<LayerConfigModel> = mutableListOf()
             var sql = "SELECT * FROM BaseLayerConfig"
             var sql = "SELECT * FROM BaseLayerConfig"
             var qList: List<HashMap<String, String>> =
             var qList: List<HashMap<String, String>> =
-                DatabaseConfigManager.getInstance().query(sql)
+                DatabaseAppConfigManager.getInstance().query(sql)
             if (qList != null && qList.isNotEmpty()) {
             if (qList != null && qList.isNotEmpty()) {
                 for (map in qList) {
                 for (map in qList) {
                     var model = LayerConfigModel(
                     var model = LayerConfigModel(
@@ -179,5 +182,54 @@ class DataManager {
             // todo: 2023/4/13 返回数据集合
             // todo: 2023/4/13 返回数据集合
             return layerList
             return layerList
         }
         }
+
+        /**
+         * 添加案件点照片
+         * @param model CaseModel 案件点模型
+         * @param callback iCompletion 完成回调
+         */
+        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 queryList = DatabaseAppUAVManager.getInstance().query(SQL)
+            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()
+                values["lng"] = model!!.longitude!!.toString()
+                values["alt"] = model!!.altitude!!.toString()
+                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,"该照片已经存储!"))
+                }
+            }
+        }
+
+        /**
+         * 根据案件Id查询案件照片的详细信息
+         * @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)
+            var queryList = DatabaseAppUAVManager.getInstance().query(querySQL)
+            if(queryList.isNotEmpty()){
+                var resList = mutableListOf<String>()
+                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("未查询到任何信息!")))
+            }
+        }
     }
     }
 }
 }

+ 4 - 3
app/src/main/java/com/cr/common/DatabaseConfigManager.kt → app/src/main/java/com/cr/common/DatabaseAppConfigManager.kt

@@ -11,7 +11,7 @@ import java.io.File
  * 创建日期:2023/3/31 09:09
  * 创建日期:2023/3/31 09:09
  * 描述:管理数据库操作类 网络下载的配置库
  * 描述:管理数据库操作类 网络下载的配置库
  */
  */
-class DatabaseConfigManager : DatabaseBaseManager() {
+class DatabaseAppConfigManager : DatabaseBaseManager() {
     /**
     /**
      * 在此代码块中加入静态方法
      * 在此代码块中加入静态方法
      */
      */
@@ -24,16 +24,17 @@ class DatabaseConfigManager : DatabaseBaseManager() {
     }
     }
 
 
     object InstanceHelper {
     object InstanceHelper {
-        var self = DatabaseConfigManager()
+        var self = DatabaseAppConfigManager()
     }
     }
 
 
+
     /**
     /**
      * 打开配置库
      * 打开配置库
      * @return Boolean
      * @return Boolean
      */
      */
     override fun openConfigDatabase(): Boolean {
     override fun openConfigDatabase(): Boolean {
         var filePath: String = CrUtil.DATABASE_PATH_CONFIG
         var filePath: String = CrUtil.DATABASE_PATH_CONFIG
-        var file: File = File(filePath)
+        var file = File(filePath)
         if (!file.exists()) return false
         if (!file.exists()) return false
         if (sqLiteDatabaseConfig == null) {
         if (sqLiteDatabaseConfig == null) {
             sqLiteDatabaseConfig = SQLiteDatabase.openDatabase(filePath, null, OPEN_READWRITE)
             sqLiteDatabaseConfig = SQLiteDatabase.openDatabase(filePath, null, OPEN_READWRITE)

+ 3 - 5
app/src/main/java/com/cr/common/DatabaseAppManager.kt → app/src/main/java/com/cr/common/DatabaseAppUAVManager.kt

@@ -1,7 +1,5 @@
 package com.cr.common
 package com.cr.common
 
 
-import android.content.ContentValues
-import android.database.Cursor
 import android.database.sqlite.SQLiteDatabase
 import android.database.sqlite.SQLiteDatabase
 import android.database.sqlite.SQLiteDatabase.OPEN_READWRITE
 import android.database.sqlite.SQLiteDatabase.OPEN_READWRITE
 import com.cr.data.CrUtil
 import com.cr.data.CrUtil
@@ -13,7 +11,7 @@ import java.io.File
  * 创建日期:2023/3/31 09:09
  * 创建日期:2023/3/31 09:09
  * 描述:数据管理类
  * 描述:数据管理类
  */
  */
-open class DatabaseAppManager :DatabaseBaseManager(){
+open class DatabaseAppUAVManager :DatabaseBaseManager(){
     /**
     /**
      * 在此代码块中加入静态方法
      * 在此代码块中加入静态方法
      */
      */
@@ -26,7 +24,7 @@ open class DatabaseAppManager :DatabaseBaseManager(){
     }
     }
 
 
     object InstanceHelper {
     object InstanceHelper {
-        var self = DatabaseAppManager()
+        var self = DatabaseAppUAVManager()
     }
     }
 
 
     /**
     /**
@@ -34,7 +32,7 @@ open class DatabaseAppManager :DatabaseBaseManager(){
      * @return Boolean
      * @return Boolean
      */
      */
     override fun openConfigDatabase(): Boolean {
     override fun openConfigDatabase(): Boolean {
-        var filePath: String = CrUtil.DATABASE_PATH
+        var filePath: String = CrUtil.DATABASE_PATH_AIR
         var file: File = File(filePath)
         var file: File = File(filePath)
         if (!file.exists()) return false
         if (!file.exists()) return false
         if (sqLiteDatabaseConfig == null) {
         if (sqLiteDatabaseConfig == null) {

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

@@ -33,6 +33,15 @@ open class DatabaseBaseManager {
     }
     }
 
 
     /**
     /**
+     * 初始化
+     */
+    init {
+        if (sqLiteDatabaseConfig == null){
+            openConfigDatabase()
+        }
+    }
+
+    /**
      * 打开配置库
      * 打开配置库
      * @return Boolean
      * @return Boolean
      */
      */

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

@@ -15,9 +15,9 @@ import android.widget.TextView
 import androidx.core.app.ActivityCompat
 import androidx.core.app.ActivityCompat
 import androidx.core.content.ContextCompat
 import androidx.core.content.ContextCompat
 import com.cr.common.DataManager
 import com.cr.common.DataManager
-import com.cr.common.DatabaseAppManager
-import com.cr.common.DatabaseConfigManager
+import com.cr.common.DatabaseAppConfigManager
 import com.cr.common.CrFileManager
 import com.cr.common.CrFileManager
+import com.cr.common.DatabaseBaseManager
 import com.cr.data.CrConfig
 import com.cr.data.CrConfig
 import com.cr.data.CrUtil
 import com.cr.data.CrUtil
 import com.cr.data.CrUtil.Companion.onStart
 import com.cr.data.CrUtil.Companion.onStart
@@ -75,12 +75,6 @@ class AvLogin : CrActivity(), OnClickListener {
         setContentView(R.layout.av_login)
         setContentView(R.layout.av_login)
         // todo: 2023/4/10 初始化上下文
         // todo: 2023/4/10 初始化上下文
         this.context = this
         this.context = this
-        // todo: 2023/3/30 初始化页面
-        fragIpAndCom = FragmentSetIpAndCom()
-        fragIpAndCom?.let {
-            addFragment(it, R.id.av_frm_left_big_panel)
-            hideFragment(it)
-        }
         // todo: 2023/4/6 初始化控件
         // todo: 2023/4/6 初始化控件
         joinControls()
         joinControls()
         // todo: 2023/3/30 注册事件
         // todo: 2023/3/30 注册事件
@@ -283,7 +277,7 @@ class AvLogin : CrActivity(), OnClickListener {
         // todo: 2023/4/3 拷贝配置库
         // todo: 2023/4/3 拷贝配置库
         CrFileManager.moveDataBase(this)
         CrFileManager.moveDataBase(this)
         // todo: 2023/4/3 判断数据库是否存在 存在则启动
         // todo: 2023/4/3 判断数据库是否存在 存在则启动
-        var databaseIsOpen: Boolean = DatabaseAppManager.getInstance().openConfigDatabase()
+        var databaseIsOpen: Boolean = DatabaseBaseManager.getInstance().openConfigDatabase()
         // todo: 2023/4/3 最终判断是否可以正常使用App
         // todo: 2023/4/3 最终判断是否可以正常使用App
         if (CrFileManager.isExists(CrUtil.PROJECT_PATH) && CrFileManager.isExists(CrUtil.IMAGE_PATH) && CrFileManager.isExists(
         if (CrFileManager.isExists(CrUtil.PROJECT_PATH) && CrFileManager.isExists(CrUtil.IMAGE_PATH) && CrFileManager.isExists(
                 CrUtil.PROJECT_CACHE_PATH
                 CrUtil.PROJECT_CACHE_PATH
@@ -292,7 +286,13 @@ class AvLogin : CrActivity(), OnClickListener {
             // todo: 2023/4/3 自检通过 可正常使用
             // todo: 2023/4/3 自检通过 可正常使用
             DialogNormal(this, "操作提示", "系统自检通过,可正常使用!").show()
             DialogNormal(this, "操作提示", "系统自检通过,可正常使用!").show()
             // todo: 2023/4/13 启动配置库
             // todo: 2023/4/13 启动配置库
-            DatabaseConfigManager.getInstance().openConfigDatabase()
+            DatabaseBaseManager.getInstance().openConfigDatabase()
+            // todo: 2023/6/19 启用Ip和COM配置页面
+            fragIpAndCom = FragmentSetIpAndCom()
+            fragIpAndCom?.let {
+                addFragment(it, R.id.av_frm_left_big_panel)
+                hideFragment(it)
+            }
             // todo: 2023/4/13 启动无人机库
             // todo: 2023/4/13 启动无人机库
 
 
             // todo: 2023/4/6 页面初始化显示
             // todo: 2023/4/6 页面初始化显示

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

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

+ 76 - 0
app/src/main/java/com/cr/pages/FragmentImageEditor.kt

@@ -0,0 +1,76 @@
+package com.cr.pages
+
+import android.graphics.BitmapFactory
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.cr.cruav.R
+import com.cr.view.CrImageEditor
+import java.io.File
+import java.io.FileInputStream
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/6/20 11:20
+ * 描述:图片编辑页面
+ */
+class FragmentImageEditor : CrNavigationFragment() {
+    // define: 2023/6/20 图片编辑器
+    private var imageEditor: CrImageEditor? = null
+    // define: 2023/6/20 图片路径
+    private var imagePath:String?=null
+
+    /**
+     * 初始化
+     * @param inflater LayoutInflater
+     * @param container ViewGroup?
+     * @param savedInstanceState Bundle?
+     * @return View?
+     */
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        mainView = inflater.inflate(R.layout.frag_image_editor, null)
+        self = this
+        // todo: 2023/6/20 挂载控件
+        joinControls()
+        // todo: 2023/6/20 显示图片
+        showImage()
+        return mainView
+    }
+
+    /**
+     * 重写挂载控件
+     */
+    override fun joinControls() {
+        // todo: 2023/6/20 挂载图片显示控件
+        imageEditor = mainView?.findViewById(R.id.image_editor)
+    }
+
+    /**
+     * 显示图片
+     */
+    private fun showImage(){
+        imagePath?.let {
+            var file = File(it)
+            if(file.exists()) {
+                var fis = FileInputStream(it)
+                var bitmap = BitmapFactory.decodeStream(fis)
+                imageEditor?.setImageBitmap(bitmap!!)
+            }
+        }
+    }
+    /**
+     * 设置显示的图片
+     * @param imagePath String 图片路径
+     */
+    fun crSetImage(imagePath:String){
+        this.imagePath = imagePath
+        // todo: 2023/6/20 显示图片
+        showImage()
+    }
+}

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

@@ -15,8 +15,8 @@ import com.cr.data.CrUtil
 import com.cr.dialog.DialogInput
 import com.cr.dialog.DialogInput
 import com.cr.dialog.DialogNormal
 import com.cr.dialog.DialogNormal
 import com.cr.map.*
 import com.cr.map.*
-import com.cr.models.ResultModel
-import com.cr.models.iCompletion
+import com.cr.models.CompletionModel
+import com.cr.models.ICompletion
 import com.esri.arcgisruntime.arcgisservices.LabelDefinition
 import com.esri.arcgisruntime.arcgisservices.LabelDefinition
 import com.esri.arcgisruntime.data.Feature
 import com.esri.arcgisruntime.data.Feature
 import com.esri.arcgisruntime.data.FeatureTable
 import com.esri.arcgisruntime.data.FeatureTable
@@ -1150,9 +1150,9 @@ class FragmentMap : CrAnimationFragment() {
                 if (appendAsync.isDone) {
                 if (appendAsync.isDone) {
                     fLayerMedia?.clearSelection()
                     fLayerMedia?.clearSelection()
                     fLayerMedia?.selectFeature(caseFeature)
                     fLayerMedia?.selectFeature(caseFeature)
-                    caseUpdatePolygonByFeature(caseFeature, object : iCompletion {
-                        override fun onCompletion(result: ResultModel) {
-                            if (result.isSuccess == true) {
+                    caseUpdatePolygonByFeature(caseFeature, object : ICompletion<String> {
+                        override fun onCompletion(completion: CompletionModel<String>) {
+                            if (completion.isSuccess == true) {
                                 CrUtil.showMessage(
                                 CrUtil.showMessage(
                                     String.format(
                                     String.format(
                                         "案件点追加成功 %s",
                                         "案件点追加成功 %s",
@@ -1160,7 +1160,7 @@ class FragmentMap : CrAnimationFragment() {
                                     )
                                     )
                                 )
                                 )
                             } else {
                             } else {
-                                showError(result.message!!)
+                                showError(completion.result!!)
                             }
                             }
                         }
                         }
                     })
                     })
@@ -1176,7 +1176,7 @@ class FragmentMap : CrAnimationFragment() {
      * @param geom Feature 案件点要素
      * @param geom Feature 案件点要素
      * @param callback iCompletion 完成回调
      * @param callback iCompletion 完成回调
      */
      */
-    private fun caseClearPolygonByFeature(geom: Feature, callback: iCompletion) {
+    private fun caseClearPolygonByFeature(geom: Feature, callback: ICompletion<String>) {
         // todo: 2023/6/13 获取案件ID
         // todo: 2023/6/13 获取案件ID
         val caseId = geom.attributes[FIELD_CASE_NAME]
         val caseId = geom.attributes[FIELD_CASE_NAME]
         // todo: 2023/6/15 先判断是否存在与该案件点名称相同的案件图斑 将其标志清除
         // todo: 2023/6/15 先判断是否存在与该案件点名称相同的案件图斑 将其标志清除
@@ -1196,11 +1196,11 @@ class FragmentMap : CrAnimationFragment() {
                     asyncUpdate?.addDoneListener(Runnable {
                     asyncUpdate?.addDoneListener(Runnable {
                         try {
                         try {
                             if (asyncUpdate.isDone) {
                             if (asyncUpdate.isDone) {
-                                if (callback != null) callback.onCompletion(ResultModel(true, ""))
+                                if (callback != null) callback.onCompletion(CompletionModel(true, ""))
                             }
                             }
                         } catch (ex: java.lang.IllegalArgumentException) {
                         } catch (ex: java.lang.IllegalArgumentException) {
                             if (callback != null) callback.onCompletion(
                             if (callback != null) callback.onCompletion(
-                                ResultModel(
+                                CompletionModel(
                                     false,
                                     false,
                                     "案件面初始化错误!"
                                     "案件面初始化错误!"
                                 )
                                 )
@@ -1209,7 +1209,7 @@ class FragmentMap : CrAnimationFragment() {
                     })
                     })
                 }
                 }
             } catch (ex: java.lang.IllegalArgumentException) {
             } catch (ex: java.lang.IllegalArgumentException) {
-                if (callback != null) callback.onCompletion(ResultModel(false, "案件面初始化错误!"))
+                if (callback != null) callback.onCompletion(CompletionModel(false, "案件面初始化错误!"))
             }
             }
         })
         })
     }
     }
@@ -1219,12 +1219,12 @@ class FragmentMap : CrAnimationFragment() {
      * @param geom Feature 案件点
      * @param geom Feature 案件点
      * @param callback iCompletion 回调
      * @param callback iCompletion 回调
      */
      */
-    private fun caseUpdatePolygonByFeature(geom: Feature, callback: iCompletion) {
+    private fun caseUpdatePolygonByFeature(geom: Feature, callback: ICompletion<String>) {
         // todo: 2023/6/15 先进行初始化
         // todo: 2023/6/15 先进行初始化
-        caseClearPolygonByFeature(geom, object : iCompletion {
-            override fun onCompletion(result: ResultModel) {
-                if (result.isSuccess == false) {
-                    if (callback != null) callback.onCompletion(result)
+        caseClearPolygonByFeature(geom, object : ICompletion<String> {
+            override fun onCompletion(completion: CompletionModel<String>) {
+                if (completion.isSuccess == false) {
+                    if (callback != null) callback.onCompletion(completion)
                 } else {
                 } else {
                     // todo: 2023/6/13 获取案件ID
                     // todo: 2023/6/13 获取案件ID
                     val caseId = geom.attributes[FIELD_CASE_NAME]
                     val caseId = geom.attributes[FIELD_CASE_NAME]
@@ -1253,7 +1253,7 @@ class FragmentMap : CrAnimationFragment() {
                                         if (updateAsync.isDone) {
                                         if (updateAsync.isDone) {
                                             // todo: 2023/6/13 更新完成
                                             // todo: 2023/6/13 更新完成
                                             if (callback != null) callback.onCompletion(
                                             if (callback != null) callback.onCompletion(
-                                                ResultModel(
+                                                CompletionModel(
                                                     true,
                                                     true,
                                                     "成功!"
                                                     "成功!"
                                                 )
                                                 )
@@ -1261,7 +1261,7 @@ class FragmentMap : CrAnimationFragment() {
                                         }
                                         }
                                     } catch (ex: java.lang.IllegalArgumentException) {
                                     } catch (ex: java.lang.IllegalArgumentException) {
                                         if (callback != null) callback.onCompletion(
                                         if (callback != null) callback.onCompletion(
-                                            ResultModel(
+                                            CompletionModel(
                                                 false,
                                                 false,
                                                 "案件对象更新失败!"
                                                 "案件对象更新失败!"
                                             )
                                             )
@@ -1271,7 +1271,7 @@ class FragmentMap : CrAnimationFragment() {
                             }
                             }
                         } catch (ex: java.lang.IllegalArgumentException) {
                         } catch (ex: java.lang.IllegalArgumentException) {
                             if (callback != null) callback.onCompletion(
                             if (callback != null) callback.onCompletion(
-                                ResultModel(
+                                CompletionModel(
                                     false,
                                     false,
                                     "案件对象查询失败!"
                                     "案件对象查询失败!"
                                 )
                                 )
@@ -1305,12 +1305,12 @@ class FragmentMap : CrAnimationFragment() {
                         dig.setListener(object : DialogNormal.DialogNormalListener {
                         dig.setListener(object : DialogNormal.DialogNormalListener {
                             // todo: 2023/6/14 确认删除
                             // todo: 2023/6/14 确认删除
                             override fun completion() {
                             override fun completion() {
-                                caseRemoveWaypointAndUpdateCasePolygon(features,object:iCompletion{
-                                    override fun onCompletion(result: ResultModel) {
-                                        if(result.isSuccess == true){
+                                caseRemoveWaypointAndUpdateCasePolygon(features,object:ICompletion<String>{
+                                    override fun onCompletion(completion: CompletionModel<String>) {
+                                        if(completion.isSuccess == true){
                                             CrUtil.showMessage("删除成功!")
                                             CrUtil.showMessage("删除成功!")
                                         }else{
                                         }else{
-                                            showError(result.message!!)
+                                            showError(completion.result!!)
                                         }
                                         }
                                     }
                                     }
                                 })
                                 })
@@ -1337,7 +1337,7 @@ class FragmentMap : CrAnimationFragment() {
      * @param features List<Feature> 案件点集合
      * @param features List<Feature> 案件点集合
      * @param callback iCompletion 完成回调
      * @param callback iCompletion 完成回调
      */
      */
-    private fun caseRemoveWaypointAndUpdateCasePolygon(features:List<Feature>,callback: iCompletion){
+    private fun caseRemoveWaypointAndUpdateCasePolygon(features:List<Feature>,callback: ICompletion<String>){
         var deleteAsync = fTableMedia?.deleteFeaturesAsync(features)
         var deleteAsync = fTableMedia?.deleteFeaturesAsync(features)
         deleteAsync?.addDoneListener(Runnable {
         deleteAsync?.addDoneListener(Runnable {
             try {
             try {
@@ -1350,7 +1350,7 @@ class FragmentMap : CrAnimationFragment() {
                     caseUpdateCasePolygonByWhere(wheres,callback)
                     caseUpdateCasePolygonByWhere(wheres,callback)
                 }
                 }
             } catch (ex: java.lang.IllegalArgumentException) {
             } catch (ex: java.lang.IllegalArgumentException) {
-                if (callback != null) callback.onCompletion(ResultModel(false,"案件点删除失败!"))
+                if (callback != null) callback.onCompletion(CompletionModel(false,"案件点删除失败!"))
             }
             }
         })
         })
     }
     }
@@ -1360,7 +1360,7 @@ class FragmentMap : CrAnimationFragment() {
      * @param wheres List<String> 案件Id的集合
      * @param wheres List<String> 案件Id的集合
      * @param callback iCompletion 完成回调
      * @param callback iCompletion 完成回调
      */
      */
-    private fun caseUpdateCasePolygonByWhere(wheres:List<String>,callback:iCompletion){
+    private fun caseUpdateCasePolygonByWhere(wheres:List<String>,callback:ICompletion<String>){
         var updateWhere = ""
         var updateWhere = ""
         // todo: 2023/6/16 组合条件
         // todo: 2023/6/16 组合条件
         for(where in wheres){
         for(where in wheres){
@@ -1388,15 +1388,15 @@ class FragmentMap : CrAnimationFragment() {
                     asyncUpdate?.addDoneListener(Runnable {
                     asyncUpdate?.addDoneListener(Runnable {
                         try {
                         try {
                             if(asyncUpdate.isDone){
                             if(asyncUpdate.isDone){
-                                if(callback != null) callback.onCompletion(ResultModel(true,""))
+                                if(callback != null) callback.onCompletion(CompletionModel(true,""))
                             }
                             }
                         }catch (ex:java.lang.IllegalArgumentException){
                         }catch (ex:java.lang.IllegalArgumentException){
-                            if(callback != null) callback.onCompletion(ResultModel(false,"关联案件更新失败!"))
+                            if(callback != null) callback.onCompletion(CompletionModel(false,"关联案件更新失败!"))
                         }
                         }
                     })
                     })
                 }
                 }
             }catch(ex:java.lang.IllegalArgumentException) {
             }catch(ex:java.lang.IllegalArgumentException) {
-                if(callback != null) callback.onCompletion(ResultModel(false,"关联案件查询失败!"))
+                if(callback != null) callback.onCompletion(CompletionModel(false,"关联案件查询失败!"))
             }
             }
         })
         })
     }
     }
@@ -1469,9 +1469,9 @@ class FragmentMap : CrAnimationFragment() {
                         asyncUpdate?.addDoneListener(Runnable {
                         asyncUpdate?.addDoneListener(Runnable {
                             try {
                             try {
                                 if (asyncUpdate.isDone) {
                                 if (asyncUpdate.isDone) {
-                                    caseUpdatePolygonByFeature(features[0], object : iCompletion {
-                                        override fun onCompletion(result: ResultModel) {
-                                            if (result.isSuccess == true) {
+                                    caseUpdatePolygonByFeature(features[0], object : ICompletion<String> {
+                                        override fun onCompletion(completion: CompletionModel<String>) {
+                                            if (completion.isSuccess == true) {
                                                 CrUtil.showMessage("移动完成!")
                                                 CrUtil.showMessage("移动完成!")
                                                 sketchEditor?.removeGeometryChangedListener(
                                                 sketchEditor?.removeGeometryChangedListener(
                                                     sketchGeometryChangeListener
                                                     sketchGeometryChangeListener
@@ -1479,7 +1479,7 @@ class FragmentMap : CrAnimationFragment() {
                                                 sketchEditor?.stop()
                                                 sketchEditor?.stop()
                                                 fLayerMedia?.clearSelection()
                                                 fLayerMedia?.clearSelection()
                                             } else {
                                             } else {
-                                                showError(result.message!!)
+                                                showError(completion.result!!)
                                             }
                                             }
                                         }
                                         }
                                     })
                                     })

+ 37 - 4
app/src/main/java/com/cr/pages/FragmentUploadCase.kt

@@ -27,6 +27,9 @@ class FragmentUploadCase : CrNavigationFragment() {
     // todo: 2023/6/15 主页面
     // todo: 2023/6/15 主页面
     private var fragmentUploadCaseMain: FragmentUploadCaseMain? = null
     private var fragmentUploadCaseMain: FragmentUploadCaseMain? = null
 
 
+    // todo: 2023/6/20 编辑照片页面
+    private var fragmentImageEditor: FragmentImageEditor? = null
+
     /**
     /**
      * 初始化
      * 初始化
      * @param inflater LayoutInflater
      * @param inflater LayoutInflater
@@ -71,8 +74,8 @@ class FragmentUploadCase : CrNavigationFragment() {
         adapter = CrPageAdapter(this.activity!!)
         adapter = CrPageAdapter(this.activity!!)
         // todo: 2023/6/15 初始化主页面
         // todo: 2023/6/15 初始化主页面
         fragmentUploadCaseMain = FragmentUploadCaseMain()
         fragmentUploadCaseMain = FragmentUploadCaseMain()
+        fragmentUploadCaseMain?.crSetListener(caseMainListener)
         adapter?.addFragment(fragmentUploadCaseMain!!)
         adapter?.addFragment(fragmentUploadCaseMain!!)
-
         // todo: 2023/6/15 设置监听
         // todo: 2023/6/15 设置监听
         viewPager?.adapter = adapter
         viewPager?.adapter = adapter
     }
     }
@@ -81,10 +84,11 @@ class FragmentUploadCase : CrNavigationFragment() {
      * 显示页面
      * 显示页面
      * @param fragment CrNavigationFragment
      * @param fragment CrNavigationFragment
      */
      */
-    private fun showPage(fragment: CrNavigationFragment){
+    private fun showPage(fragment: CrNavigationFragment) {
         var fragments = adapter?.getFragments()
         var fragments = adapter?.getFragments()
-        for(i in 0 until fragments!!.size){
-            if(fragments?.get(i) == fragment){
+        CrUtil.print("页面数量---" + fragments?.size)
+        for (i in 0 until fragments!!.size) {
+            if (fragments?.get(i) == fragment) {
                 fragment.nvBar?.visibility = View.GONE
                 fragment.nvBar?.visibility = View.GONE
                 viewPager?.currentItem = i
                 viewPager?.currentItem = i
                 break
                 break
@@ -102,6 +106,24 @@ class FragmentUploadCase : CrNavigationFragment() {
     }
     }
 
 
     /**
     /**
+     * 上传主页监听
+     */
+    private val caseMainListener = object : FragmentUploadCaseMain.IOperationListener {
+        // todo: 2023/6/20 编辑照片操作回调
+        override fun onEditImage(imagePath: String) {
+            nvBar?.crSetTitle(R.string.upload_case_title_image_editor)
+            nvBar?.crSetVisible(backIsVisible = true, dismissIsVisible = false)
+            // todo: 2023/6/20 初始化照片编辑页面
+            fragmentImageEditor = FragmentImageEditor()
+            adapter?.addFragment(fragmentImageEditor!!)
+            // todo: 2023/6/20 设置显示的照片
+            fragmentImageEditor?.crSetImage(imagePath)
+            // todo: 2023/6/20 显示页面
+            showPage(fragmentImageEditor!!)
+        }
+    }
+
+    /**
      * 设置关联的案件
      * 设置关联的案件
      * @param joinCase CaseModel 关联案件
      * @param joinCase CaseModel 关联案件
      */
      */
@@ -116,4 +138,15 @@ class FragmentUploadCase : CrNavigationFragment() {
     override fun onDismiss() {
     override fun onDismiss() {
         CrApplication.getEventBus().post(EventFragmentBarAction(self!!, BarAction.ACTION_DISMISS))
         CrApplication.getEventBus().post(EventFragmentBarAction(self!!, BarAction.ACTION_DISMISS))
     }
     }
+
+    /**
+     * 重写回退事件
+     */
+    override fun onGotoBack() {
+        // todo: 2023/6/20 删除刚刚加载的页面
+        adapter?.removeLastFragment()
+        // todo: 2023/6/20 初始化任务栏
+        initBar()
+
+    }
 }
 }

+ 70 - 5
app/src/main/java/com/cr/pages/FragmentUploadCaseMain.kt

@@ -12,9 +12,12 @@ import android.widget.TextView
 import com.cr.common.CrPictureManager
 import com.cr.common.CrPictureManager
 import com.cr.common.CrFileManager
 import com.cr.common.CrFileManager
 import com.cr.common.CrUnitManager
 import com.cr.common.CrUnitManager
+import com.cr.common.DataManager
 import com.cr.cruav.R
 import com.cr.cruav.R
 import com.cr.data.CrUtil
 import com.cr.data.CrUtil
 import com.cr.map.CaseModel
 import com.cr.map.CaseModel
+import com.cr.models.CompletionModel
+import com.cr.models.ICompletion
 import com.cr.widget.CrImageBrowserWidget
 import com.cr.widget.CrImageBrowserWidget
 
 
 /**
 /**
@@ -24,6 +27,14 @@ import com.cr.widget.CrImageBrowserWidget
  * 描述:案件上传主页面
  * 描述:案件上传主页面
  */
  */
 class FragmentUploadCaseMain : CrNavigationFragment(), View.OnClickListener {
 class FragmentUploadCaseMain : CrNavigationFragment(), View.OnClickListener {
+    /**
+     * 操作接口
+     */
+    interface IOperationListener {
+        // todo: 2023/6/20 编辑照片
+        fun onEditImage(imagePath: String)
+    }
+
     companion object {
     companion object {
         const val OPEN_ALBUM = 3  // define: 2023/6/16 相册
         const val OPEN_ALBUM = 3  // define: 2023/6/16 相册
     }
     }
@@ -39,6 +50,8 @@ class FragmentUploadCaseMain : CrNavigationFragment(), View.OnClickListener {
     private var imageBrowser: CrImageBrowserWidget? = null // define: 2023/6/16 图片浏览控件
     private var imageBrowser: CrImageBrowserWidget? = null // define: 2023/6/16 图片浏览控件
 
 
     private var joinCase: CaseModel? = null // define: 2023/6/15 关联的案件点
     private var joinCase: CaseModel? = null // define: 2023/6/15 关联的案件点
+    private var listener: IOperationListener? = null // define: 2023/6/20 监听
+    private var cursorImageName: String? = null // define: 2023/6/20 照片名称
 
 
     /**
     /**
      * 初始化
      * 初始化
@@ -89,10 +102,11 @@ class FragmentUploadCaseMain : CrNavigationFragment(), View.OnClickListener {
     }
     }
 
 
     // todo: 2023/6/17 滑动监听
     // todo: 2023/6/17 滑动监听
-    private val imageBrowserListener = object :CrImageBrowserWidget.iChangeListener{
+    private val imageBrowserListener = object : CrImageBrowserWidget.iChangeListener {
         // todo: 2023/6/17 滑动监听
         // todo: 2023/6/17 滑动监听
         override fun onChange(file: CrImageBrowserWidget.ImageFileModel?) {
         override fun onChange(file: CrImageBrowserWidget.ImageFileModel?) {
-            lblCaseMediaName?.text = file?.fileName
+            cursorImageName = file?.fileName
+            lblCaseMediaName?.text = cursorImageName
             lblCaseMediaSize?.text = file?.fileSizeDescription
             lblCaseMediaSize?.text = file?.fileSizeDescription
         }
         }
     }
     }
@@ -105,7 +119,11 @@ class FragmentUploadCaseMain : CrNavigationFragment(), View.OnClickListener {
         when (view?.id) {
         when (view?.id) {
             // todo: 2023/6/15 编辑照片
             // todo: 2023/6/15 编辑照片
             R.id.case_btn_edit -> {
             R.id.case_btn_edit -> {
-
+                if (cursorImageName == null){
+                    showWarning("未选择需要编辑的照片!")
+                }else{
+                    if(listener != null) listener?.onEditImage(String.format("%s%s",CrUtil.IMAGE_PATH,cursorImageName))
+                }
             }
             }
             // todo: 2023/6/15 打开相册
             // todo: 2023/6/15 打开相册
             R.id.case_btn_photo -> {
             R.id.case_btn_photo -> {
@@ -129,10 +147,24 @@ class FragmentUploadCaseMain : CrNavigationFragment(), View.OnClickListener {
         this.joinCase = joinCase
         this.joinCase = joinCase
         // todo: 2023/6/15 设置显示内容
         // todo: 2023/6/15 设置显示内容
         lblCaseName?.text = this.joinCase?.name
         lblCaseName?.text = this.joinCase?.name
-        lblCaseImageCount?.text = String.format("取证照片[%s]张", this.joinCase?.imgArray?.size)
         lblCaseCreateDate?.text = this.joinCase?.date
         lblCaseCreateDate?.text = this.joinCase?.date
+        lblCaseImageCount?.text = String.format("取证照片[%s]张", this.joinCase?.imgArray?.size)
         lblCaseMediaName?.text = ""
         lblCaseMediaName?.text = ""
         lblCaseMediaSize?.text = ""
         lblCaseMediaSize?.text = ""
+        // todo: 2023/6/20 查询数据库中数据
+        DataManager.appQueryImages(this.joinCase!!.name!!, object : ICompletion<List<String>> {
+            override fun onCompletion(completion: CompletionModel<List<String>>) {
+                if (completion.isSuccess == true) {
+                    // todo: 2023/6/20 更新显示
+                    lblCaseImageCount?.text = String.format("取证照片[%s]张", completion.result!!.size)
+                    // todo: 2023/6/20 追加到照片浏览器中
+                    for (imgName in completion.result!!) {
+                        var imgPath = String.format("%s%s", CrUtil.IMAGE_PATH, imgName)
+                        imageBrowser?.crAppendImage(imgPath)
+                    }
+                }
+            }
+        })
     }
     }
 
 
     /**
     /**
@@ -156,7 +188,35 @@ class FragmentUploadCaseMain : CrNavigationFragment(), View.OnClickListener {
                     String.format("%sUAV%s.jpg", CrUtil.IMAGE_PATH, CrUnitManager.toSystemDate())
                     String.format("%sUAV%s.jpg", CrUtil.IMAGE_PATH, CrUnitManager.toSystemDate())
                 var res = CrFileManager.copyFile(imagePath, newFilePath)
                 var res = CrFileManager.copyFile(imagePath, newFilePath)
                 if (res) {
                 if (res) {
-                    imageBrowser?.crAppendImage(newFilePath)
+                    // todo: 2023/6/19 先存储到数据库
+                    var fileName = CrFileManager.getFileName(newFilePath)
+                    var model = CaseModel()
+                    model.name = this.joinCase!!.name
+                    model.imgName = fileName
+                    DataManager.appAppendImages(model, object : ICompletion<String> {
+                        override fun onCompletion(completion: CompletionModel<String>) {
+                            if (completion.isSuccess == true) {
+                                // todo: 2023/6/20 添加到照片容器
+                                imageBrowser?.crAppendImage(newFilePath)
+                                // todo: 2023/6/20 刷新照片熟练
+                                DataManager.appQueryImages(
+                                    joinCase!!.name!!,
+                                    object : ICompletion<List<String>> {
+                                        override fun onCompletion(completion: CompletionModel<List<String>>) {
+                                            if (completion.isSuccess == true) {
+                                                // todo: 2023/6/20 更新显示
+                                                lblCaseImageCount?.text = String.format(
+                                                    "取证照片[%s]张",
+                                                    completion.result!!.size
+                                                )
+                                            }
+                                        }
+                                    })
+                            } else {
+                                showError(completion.result!!)
+                            }
+                        }
+                    })
                 } else {
                 } else {
                     showError("文件转存失败!")
                     showError("文件转存失败!")
                 }
                 }
@@ -165,4 +225,9 @@ class FragmentUploadCaseMain : CrNavigationFragment(), View.OnClickListener {
             }
             }
         }
         }
     }
     }
+
+    // todo: 2023/6/20 设置监听
+    fun crSetListener(listener: IOperationListener) {
+        this.listener = listener
+    }
 }
 }

+ 216 - 0
app/src/main/java/com/cr/view/CrImageEditor.kt

@@ -0,0 +1,216 @@
+package com.cr.view
+
+import android.content.Context
+import android.graphics.*
+import android.util.AttributeSet
+import android.view.GestureDetector
+import android.view.MotionEvent
+import android.view.ScaleGestureDetector
+import androidx.appcompat.widget.AppCompatImageView
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/6/20 11:03
+ * 描述:图片编辑视图
+ */
+class CrImageEditor @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null
+) : AppCompatImageView(context, attrs) {
+    // define: 2023/6/20 缩放
+    private var mScaleGestureDetector: ScaleGestureDetector? = null
+
+    // define: 2023/6/20 平移
+    private var mGestureDetector: GestureDetector? = null
+
+    // todo: 2023/6/20 缩放平移矩阵
+    private var mCurrentMatrix = Matrix()
+
+    // todo: 2023/6/20 最小缩放
+    private var mCenterX: Float? = 0f
+    private var mCenterY: Float? = 0f
+
+    // todo: 2023/6/20 点击位置点集合
+    private var drawPoints = mutableListOf<PointF>()
+
+    // todo: 2023/6/21 绘制点集合
+    private var downPoints = mutableListOf<PointF>()
+
+    // todo: 2023/6/20 画笔
+    private var drawPointPaint = Paint()
+    private var drawLinePaint = Paint()
+
+    /**
+     * 缩放监听
+     */
+    private val mScaleListener = object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
+        // todo: 2023/6/20 缩放开始
+        override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean {
+            return true
+        }
+
+        // todo: 2023/6/20 缩放中
+        override fun onScale(detector: ScaleGestureDetector?): Boolean {
+            var scaleFactor = detector?.scaleFactor
+            if (mCenterX == 0f) {
+                // todo: 2023/6/20 最小X轴缩放
+                mCenterX = width / 2f
+            }
+            if (mCenterY == 0f) {
+                // todo: 2023/6/20 最小Y轴缩放
+                mCenterY = height / 2f
+            }
+            // todo: 2023/6/21 缩放变换
+            mCurrentMatrix.postScale(scaleFactor!!, scaleFactor!!, mCenterX!!, mCenterY!!)
+            invalidate()
+            return true
+        }
+
+        // todo: 2023/6/20 缩放结束
+        override fun onScaleEnd(detector: ScaleGestureDetector?) {
+
+        }
+    }
+
+
+    /**
+     * 平移监听
+     */
+    private val mTranslationListener = object : GestureDetector.SimpleOnGestureListener() {
+        // todo: 2023/6/20 单击确认
+        override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
+            // todo: 2023/6/20 单击绘制一个点 试试
+            e?.let {
+                var point = PointF(it.x, it.y)
+                // todo: 2023/6/21 由于缩放后点击,点击位置已经经过矩阵变换,为统一在重绘时变换,需要逆向变换一次
+                downPoints.add(calculateInversePointF(point, mCurrentMatrix))
+                // todo: 2023/6/21 重绘
+                invalidate()
+            }
+            return true
+        }
+
+        // todo: 2023/6/20 移动
+        override fun onScroll(
+            e1: MotionEvent?,
+            e2: MotionEvent?,
+            distanceX: Float,
+            distanceY: Float
+        ): Boolean {
+            // todo: 2023/6/21 设置变化矩阵
+            mCurrentMatrix.postTranslate(-distanceX, -distanceY)
+            // todo: 2023/6/21 重绘
+            invalidate()
+            return true
+        }
+    }
+
+    /**
+     * 根据矩阵计算点位置
+     * @param pointF PointF 变化前
+     * @param matrix Matrix 矩阵
+     * @return PointF 变化后
+     */
+    private fun calculatePointF(pointF: PointF, matrix: Matrix): PointF {
+        // todo: 2023/6/21 返回点
+        var resPointF = PointF()
+        // todo: 2023/6/21 获取矩阵数据
+        var matrixValue = FloatArray(9)
+        matrix.getValues(matrixValue)
+        // todo: 2023/6/21 计算
+        resPointF.x = pointF.x * matrixValue[0] + matrixValue[2]
+        resPointF.y = pointF.y * matrixValue[4] + matrixValue[5]
+        // todo: 2023/6/21 返回
+        return resPointF
+    }
+
+    /**
+     * 根据矩阵反向计算点位置
+     * @param pointF PointF 变化前
+     * @param matrix Matrix 变换矩阵
+     * @return PointF 变化后
+     */
+    private fun calculateInversePointF(pointF: PointF, matrix: Matrix): PointF {
+        // todo: 2023/6/21 返回点
+        var resPointF = PointF()
+        // todo: 2023/6/21 反转矩阵
+        var inverseMatrix = Matrix()
+        matrix.invert(inverseMatrix)
+        // todo: 2023/6/21 获取矩阵数据
+        var matrixValue = FloatArray(9)
+        inverseMatrix.getValues(matrixValue)
+        // todo: 2023/6/21 计算
+        resPointF.x = pointF.x * matrixValue[0] + matrixValue[2]
+        resPointF.y = pointF.y * matrixValue[4] + matrixValue[5]
+        // todo: 2023/6/21 返回
+        return resPointF
+    }
+
+
+    /**
+     * 初始化
+     */
+    init {
+        // todo: 2023/6/20 初始化平移、缩放监听
+        mScaleGestureDetector = ScaleGestureDetector(context, mScaleListener)
+        mGestureDetector = GestureDetector(context, mTranslationListener)
+        // todo: 2023/6/20 初始化点画笔
+        drawPointPaint.color = Color.BLUE
+        drawPointPaint.isAntiAlias = true
+        drawPointPaint.strokeWidth = 20f
+        // todo: 2023/6/20 初始化线画笔
+        drawLinePaint.color = Color.RED
+        drawLinePaint.isAntiAlias = true
+        drawLinePaint.strokeWidth = 5.0f
+    }
+
+    /**
+     * 绘制
+     * @param canvas Canvas
+     */
+    override fun onDraw(canvas: Canvas?) {
+        var saveCount = canvas?.save()
+        canvas?.concat(mCurrentMatrix)
+        super.onDraw(canvas)
+        canvas?.restoreToCount(saveCount!!)
+
+        // todo: 2023/6/21 变换
+        drawPoints.clear()
+        for (point in downPoints) {
+            drawPoints.add(calculatePointF(point, mCurrentMatrix))
+        }
+
+        // todo: 2023/6/20 绘制点
+        for (point in drawPoints) {
+            canvas?.drawPoint(point.x, point.y, drawPointPaint)
+        }
+        // todo: 2023/6/20 绘制线
+        if (drawPoints.size > 1) {
+            var points = mutableListOf<Float>()
+            for (i in 0 until drawPoints.size - 1) {
+                var point1 = drawPoints[i]
+                var point2 = drawPoints[i + 1]
+                points.add(point1.x)
+                points.add(point1.y)
+                points.add(point2.x)
+                points.add(point2.y)
+            }
+            canvas?.drawLines(points.toFloatArray(), drawLinePaint)
+        }
+    }
+
+    /**
+     * 覆写Touch事件
+     * @param event MotionEvent
+     * @return Boolean
+     */
+    override fun onTouchEvent(event: MotionEvent?): Boolean {
+        // todo: 2023/6/20 这里将触摸事件转接给ScaleGestureDetector与GestureDetector
+        mScaleGestureDetector?.onTouchEvent(event)
+        if (mScaleGestureDetector?.isInProgress == false) {
+            mGestureDetector?.onTouchEvent(event)
+        }
+        return true
+    }
+}

+ 1 - 1
app/src/main/java/com/cr/widget/CrImageBrowserWidget.kt

@@ -55,7 +55,7 @@ class CrImageBrowserWidget @JvmOverloads constructor(
         // todo: 2023/6/16 设置适配器
         // todo: 2023/6/16 设置适配器
         adapter = BaseAdapter(dataList)
         adapter = BaseAdapter(dataList)
         viewPager?.adapter = adapter
         viewPager?.adapter = adapter
-        // todo: 2023/6/17 设置监听
+        // todo: 2023/6/17 设置监听 此处设置监听会导致空引用 后期处理
 //        viewPager?.registerOnPageChangeCallback(pageChangeListener)
 //        viewPager?.registerOnPageChangeCallback(pageChangeListener)
     }
     }
 
 

+ 25 - 0
app/src/main/res/drawable/back_seek_bar.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <!--未划过部分滑轨颜色-->
+    <item
+        android:id="@android:id/background"
+        android:height="@dimen/cr_4_dp"
+        android:gravity="center">
+        <shape>
+            <corners android:radius="@dimen/cr_67_dp"/>
+            <solid android:color="#ff51495e"/>
+        </shape>
+    </item>
+    <!--划过部分滑轨颜色-->
+    <item
+        android:id="@android:id/progress"
+        android:height="@dimen/cr_6_dp"
+        android:gravity="center">
+        <clip>
+            <shape>
+                <corners android:radius="@dimen/cr_67_dp"/>
+                <solid android:color="#ffffff"/>
+            </shape>
+        </clip>
+    </item>
+</layer-list>

+ 9 - 0
app/src/main/res/drawable/seek_bar_thumb.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="#ffff00"/>
+    <size android:width="@dimen/cr_14_dp"
+        android:height="@dimen/cr_14_dp"/>
+    <stroke android:color="#ffffff"
+        android:width="@dimen/cr_1_dp"/>
+</shape>

+ 134 - 0
app/src/main/res/layout/frag_image_editor.xml

@@ -0,0 +1,134 @@
+<?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">
+    <!--图片编辑控件-->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="horizontal"
+        android:layout_weight="1">
+        <com.cr.view.CrImageEditor
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/image_editor"/>
+    </LinearLayout>
+    <View style="@style/view_split_h1"/>
+    <!--操作-->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/cr_44_dp">
+        <!--线条颜色-->
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:orientation="vertical">
+            <TextView
+                style="@style/lbl_title_common"
+                android:layout_width="match_parent"
+                android:gravity="center"
+                android:text="@string/fie_title_line_color" />
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:gravity="center_vertical">
+                <LinearLayout
+                    style="@style/fie_line_color_button"
+                    android:background="@color/line_1"
+                    android:id="@+id/btn_line_color1"/>
+                <LinearLayout
+                    style="@style/fie_line_color_button"
+                    android:background="@color/line_2"
+                    android:id="@+id/btn_line_color2"/>
+                <LinearLayout
+                    style="@style/fie_line_color_button"
+                    android:background="@color/line_3"
+                    android:id="@+id/btn_line_color3"/>
+                <LinearLayout
+                    style="@style/fie_line_color_button"
+                    android:background="@color/line_4"
+                    android:id="@+id/btn_line_color4"/>
+                <LinearLayout
+                    style="@style/fie_line_color_button"
+                    android:background="@color/line_5"
+                    android:id="@+id/btn_line_color5"/>
+            </LinearLayout>
+        </LinearLayout>
+        <View style="@style/view_split_v1"/>
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:orientation="vertical">
+            <TextView
+                style="@style/lbl_title_common"
+                android:layout_width="match_parent"
+                android:gravity="center"
+                android:text="@string/fie_title_lien_width" />
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:gravity="center">
+                <SeekBar
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:progressDrawable="@drawable/back_seek_bar"
+                    android:thumb="@drawable/seek_bar_thumb"
+                    android:max="10"
+                    android:min="0"
+                    android:splitTrack="false"
+                    android:progress="5"/>
+            </LinearLayout>
+        </LinearLayout>
+        <View style="@style/view_split_v1"/>
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:gravity="center_vertical">
+            <LinearLayout
+                style="@style/button_panel"
+                android:id="@+id/btn_back">
+                <ImageView
+                    style="@style/button_image"
+                    android:src="@drawable/goto_back"/>
+                <TextView
+                    style="@style/button_title"
+                    android:text="@string/fie_btn_back"/>
+            </LinearLayout>
+            <LinearLayout
+                style="@style/button_panel"
+                android:id="@+id/btn_reset">
+                <ImageView
+                    style="@style/button_image"
+                    android:src="@drawable/tools_window"/>
+                <TextView
+                    style="@style/button_title"
+                    android:text="@string/fie_btn_reset"/>
+            </LinearLayout>
+            <LinearLayout
+                style="@style/button_panel"
+                android:id="@+id/btn_save">
+                <ImageView
+                    style="@style/button_image"
+                    android:src="@drawable/ty_save"/>
+                <TextView
+                    style="@style/button_title"
+                    android:text="@string/fie_btn_save"/>
+            </LinearLayout>
+            <LinearLayout
+                style="@style/button_panel"
+                android:id="@+id/btn_recover">
+                <ImageView
+                    style="@style/button_image"
+                    android:src="@drawable/tools_ty"/>
+                <TextView
+                    style="@style/button_title"
+                    android:text="@string/fie_btn_recover"/>
+            </LinearLayout>
+        </LinearLayout>
+    </LinearLayout>
+</LinearLayout>

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

@@ -19,6 +19,11 @@
     <color name="switch_off">#9e9e9e</color>
     <color name="switch_off">#9e9e9e</color>
     <color name="switch_on">#34db35</color>
     <color name="switch_on">#34db35</color>
 
 
+    <color name="line_1">#F8F732</color>
+    <color name="line_2">#11FF5E</color>
+    <color name="line_3">#1B4CFF</color>
+    <color name="line_4">#FF0000</color>
+    <color name="line_5">#0D93F2</color>
 
 
     <!--常用颜色-->
     <!--常用颜色-->
     <color name="white">#FFFFFF</color>
     <color name="white">#FFFFFF</color>

+ 11 - 1
app/src/main/res/values/strings.xml

@@ -136,6 +136,7 @@
 
 
     <!--案件上传相关-->
     <!--案件上传相关-->
     <string name="upload_case_title_main">案件上传</string>
     <string name="upload_case_title_main">案件上传</string>
+    <string name="upload_case_title_image_editor">照片编辑</string>
     <string name="ucm_lbl_name">20230615124325</string>
     <string name="ucm_lbl_name">20230615124325</string>
     <string name="ucm_lbl_description">取证照片[10]张</string>
     <string name="ucm_lbl_description">取证照片[10]张</string>
     <string name="ucm_lbl_date">2023-06-15 12:00:00</string>
     <string name="ucm_lbl_date">2023-06-15 12:00:00</string>
@@ -147,6 +148,14 @@
     <string name="ucm_btn_photo">相册</string>
     <string name="ucm_btn_photo">相册</string>
     <string name="ucm_btn_upload">上传</string>
     <string name="ucm_btn_upload">上传</string>
 
 
+    <!--照片编辑页面相关-->
+    <string name="fie_title_line_color">线条颜色</string>
+    <string name="fie_title_lien_width">线条宽度</string>
+    <string name="fie_btn_back">回退</string>
+    <string name="fie_btn_reset">重绘</string>
+    <string name="fie_btn_save">保存</string>
+    <string name="fie_btn_recover">恢复</string>
+
     <!--字体-->
     <!--字体-->
     <string name="ico_nv_left" translatable="false">&#xe60b;</string>
     <string name="ico_nv_left" translatable="false">&#xe60b;</string>
     <string name="ico_nv_right" translatable="false">&#xe81a;</string>
     <string name="ico_nv_right" translatable="false">&#xe81a;</string>
@@ -163,6 +172,7 @@
     <string name="ico_undo">&#xe6ce;</string>
     <string name="ico_undo">&#xe6ce;</string>
     <string name="ico_redo">&#xe6cc;</string>
     <string name="ico_redo">&#xe6cc;</string>
     <string name="ico_move">&#xe8c9;</string>
     <string name="ico_move">&#xe8c9;</string>
-
+    <string name="ico_recover">&#xe672;</string>
+    <string name="ico_reset">&#xe6cb;</string>
 
 
 </resources>
 </resources>

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

@@ -210,7 +210,7 @@
     <style name="lbl_title_common">
     <style name="lbl_title_common">
         <item name="android:layout_width">wrap_content</item>
         <item name="android:layout_width">wrap_content</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:layout_height">wrap_content</item>
-        <item name="android:textSize">@dimen/sp_15</item>
+        <item name="android:textSize">@dimen/sp_11</item>
         <item name="android:layout_marginRight">@dimen/common_margin</item>
         <item name="android:layout_marginRight">@dimen/common_margin</item>
         <item name="android:textColor">@color/yellow</item>
         <item name="android:textColor">@color/yellow</item>
     </style>
     </style>
@@ -343,6 +343,15 @@
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_weight">1</item>
         <item name="android:layout_weight">1</item>
     </style>
     </style>
+    <!--图片编辑页面线条颜色控制按钮样式-->
+    <style name="fie_line_color_button">
+        <item name="android:layout_width">@dimen/cr_24_dp</item>
+        <item name="android:layout_height">@dimen/cr_24_dp</item>
+        <item name="android:clickable">true</item>
+        <item name="android:layout_marginLeft">@dimen/cr_4_dp</item>
+        <item name="android:layout_marginRight">@dimen/cr_4_dp</item>
+        <item name="android:orientation">horizontal</item>
+    </style>
 
 
     <!--自定义文本框属性-->
     <!--自定义文本框属性-->
     <declare-styleable name="ViewEditTextProperty">
     <declare-styleable name="ViewEditTextProperty">