Procházet zdrojové kódy

1、数据库操作完善
2、JSON数据读取、模型转换为JSON公共方法开发

不会爬树的猴 před 2 roky
rodič
revize
29d2f7b5d1

+ 1 - 1
app/build.gradle

@@ -14,7 +14,7 @@ android {
         minSdkVersion 24
         targetSdkVersion 30
         versionCode 1
-        versionName "1.0"
+        versionName "V1.0.0"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         multiDexEnabled true
         ndk {

+ 2 - 2
app/src/main/AndroidManifest.xml

@@ -34,9 +34,9 @@
     <application
         android:name=".CrApplication"
         android:allowBackup="true"
-        android:icon="@mipmap/ic_launcher"
+        android:icon="@drawable/app_icon"
         android:label="@string/app_name"
-        android:roundIcon="@mipmap/ic_launcher_round"
+        android:roundIcon="@drawable/app_icon"
         android:supportsRtl="true"
         android:theme="@style/Theme.DJIV5Demo">
         <activity

+ 85 - 0
app/src/main/java/com/cr/common/ClassManager.java

@@ -0,0 +1,85 @@
+package com.cr.common;
+
+import com.cr.models.iNetDataModel;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+/**
+ * 作者:王成
+ * 平台:MAC
+ * 用户:wc
+ * 创建日期: 2021/11/1 14:23
+ * 描述:类解析管理器
+ */
+public class ClassManager {
+    /**
+     *
+     * 描述: 转换类的全部字段内容 组合为JSONObject
+     *
+     * 作者: 王成
+     * 创建日期: 2021/11/1 14:26
+     * 操作系统: MAC
+     * @param object 类实例
+     * @return JSONObject
+     */
+    public static JSONObject fieldsToJSONObject(Object object){
+        JSONObject jsonObj = new JSONObject();
+        // TODO: 2022/9/9 加入本类
+        toJSONObject(jsonObj,object);
+        return jsonObj;
+    }
+
+    /**
+     * 将类的字段加入JSONObject
+     * @param jsonObj 接受字符串的JSONObject
+     * @param object 类
+     */
+    private static void toJSONObject(JSONObject jsonObj,Object object){
+        for(Field field : object.getClass().getFields()){
+            String fldName = field.getName();
+            try {
+                String fldValue = "";
+                Class cls = field.getType();
+                if(cls == String.class){
+                    fldValue = (String)field.get(object);
+                    jsonObj.put(fldName,fldValue);
+                }else if(cls.isEnum()){
+                    Object obj = field.get(object);
+                }else if(iNetDataModel.class.isAssignableFrom(cls)){
+                    iNetDataModel model = (iNetDataModel) field.get(object);
+                    jsonObj.put(fldName,model.toJSON());
+                } else if(cls.isAssignableFrom(List.class)){
+                    // TODO: 2022/8/22 获取存储的数组
+                    List<Object> value = (List<Object>)field.get(object);
+                    if(value == null || value.size() == 0) continue;
+                    // TODO: 2022/8/22 获取第一个值
+                    Object fistValue = value.get(0);
+                    // TODO: 2022/8/22 判断类型
+                    Class clsSub = fistValue.getClass();
+                    if(clsSub == String.class){
+                        String outJSON = "";
+                        for(Object obj :value){
+                            if(outJSON.equals("")){
+                                outJSON = String.format("\"%s\"",obj.toString());
+                            }else{
+                                outJSON += "," + String.format("\"%s\"",obj.toString());
+                            }
+                        }
+                        jsonObj.put(fldName,String.format("[%s]",outJSON));
+                    }else if(iNetDataModel.class.isAssignableFrom(clsSub)){
+                        List<iNetDataModel> listValue = (List<iNetDataModel>)field.get(object);
+                        jsonObj.put(fldName,JSONManager.transformToString(listValue));
+                    }
+                }
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }catch (JSONException e){
+                e.printStackTrace();
+            }
+        }
+    }
+}

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

@@ -1,6 +1,7 @@
 package com.cr.common
 
 import com.cr.models.IPAndComModel
+import com.cr.models.UserModel
 
 /**
  * 操作系统:MAC系统
@@ -58,9 +59,9 @@ class DataManager {
          * @return Boolean
          */
         fun updateNetworkChecked(item:IPAndComModel,isChecked:Boolean):Boolean{
-            var where:String  = "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 values = hashMapOf<String,String>("checked" to checkedValue)
+            var values = hashMapOf("checked" to checkedValue)
             return DatabaseManager.getInstance().update("ipcom",values,where)
         }
 
@@ -70,7 +71,7 @@ class DataManager {
          * @return Boolean
          */
         fun insertNetworkLink(item:IPAndComModel):Boolean{
-            var values = hashMapOf<String,String>("checked" to "1","ip" to item.ip,"com" to item.com,"server" to item.serverName)
+            var values = hashMapOf("checked" to "1","ip" to item.ip,"com" to item.com,"server" to item.serverName)
             return DatabaseManager.getInstance().insert("ipcom",values)
         }
 
@@ -79,8 +80,48 @@ class DataManager {
          * @return Boolean
          */
         fun cancelNetworkChecked():Boolean{
-            var values = hashMapOf<String,String>("checked" to "0")
+            var values = hashMapOf("checked" to "0")
             return DatabaseManager.getInstance().update("ipcom",values,"")
         }
+
+        /**
+         * 存储账号和密码
+         * @param userName String 账号
+         * @param password String 密码
+         * @return Boolean
+         */
+        fun saveUser(userName:String,password:String):Boolean{
+            // todo: 2023/4/6 由于只保留一条数据 保存前先删除
+            deleteUser()
+            // todo: 2023/4/6 定义插入数据
+            var userMap:HashMap<String,String> = hashMapOf()
+            userMap["name"] = userName
+            userMap["password"] = password
+            userMap["issave"] = "1"
+            return DatabaseManager.getInstance().insert("user",userMap)
+        }
+
+        /**
+         * 删除账号和密码
+         * @return Boolean
+         */
+        fun deleteUser():Boolean{
+            return DatabaseManager.getInstance().delete("user","")
+        }
+
+        /**
+         * 获取存储的账号信息
+         * @return UserModel
+         */
+        fun getUser():UserModel{
+            var user = UserModel()
+            var sql = "SELECT * FROM user"
+            var qList:List<HashMap<String,String>> = DatabaseManager.getInstance().query(sql)
+            if (qList != null && qList.isNotEmpty()){
+                user.userId = qList[0]["name"]
+                user.userPwd = qList[0]["password"]
+            }
+            return user
+        }
     }
 }

+ 11 - 0
app/src/main/java/com/cr/common/DatabaseManager.kt

@@ -86,6 +86,17 @@ class DatabaseManager {
     }
 
     /**
+     * 删除数据
+     * @param tabName String 表名
+     * @param where String 条件
+     * @return Boolean
+     */
+    fun delete(tabName:String,where:String):Boolean{
+        var resInt = sqLiteDatabaseConfig?.delete(tabName,where,null)
+        return resInt!! > 0
+    }
+
+    /**
      * 插入数据
      * @param tabName String 表名
      * @param values HashMap<String, String> 插入集合

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

@@ -0,0 +1,267 @@
+package com.cr.common;
+
+import com.cr.models.iNetDataModel;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.*;
+
+/**
+ * 作者:王成
+ * 平台:MAC
+ * 用户:wc
+ * 创建日期: 2021/7/29 11:17
+ * 描述:JSON管理器
+ */
+public class JSONManager {
+    /**
+     * 网络交互正常 成功标识
+     */
+    private static String RES_OK = "RES_OK";
+    /**
+     * 网络交互正常 失败标识
+     */
+    private static String RES_NO = "RES_NO";
+    /**
+     * 网络交互正常 错误标识
+     */
+    private static String RES_ERR = "RES_ERR";
+
+    /**
+     * 将模型输出为JSON
+     *
+     * @param model 模型实例
+     * @return JSON
+     */
+    public static String toJSON(iNetDataModel model) {
+        String res = "{" + String.format("\"res\":\"%s\",\"data\":[%s]", RES_OK, model.toJSON()) + "}";
+        return res;
+    }
+
+    /**
+     * 字符串包装成JSON
+     *
+     * @param str 字符串
+     * @return 包装后的内容
+     */
+    public static String strToJSON(String str) {
+        String res = "{" + String.format("\"res\":\"%s\",\"data\":[%s]", RES_OK, str) + "}";
+        return res;
+    }
+
+    /**
+     * 将数据集输出JSON字符串
+     *
+     * @param modelList
+     * @return
+     */
+    public static String toJSONToo(List<? extends iNetDataModel> modelList) {
+        String res = "";
+        StringBuilder jsonBuilder = new StringBuilder();
+        for (iNetDataModel model : modelList) {
+            if (jsonBuilder.length() == 0) {
+                jsonBuilder.append(model.toJSON());
+            } else {
+                jsonBuilder.append(",").append(model.toJSON());
+            }
+        }
+        if (modelList.size() > 0) {
+            res = "{" + String.format("\"res\":\"%s\",\"data\":[%s]", RES_OK, jsonBuilder) + "}";
+        } else {
+            JSONObject obj = new JSONObject();
+            try {
+                obj.put("code", "1002");
+                obj.put("msg", "未查询到符合条件的数据!");
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+            res = "{" + String.format("\"res\":\"%s\",\"data\":[%s]", RES_NO, obj) + "}";
+        }
+
+        return res;
+    }
+
+    /**
+     * 转换错误描述JSON
+     *
+     * @param errCode    错误代码
+     * @param errMessage 错误内容
+     * @return 错误描述JSON字符串
+     */
+    public static String toJSONError(String errCode, String errMessage) {
+        JSONObject obj = new JSONObject();
+        try {
+            obj.put("code", errCode);
+            obj.put("msg", errMessage);
+        }catch (JSONException e){
+            e.printStackTrace();
+        }
+        String res = "{" + String.format("\"res\":\"%s\",\"data\":[%s]", RES_ERR, obj) + "}";
+        return res;
+    }
+
+    /**
+     * 转换执行成功描述JSON
+     *
+     * @param errCode    代码
+     * @param errMessage 内容
+     * @return 成功描述JSON字符串
+     */
+    public static String toJSONSuccess(String errCode, String errMessage) {
+        JSONObject obj = new JSONObject();
+        try{
+            obj.put("code", errCode);
+            obj.put("msg", errMessage);
+        }catch (JSONException e){
+            e.printStackTrace();
+        }
+        String res = "{" + String.format("\"res\":\"%s\",\"data\":[%s]", RES_OK, obj) + "}";
+        return res;
+    }
+
+    /**
+     * 转换执行无数据描述JSON
+     *
+     * @param errCode    代码
+     * @param errMessage 内容
+     * @return 无数据描述JSON字符串
+     */
+    public static String toJSONNodata(String errCode, String errMessage) {
+        JSONObject obj = new JSONObject();
+        try{
+            obj.put("code", errCode);
+            obj.put("msg", errMessage);
+        }catch (JSONException e){
+            e.printStackTrace();
+        }
+        String res = "{" + String.format("\"res\":\"%s\",\"data\":[%s]", RES_NO, obj) + "}";
+        return res;
+    }
+
+    /**
+     * 获取int类型数值
+     *
+     * @param obj
+     * @param keyName
+     * @return
+     */
+    public static int getIntValue(JSONObject obj, String keyName) {
+        try {
+            String strVal = obj.getString(keyName);
+            if (strVal.equals("")) return 0;
+            else return Integer.valueOf(strVal);
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+        return 0;
+    }
+
+    /**
+     * 获取double类型数值
+     *
+     * @param obj
+     * @param keyName
+     * @return
+     */
+    public static double getDoubleValue(JSONObject obj, String keyName) {
+        try {
+            String strVal = obj.getString(keyName);
+            if (strVal.equals("")) return 0;
+            else return Double.valueOf(strVal);
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+        return 0;
+    }
+
+    /**
+     * 获取字符串
+     *
+     * @param obj
+     * @param keyName
+     * @return
+     */
+    public static String getStringValue(JSONObject obj, String keyName) {
+        try {
+            String strVal = obj.getString(keyName);
+            return strVal;
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+
+    /**
+     * 获取布尔值
+     *
+     * @param obj
+     * @param keyName
+     * @return
+     */
+    public static boolean getBooleanValue(JSONObject obj, String keyName) {
+        try {
+            String strVal = obj.getString(keyName);
+            return strVal.equals("1") || strVal.equals("true") ? true : false;
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    /**
+     * 获取JSON
+     *
+     * @param obj
+     * @param keyName
+     * @return
+     */
+    public static JSONObject getJSONObjValue(JSONObject obj, String keyName) {
+        JSONObject resObj = null;
+        resObj = obj.optJSONObject(keyName);
+        return resObj;
+    }
+
+    /**
+     * 获取JSON数组
+     *
+     * @param obj
+     * @param keyName
+     * @return
+     */
+    public static JSONArray getJSONArrayValue(JSONObject obj, String keyName) {
+        JSONArray resObj = null;
+        resObj = obj.optJSONArray(keyName);
+        return resObj;
+    }
+
+    /**
+     * 通过Map和Key获取字符串值
+     *
+     * @param map          map 数据集
+     * @param key          key 关键字
+     * @param defaultValue 默认值
+     * @return 获取的字符串
+     */
+    public static <T> String getStringByMap(Map<String, T> map, String key, String defaultValue) {
+        if (map.get(key) == null) return "";
+        else return map.get(key).toString();
+    }
+
+
+    /**
+     * 将List数据集转换为JSON数组
+     *
+     * @param dataList 数据集
+     * @return JSON数组
+     */
+    public static String transformToString(List<? extends iNetDataModel> dataList) {
+        StringBuilder resBuilder = new StringBuilder();
+        for (iNetDataModel model : dataList) {
+            if (resBuilder.length() == 0) resBuilder.append(model.toJSON());
+            else resBuilder.append(",").append(model.toJSON());
+        }
+        return String.format("[%s]", resBuilder);
+    }
+}

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

@@ -13,16 +13,21 @@ import android.util.Log
 import android.view.View
 import android.view.View.OnClickListener
 import android.view.WindowManager
+import android.widget.Switch
+import android.widget.TextView
 import androidx.core.app.ActivityCompat
 import androidx.core.content.ContextCompat
 import androidx.core.content.PermissionChecker
+import com.cr.common.DataManager
 import com.cr.common.DatabaseManager
 import com.cr.common.FileManager
 import com.cr.data.CrUtil
 import com.cr.dialog.DialogNormal
 import com.cr.dialog.DialogNormal.DialogNormalListener
 import com.cr.event.EventFragmentBarAction
+import com.cr.models.UserModel
 import com.cr.pages.FragmentSetIpAndCom
+import com.cr.widget.CrEditTextWidget
 import com.squareup.otto.Subscribe
 import kotlinx.android.synthetic.main.av_login.*
 
@@ -53,6 +58,12 @@ class AvLogin : CrActivity(), OnClickListener {
     // define: 2023/3/30 设置页面
     var fragIpAndCom: FragmentSetIpAndCom? = null
 
+    // define: 2023/4/6 初始化控件
+    var lblVersion: TextView? = null
+    var txtUserName: CrEditTextWidget? = null
+    var txtPassword: CrEditTextWidget? = null
+    var switchSavePassword :Switch? = null
+
     /**
      * 创建视图
      * @param savedInstanceState Bundle?
@@ -66,6 +77,8 @@ class AvLogin : CrActivity(), OnClickListener {
             addFragment(it, R.id.av_frm_left_panel)
             hideFragment(it)
         }
+        // todo: 2023/4/6 初始化控件
+        joinControls()
         // todo: 2023/3/30 注册事件
         registerListener();
         // todo: 2023/3/31 检测权限
@@ -91,6 +104,30 @@ class AvLogin : CrActivity(), OnClickListener {
     }
 
     /**
+     * 重写挂载控件事件
+     */
+    override fun joinControls() {
+        super.joinControls()
+        // todo: 2023/4/6 初始化版本信息
+        lblVersion = findViewById(R.id.login_version)
+        lblVersion?.text = "{${CrUtil.getVersionName(this)}}"
+        // todo: 2023/4/6 初始化账号密码
+        txtUserName = findViewById(R.id.login_username)
+        txtPassword = findViewById(R.id.login_password)
+        switchSavePassword = findViewById(R.id.switch_password)
+    }
+
+    /**
+     * 页面初始化
+     */
+    private fun initPage(){
+        // todo: 2023/4/6 获取存储的用户并显示
+        var user:UserModel = DataManager.getUser()
+        txtUserName?.setContent(user.userId!!)
+        txtPassword?.setContent(user.userPwd!!)
+    }
+
+    /**
      * 重写注册事件
      */
     override fun registerListener() {
@@ -112,10 +149,13 @@ class AvLogin : CrActivity(), OnClickListener {
      */
     override fun onClick(p0: View?) {
         when (p0!!.id) {
-            R.id.login_btn_login ->
-                CrUtil.showMessage("登录")
+            R.id.login_btn_login -> {
+                var userName: String? = txtUserName?.checkBlank("请输入账号!") ?: return
+                var passWord: String? = txtPassword?.checkBlank("请输入密码!") ?: return
+                var isSave:Boolean? = switchSavePassword?.isChecked
+                login(userName!!,passWord!!,isSave!!)
+            }
             R.id.login_btn_set -> {
-                CrUtil.showMessage("设置")
                 fragIpAndCom?.let {
                     showFragment(it)
                 }
@@ -125,6 +165,23 @@ class AvLogin : CrActivity(), OnClickListener {
     }
 
     /**
+     * 登录验证
+     * @param userName String 账号
+     * @param password String 密码
+     * @param isSave Boolean 是否保存
+     */
+    private fun login(userName:String,password:String,isSave:Boolean){
+        if(isSave){
+            if(DataManager.saveUser(userName,password)) {
+                CrUtil.showMessage("登录成功并保存")
+            }
+        }else{
+            if(DataManager.deleteUser())
+                CrUtil.showMessage("登录成功不保存")
+        }
+    }
+
+    /**
      * 检测权限
      */
     private fun checkAndRequestPermissions() {
@@ -191,7 +248,7 @@ class AvLogin : CrActivity(), OnClickListener {
         // todo: 2023/4/3 拷贝配置库
         FileManager.MoveDataBase(this)
         // todo: 2023/4/3 判断数据库是否存在 存在则启动
-        var databaseIsOpen:Boolean = DatabaseManager.getInstance().openConfigDatabase()
+        var databaseIsOpen: Boolean = DatabaseManager.getInstance().openConfigDatabase()
         // todo: 2023/4/3 最终判断是否可以正常使用App
         if (FileManager.isExists(CrUtil.PROJECT_PATH) && FileManager.isExists(CrUtil.IMAGE_PATH) && FileManager.isExists(
                 CrUtil.PROJECT_CACHE_PATH
@@ -199,7 +256,9 @@ class AvLogin : CrActivity(), OnClickListener {
         ) {
             // todo: 2023/4/3 自检通过 可正常使用
             DialogNormal(this, "操作提示", "系统自检通过,可正常使用!").show()
-        }else{
+            // todo: 2023/4/6 页面初始化显示
+            initPage()
+        } else {
             // todo: 2023/4/3 自检异常 重启App自检
             DialogNormal(this, "操作提示", "系统自检异常,请重启App!", object : DialogNormalListener {
                 override fun completion() {
@@ -218,7 +277,7 @@ class AvLogin : CrActivity(), OnClickListener {
      * @param event EventFragmentBarAction
      */
     @Subscribe
-    fun onFragmentBar(event:EventFragmentBarAction){
+    fun onFragmentBar(event: EventFragmentBarAction) {
         hideFragment(fragIpAndCom!!)
     }
 

+ 5 - 0
app/src/main/java/com/cr/cruav/CrActivity.kt

@@ -48,7 +48,9 @@ open class CrActivity : AppCompatActivity() {
      */
     fun FragmentActivity.hideFragment(fragment:Fragment){
         supportFragmentManager.inTransaction {
+            this.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
             this.hide(fragment)
+            this.addToBackStack("")
         }
     }
 
@@ -59,7 +61,10 @@ open class CrActivity : AppCompatActivity() {
      */
     fun FragmentActivity.showFragment(fragment:Fragment){
         supportFragmentManager.inTransaction {
+            //this.setCustomAnimations(R.anim.slide_left_in,R.anim.slide_left_out,R.anim.slide_left_in,R.anim.slide_left_out)
+            this.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE)
             this.show(fragment)
+            this.addToBackStack("")
         }
     }
 

+ 53 - 0
app/src/main/java/com/cr/data/utils.kt

@@ -1,12 +1,17 @@
 package com.cr.data
 
 import android.content.Context
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
 import android.graphics.Typeface
+import android.os.Build
 import android.os.Handler
 import android.os.Looper
 import android.util.Log
 import android.widget.TextView
 import android.widget.Toast
+import androidx.annotation.RequiresApi
+import com.cr.dialog.DialogNormal
 import dji.v5.utils.common.ContextUtil
 import dji.v5.utils.common.StringUtils
 import java.text.SimpleDateFormat
@@ -180,6 +185,54 @@ class CrUtil {
             val m = p.matcher(strCOM)
             return m.matches()
         }
+
+        /**
+         * 获取版本名称
+         * @param context Context 上下文
+         * @return String
+         */
+        fun getVersionName(context: Context):String{
+            var packageInfo:PackageInfo = getPackageInfo(context)
+            return packageInfo.versionName
+        }
+
+        /**
+         * 获取版本号
+         * @param context Context 上下文
+         * @return Long
+         */
+        @RequiresApi(Build.VERSION_CODES.P)
+        fun getVersionCode(context: Context):Long{
+            var packageInfo:PackageInfo = getPackageInfo(context)
+            return packageInfo.longVersionCode
+        }
+
+        /**
+         * 获取包信息
+         * @param context Context 上下文
+         * @return PackageInfo
+         */
+        fun getPackageInfo(context: Context):PackageInfo{
+            var pm:PackageManager = context.packageManager
+            var packageInfo:PackageInfo = pm.getPackageInfo(context.packageName,PackageManager.GET_CONFIGURATIONS)
+            return packageInfo
+        }
+
+        /**
+         * 扩展函数 判断TextView内容是否为空
+         * @receiver TextView 文本框
+         * @param message String 错误消息
+         * @return String?
+         */
+        fun TextView.checkBlank(message: String):String?{
+            val text = this.text.toString()
+            if(text.isBlank()){
+                DialogNormal(this.context,"警告",message).show()
+                return null
+            }else{
+                return text
+            }
+        }
     }
 }
 

+ 45 - 0
app/src/main/java/com/cr/models/UserModel.kt

@@ -0,0 +1,45 @@
+package com.cr.models
+
+import com.cr.common.ClassManager
+import org.json.JSONObject
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/4/6 11:29
+ * 描述:账户模型
+ */
+class UserModel constructor(): iNetDataModel<UserModel> {
+    var userId: String? = ""   // define: 2023/4/6 账号Id
+    var userPwd: String? = ""   // define: 2023/4/6 密码
+    var userName: String? = ""   // define: 2023/4/6 账号名称
+
+    /**
+     * 构造方法
+     * @param userId String 账号Id
+     * @param userPwd String 密码
+     * @constructor
+     */
+    constructor(userId:String,userPwd:String):this(){
+        this.userId = userId
+        this.userPwd = userPwd
+    }
+
+    /**
+     * 转换为JSON字符串
+     * @return String
+     */
+    override fun toJSON(): String {
+        var jsonObj: JSONObject = ClassManager.fieldsToJSONObject(this)
+        return jsonObj.toString()
+    }
+
+    /**
+     * 通过JSON字符串初始化
+     * @param json String
+     * @return UserModel
+     */
+    override fun toModel(json: String): UserModel? {
+        return null
+    }
+}

+ 12 - 0
app/src/main/java/com/cr/models/iNetDataModel.kt

@@ -0,0 +1,12 @@
+package com.cr.models
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/4/6 11:31
+ * 描述:网路传输数据接口
+ */
+interface iNetDataModel<T> {
+    fun toJSON():String
+    fun toModel(json:String):T?
+}

+ 34 - 0
app/src/main/java/com/cr/pages/CrFragment.kt

@@ -4,7 +4,11 @@ import android.content.Context
 import android.os.Handler
 import android.os.Looper
 import android.view.View
+import android.view.animation.Animation
+import android.view.animation.AnimationUtils
 import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentTransaction
+import com.cr.cruav.R
 
 /**
  * 操作系统:MAC系统
@@ -52,4 +56,34 @@ open class CrFragment : Fragment() {
     override fun getContext(): Context? {
         return mainView!!.context
     }
+
+    /**
+     * 重写左侧滑动动画效果
+     * @param transit Int
+     * @param enter Boolean
+     * @param nextAnim Int
+     * @return Animation?
+     */
+    override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
+        // todo: 2023/4/6 表示是一个进入动作,比如add.show等
+        if (transit == FragmentTransaction.TRANSIT_FRAGMENT_OPEN) {
+            if (enter) {
+                // todo: 2023/4/6 普通的进入的动作
+                return AnimationUtils.loadAnimation(context, R.anim.slide_left_in);
+            } else {
+                // todo: 2023/4/6 比如一个已经Fragment被另一个replace,是一个进入动作,被replace的那个就是false
+                return AnimationUtils.loadAnimation(context, R.anim.slide_left_out);
+            }
+        } else if (transit == FragmentTransaction.TRANSIT_FRAGMENT_CLOSE) {
+            // todo: 2023/4/6 表示一个退出动作,比如出栈,hide,detach等
+            if (enter) {
+                // todo: 2023/4/6 之前被replace的重新进入到界面或者Fragment回到栈顶
+                return AnimationUtils.loadAnimation(context, R.anim.slide_left_in);
+            } else {
+                // todo: 2023/4/6 Fragment退出,出栈
+                return AnimationUtils.loadAnimation(context, R.anim.slide_left_out);
+            }
+        }
+        return null
+    }
 }

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

@@ -156,12 +156,12 @@ class FragmentSetIpAndCom : CrNavigationFragment(),View.OnClickListener{
             // todo: 2023/4/3 存在则更新
             var isReset:Boolean = DataManager.cancelNetworkChecked()
             var isUpdate:Boolean = DataManager.updateNetworkChecked(link,true)
-            CrUtil.showMessage(if(isReset && isUpdate) "设置成功" else "设置失败")
+            DialogNormal(context!!,"提示",if(isReset && isUpdate) "设置成功" else "设置失败").show()
         }else{
             // todo: 2023/4/3 不存在 则追加
             var isReset:Boolean = DataManager.cancelNetworkChecked()
             var isInsert:Boolean = DataManager.insertNetworkLink(link)
-            CrUtil.showMessage(if(isReset && isInsert) "设置成功" else "设置失败")
+            DialogNormal(context!!,"提示",if(isReset && isInsert) "设置成功" else "设置失败").show()
         }
         // todo: 2023/4/3 重置页面
         initPage()

+ 10 - 0
app/src/main/java/com/cr/widget/CrEditTextWidget.kt

@@ -14,6 +14,7 @@ import android.widget.ImageButton
 import android.widget.ImageView
 import android.widget.TextView
 import com.cr.cruav.R
+import com.cr.data.CrUtil.Companion.checkBlank
 import com.cr.data.FontManager
 
 /**
@@ -162,6 +163,15 @@ class CrEditTextWidget @JvmOverloads constructor(
     }
 
     /**
+     * 检查输入内容是否为空
+     * @param message String 错误消息
+     * @return String?
+     */
+    fun checkBlank(message:String):String?{
+        return txtContent?.checkBlank(message)
+    }
+
+    /**
      * 设置图片图标
      * @param drawable Drawable 图标资源
      */

+ 10 - 0
app/src/main/res/anim/slide_left_in.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate
+        android:duration = "800"
+        android:toXDelta="0.0"
+        android:fromXDelta="-100.0%p"/>
+    <alpha android:fromAlpha="0.0"
+        android:toAlpha="1.0"
+        android:duration="800"/>
+</set>

+ 9 - 0
app/src/main/res/anim/slide_left_out.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate android:toXDelta="-100.0%"
+        android:fromXDelta="0.0"
+        android:duration="800"/>
+    <alpha android:fromAlpha="1.0"
+        android:toAlpha="0.0"
+        android:duration="800"/>
+</set>

binární
app/src/main/res/drawable/app_icon.png


+ 1 - 1
app/src/main/res/drawable/shape_back_dialog_normal.xml

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

+ 1 - 1
app/src/main/res/drawable/shape_back_navigation_bar.xml

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <gradient android:startColor="#A0000000"
+    <gradient android:startColor="@color/midnightblue"
         android:endColor="#A0000000"
         android:angle="180"/>
 </shape>

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

@@ -24,7 +24,7 @@
             android:gravity="center"
             android:layout_margin="@dimen/common_margin"
             android:id="@+id/dig_title"
-            android:textColor="@color/black"/>
+            android:textColor="@color/white"/>
         <TextView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"

binární
app/src/main/res/raw/config.db