Compare commits

...

42 Commits

Author SHA1 Message Date
fengjignqi
7e63101fc9 连接蓝牙,配网 2026-06-04 14:30:24 +08:00
fengjignqi
0f9c8c7329 显示附近蓝牙设备 2026-06-04 08:49:28 +08:00
fengjignqi
20a08e9b61 显示附近蓝牙设备 2026-06-03 16:47:42 +08:00
fengjignqi
07edcb4664 引入蓝牙依赖 2026-06-03 16:25:13 +08:00
fengjignqi
5089e760e5 历史记录筛选 2026-06-03 15:43:43 +08:00
fengjignqi
2507657285 历史记录筛选 2026-06-03 15:14:49 +08:00
fengjignqi
bd75b8baeb 历史记录筛选 2026-06-02 18:00:45 +08:00
fengjignqi
03e67932b1 电池电量icon优化 2026-06-02 13:58:54 +08:00
fengjignqi
b7ab2e69a4 排程浇水历史记录 2026-06-01 15:54:06 +08:00
fengjignqi
694b74cda7 排程部分功能优化,
解绑,删除,绑定
2026-05-30 16:32:17 +08:00
fengjignqi
7aed064ddb 排程部分功能优化,
解绑,删除,绑定
2026-05-30 15:53:15 +08:00
fengjignqi
89df3119f8 排程部分功能优化,
解绑,删除,绑定
2026-05-30 09:01:24 +08:00
fengjignqi
ed9cdaf126 排程解绑设备,添加已关联设备tab 2026-05-29 18:02:04 +08:00
fengjignqi
436b65c5e6 更新后新增排程提交 2026-05-29 16:28:55 +08:00
fengjignqi
5a42515f77 更新后新增排程提交 2026-05-29 15:10:40 +08:00
fengjignqi
a8b9aabf20 更新后新增排程提交 2026-05-29 10:47:02 +08:00
fengjignqi
e1d13665ab 更新后新增排程提交 2026-05-29 10:24:43 +08:00
fengjignqi
1000c43321 更新后新增排程提交 2026-05-29 10:18:41 +08:00
fengjignqi
9318646aa4 time配置校验时间冲突 2026-05-29 08:17:06 +08:00
fengjignqi
644a68d865 time列表设置时间 2026-05-28 17:58:32 +08:00
fengjignqi
693acda192 time列表设置时间 2026-05-28 17:11:04 +08:00
fengjignqi
967ddca167 侧滑删除 2026-05-28 16:54:28 +08:00
fengjignqi
9d41f8c1eb 侧滑删除 2026-05-28 15:45:42 +08:00
fengjignqi
21f70b68eb 排程重做 2026-05-28 15:18:57 +08:00
fengjignqi
79e66a20ef 排程重做 2026-05-28 14:56:39 +08:00
fengjignqi
401d1892bb 排程重做 2026-05-28 12:00:18 +08:00
fengjignqi
47769d1003 编辑排程状态 2026-05-27 17:08:57 +08:00
fengjignqi
f7bee61a56 编辑排程状态 2026-05-27 15:47:23 +08:00
fengjignqi
20aaf98235 排程分页2 2026-05-27 10:01:09 +08:00
fengjignqi
30e88c8067 排程分页 2026-05-27 09:41:27 +08:00
fengjignqi
0ca0a395cd 排程编辑更新 2026-05-27 08:52:18 +08:00
fengjignqi
f2b8062398 排程编辑更新 2026-05-26 17:41:27 +08:00
fengjignqi
9ab6d134ab 排程编辑更新 2026-05-26 17:35:08 +08:00
fengjignqi
65dfc1b5f1 排程编辑更新 2026-05-26 15:31:26 +08:00
fengjignqi
5ca81f565a 排程详情 2026-05-26 14:25:41 +08:00
fengjignqi
1ed3a68a5e 手机号、邮箱 + 验证码修改密码 2026-05-26 10:47:46 +08:00
fengjignqi
e14bdaf046 新增排程接口+排程更新 2026-05-26 09:06:11 +08:00
fengjignqi
6c6d211701 新增排程接口 2026-05-25 15:43:34 +08:00
fengjignqi
e6e3f755d0 新增排程接口 2026-05-25 10:16:33 +08:00
fengjignqi
819965faec 新增排程接口 2026-05-25 09:52:26 +08:00
fengjignqi
f86fedd6f1 新增排程页面重做 2026-05-22 15:05:27 +08:00
fengjignqi
1b7c8f0c2d 修改密码 2026-05-21 18:00:42 +08:00
141 changed files with 7346 additions and 724 deletions

View File

@@ -4,7 +4,7 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-05-19T02:00:28.842946500Z"> <DropdownSelection timestamp="2026-06-03T03:26:05.515101Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=D122222104A9" /> <DeviceId pluginId="PhysicalDevice" identifier="serial=D122222104A9" />

View File

@@ -4,7 +4,7 @@ apply plugin: 'com.hihonor.mcs.asplugin'
apply plugin: 'io.freefair.lombok' // ✅ 加上这个 apply plugin: 'io.freefair.lombok' // ✅ 加上这个
android { android {
compileSdkVersion 33 compileSdkVersion 34
lintOptions { lintOptions {
checkReleaseBuilds false // 关闭 release 打包时 lint 检查 checkReleaseBuilds false // 关闭 release 打包时 lint 检查
abortOnError false // 即使有错误也不终止编译 abortOnError false // 即使有错误也不终止编译
@@ -121,6 +121,7 @@ dependencies {
implementation project(path: ':imagepickerl') implementation project(path: ':imagepickerl')
//消息传递 //消息传递
implementation 'de.greenrobot:eventbus:3.0.0-beta1' implementation 'de.greenrobot:eventbus:3.0.0-beta1'
implementation 'org.greenrobot:eventbus:3.3.1'
implementation 'com.trello.rxlifecycle2:rxlifecycle:2.2.1' implementation 'com.trello.rxlifecycle2:rxlifecycle:2.2.1'
implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.1' implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.1'
implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.1' implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.1'
@@ -159,8 +160,8 @@ dependencies {
//鲁班图片压缩 //鲁班图片压缩
implementation 'top.zibin:Luban:1.1.8' implementation 'top.zibin:Luban:1.1.8'
//带有侧滑功能的recyclerview //带有侧滑功能的recyclerview
// implementation 'com.yanzhenjie.recyclerview:x:1.3.2' implementation 'com.yanzhenjie.recyclerview:x:1.3.2'
implementation 'com.github.luqiming666:SwipeRecyclerView:1.4.8' // implementation 'com.github.luqiming666:SwipeRecyclerView:1.4.8'
//Activity与Fragmen实现沉浸式状态栏 //Activity与Fragmen实现沉浸式状态栏
implementation 'com.github.tangguna:immersion:1.0.1' implementation 'com.github.tangguna:immersion:1.0.1'
//viewpager2 //viewpager2
@@ -226,6 +227,11 @@ dependencies {
implementation "androidx.camera:camera-camera2:1.0.2" implementation "androidx.camera:camera-camera2:1.0.2"
implementation "androidx.camera:camera-lifecycle:1.0.2" implementation "androidx.camera:camera-lifecycle:1.0.2"
implementation "androidx.camera:camera-view:1.0.0-alpha25" implementation "androidx.camera:camera-view:1.0.0-alpha25"
//蓝牙扫描
implementation 'no.nordicsemi.android.support.v18:scanner:1.6.0'
//蓝牙通讯
implementation 'no.nordicsemi.android:ble:2.11.0'
//espressif官方sdk用于esp固件的扫描配网等。
implementation 'com.github.espressif:esp-idf-provisioning-android:lib-2.2.3'
} }

View File

@@ -35,6 +35,14 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<!-- 蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- 支持ble的设备 -->
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
<!--后台获取位置信息,若需后台定位则必选--> <!--后台获取位置信息,若需后台定位则必选-->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!--用于申请调用A-GPS模块,卫星定位加速--> <!--用于申请调用A-GPS模块,卫星定位加速-->
@@ -56,9 +64,9 @@
<application <application
android:name="com.ckkj.water.MyApplication" android:name="com.ckkj.water.MyApplication"
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/app_logo"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher" android:roundIcon="@mipmap/app_logo"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:theme="@style/custom_app_theme" android:theme="@style/custom_app_theme"
android:supportsRtl="true" android:supportsRtl="true"
@@ -111,10 +119,6 @@
android:launchMode="singleTask" android:launchMode="singleTask"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize"/> android:windowSoftInputMode="adjustResize"/>
<activity
android:name="com.ckkj.water.chat.ChatHistoryActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize"/>
<activity <activity
android:name="com.ckkj.water.login.LoginActivity" android:name="com.ckkj.water.login.LoginActivity"
android:theme="@style/AppTheme.FullScreen" android:theme="@style/AppTheme.FullScreen"
@@ -164,6 +168,10 @@
android:name="com.ckkj.water.device.AddDeviceActivity" android:name="com.ckkj.water.device.AddDeviceActivity"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize"/> android:windowSoftInputMode="adjustResize"/>
<activity
android:name="com.ckkj.water.device.AddDeviceActivity_copy"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize"/>
<activity <activity
android:name="com.ckkj.water.device.SelectWifiActivity" android:name="com.ckkj.water.device.SelectWifiActivity"
android:screenOrientation="portrait" android:screenOrientation="portrait"

View File

@@ -120,4 +120,7 @@ public class AppConfig {
public static String APP_CLIENT_ID = "428a8310cd442757ae699df5d894f051"; public static String APP_CLIENT_ID = "428a8310cd442757ae699df5d894f051";
public static String APP_USER_TYPE = "app_user"; public static String APP_USER_TYPE = "app_user";
//蓝牙设备的uuid
public static String BLUETOOTH_DEVICE_UUID = "1775244d-6b43-439b-877c-060f2d9bed07";
} }

View File

@@ -154,6 +154,7 @@ public class MyApplication extends Application {
.setUseDeviceSize(true) .setUseDeviceSize(true)
// 是否支持 fragment // 是否支持 fragment
.setCustomFragment(true); .setCustomFragment(true);
android.util.Log.e("TEST", "hello");
} }
private boolean shouldInit() { private boolean shouldInit() {

View File

@@ -20,6 +20,7 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.text.InputFilter; import android.text.InputFilter;
import android.text.InputType;
import android.text.Spanned; import android.text.Spanned;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
@@ -100,6 +101,11 @@ public abstract class BaseActivity<T extends ViewBinding, P extends IPresenter>
public static final int REQUEST_EVENT_CODE_10001 = 10001; public static final int REQUEST_EVENT_CODE_10001 = 10001;
public static final int REQUEST_EVENT_CODE_10002 = 10002; public static final int REQUEST_EVENT_CODE_10002 = 10002;
public static final int REQUEST_EVENT_CODE_10003 = 10003; public static final int REQUEST_EVENT_CODE_10003 = 10003;
public static final int INPUT_TYPE_NORMAL = 0; // 默认
public static final int INPUT_TYPE_NUMBER = 1; // 数字
public static final int INPUT_TYPE_LETTER = 2; // 英文字母
public static final int INPUT_TYPE_CHINESE = 3; // 中文
public static final int INPUT_TYPE_NUMBER_LETTER = 4;//数字+字母
public InputFilter mInputFilter; public InputFilter mInputFilter;
private static final AtomicBoolean isDialogShown = new AtomicBoolean(false); // 使用 AtomicBoolean 保证线程安全 private static final AtomicBoolean isDialogShown = new AtomicBoolean(false); // 使用 AtomicBoolean 保证线程安全
private ObjectAnimator rotateAnimator; private ObjectAnimator rotateAnimator;
@@ -484,15 +490,29 @@ public abstract class BaseActivity<T extends ViewBinding, P extends IPresenter>
* @param confirmText 确定 文案 * @param confirmText 确定 文案
* @param click * @param click
*/ */
public void showEditDialog(String title, String hint,String content, boolean touchOutsideCancel, String cancelText, String confirmText, public void showEditDialog(String title,
String hint,
String content,
boolean touchOutsideCancel,
String cancelText,
String confirmText,
int inputType,
final OnDialogClick click) { final OnDialogClick click) {
View view = getLayoutInflater().inflate(R.layout.public_dialog_input_text, null); View view = getLayoutInflater().inflate(R.layout.public_dialog_input_text, null);
EditText editText = view.findViewById(R.id.et_input); EditText editText = view.findViewById(R.id.et_input);
// EditText自动获取焦点
editText.requestFocus();
//设置输入类型
setEditInputType(editText,inputType);
if(TextUtils.isEmpty(content)){ if(TextUtils.isEmpty(content)){
editText.setHint(hint); editText.setHint(hint);
}else{ }else{
editText.setText(content); editText.setText(content);
} }
if (!TextUtils.isEmpty(content)) {
editText.setSelection(editText.getText().length());
}
setTextView(R.id.tv_title, title, view); setTextView(R.id.tv_title, title, view);
if (!TextUtils.isEmpty(confirmText) && !TextUtils.isEmpty(cancelText)) { if (!TextUtils.isEmpty(confirmText) && !TextUtils.isEmpty(cancelText)) {
((TextView) view.findViewById(R.id.btnLeft)).setText(cancelText); ((TextView) view.findViewById(R.id.btnLeft)).setText(cancelText);
@@ -1128,4 +1148,72 @@ public abstract class BaseActivity<T extends ViewBinding, P extends IPresenter>
// 方法2通过Application检查如果有记录当前Activity // 方法2通过Application检查如果有记录当前Activity
return MyApplication.getCurrentActivity() == this; return MyApplication.getCurrentActivity() == this;
} }
private void setEditInputType(EditText editText,int type){
switch (type){
case INPUT_TYPE_NUMBER:
//纯数字键盘
editText.setInputType(
InputType.TYPE_CLASS_NUMBER
);
break;
case INPUT_TYPE_LETTER:
//只能输入字母
editText.setFilters(
new InputFilter[]{
(source,start,end,dest,dstart,dend)->{
if(source.toString()
.matches("[a-zA-Z]+")){
return source;
}
return "";
}
});
break;
case INPUT_TYPE_CHINESE:
//只能输入中文
editText.setFilters(
new InputFilter[]{
(source,start,end,dest,dstart,dend)->{
if(source.toString()
.matches("[\\u4e00-\\u9fa5]+")){
return source;
}
return "";
}
});
break;
case INPUT_TYPE_NUMBER_LETTER:
//数字+字母
editText.setFilters(
new InputFilter[]{
(source,start,end,dest,dstart,dend)->{
if(source.toString()
.matches("[a-zA-Z0-9]+")){
return source;
}
return "";
}
});
break;
default:
editText.setInputType(
InputType.TYPE_CLASS_TEXT
);
break;
}
}
} }

View File

@@ -11,6 +11,8 @@ import android.content.Intent;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.text.InputFilter;
import android.text.InputType;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.Gravity; import android.view.Gravity;
@@ -20,6 +22,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
@@ -30,6 +33,7 @@ import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.viewbinding.ViewBinding; import androidx.viewbinding.ViewBinding;
import com.ckkj.water.utils.show.ToastUtil;
import com.esafirm.imagepicker.features.ImagePicker; import com.esafirm.imagepicker.features.ImagePicker;
import com.ckkj.water.AppConfig; import com.ckkj.water.AppConfig;
import com.ckkj.water.ConstantUtil; import com.ckkj.water.ConstantUtil;
@@ -70,6 +74,12 @@ public abstract class BaseFragment<T extends ViewBinding,P extends IPresenter> e
protected static final int REQUEST_EVENT_CODE_10002 = 10002; protected static final int REQUEST_EVENT_CODE_10002 = 10002;
protected static final int REQUEST_EVENT_CODE_10003 = 10003; protected static final int REQUEST_EVENT_CODE_10003 = 10003;
public static final int INPUT_TYPE_NORMAL = 0; // 默认
public static final int INPUT_TYPE_NUMBER = 1; // 数字
public static final int INPUT_TYPE_LETTER = 2; // 英文字母
public static final int INPUT_TYPE_CHINESE = 3; // 中文
public static final int INPUT_TYPE_NUMBER_LETTER = 4;//数字+字母
private static final AtomicBoolean isDialogShown = new AtomicBoolean(false); // 使用 AtomicBoolean 保证线程安全 private static final AtomicBoolean isDialogShown = new AtomicBoolean(false); // 使用 AtomicBoolean 保证线程安全
@@ -860,6 +870,193 @@ public abstract class BaseFragment<T extends ViewBinding,P extends IPresenter> e
}); });
} }
/**
* +
*
* @param title 标题
* @param hint 提示内容2
* @param content 内容
* @param touchOutsideCancel 弹窗类型
* @param cancelText 取消 文案
* @param confirmText 确定 文案
* @param click
*/
public void showEditDialog(String title,
String hint,
String content,
boolean touchOutsideCancel,
String cancelText,
String confirmText,
int inputType,
final BaseActivity.OnDialogClick click) {
View view = getLayoutInflater().inflate(
R.layout.public_dialog_input_text,
null
);
EditText editText = view.findViewById(R.id.et_input);
//设置输入类型
setEditInputType(editText,inputType);
if(TextUtils.isEmpty(content)){
editText.setHint(hint);
}else{
editText.setText(content);
editText.setSelection(content.length());
}
setTextView(R.id.tv_title,title,view);
if (!TextUtils.isEmpty(confirmText)
&& !TextUtils.isEmpty(cancelText)) {
((TextView)view.findViewById(R.id.btnLeft))
.setText(cancelText);
((TextView)view.findViewById(R.id.btnRight))
.setText(confirmText);
}
view.findViewById(R.id.btnLeft)
.setOnClickListener(v -> {
if(dialog!=null&&dialog.isShowing())
dialog.dismiss();
if(click!=null)
click.onCancelClick();
});
view.findViewById(R.id.btnRight)
.setOnClickListener(v -> {
String value=editText.getText()
.toString()
.trim();
if(TextUtils.isEmpty(value)){
ToastUtil.showShort(mContext,hint);
return;
}
if(dialog!=null&&dialog.isShowing())
dialog.dismiss();
if(click!=null)
click.onConfirmClisk(value);
});
AlertDialog.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
builder = new AlertDialog.Builder(
mContext,
AlertDialog.THEME_HOLO_LIGHT
);
} else {
builder = new AlertDialog.Builder(mContext);
}
builder.setInverseBackgroundForced(true);
builder.setView(view);
dialog = builder.show();
dialog.setCanceledOnTouchOutside(
touchOutsideCancel
);
try {
((View)dialog.getWindow()
.getDecorView()
.findViewById(R.id.contentDialog)
.getParent()
.getParent())
.setBackgroundColor(
getResources().getColor(
R.color.transparent
)
);
} catch (Exception e) {
e.printStackTrace();
}
}
private void setEditInputType(EditText editText,int type){
switch (type){
case INPUT_TYPE_NUMBER:
//纯数字键盘
editText.setInputType(
InputType.TYPE_CLASS_NUMBER
);
break;
case INPUT_TYPE_LETTER:
//只能输入字母
editText.setFilters(
new InputFilter[]{
(source,start,end,dest,dstart,dend)->{
if(source.toString()
.matches("[a-zA-Z]+")){
return source;
}
return "";
}
});
break;
case INPUT_TYPE_CHINESE:
//只能输入中文
editText.setFilters(
new InputFilter[]{
(source,start,end,dest,dstart,dend)->{
if(source.toString()
.matches("[\\u4e00-\\u9fa5]+")){
return source;
}
return "";
}
});
break;
case INPUT_TYPE_NUMBER_LETTER:
//数字+字母
editText.setFilters(
new InputFilter[]{
(source,start,end,dest,dstart,dend)->{
if(source.toString()
.matches("[a-zA-Z0-9]+")){
return source;
}
return "";
}
});
break;
default:
editText.setInputType(
InputType.TYPE_CLASS_TEXT
);
break;
}
}
/** /**
* 权限请求结果回调 * 权限请求结果回调
*/ */

View File

@@ -16,12 +16,26 @@ import lombok.NoArgsConstructor;
@Data @Data
public class MineUserInfoBean implements Serializable { public class MineUserInfoBean implements Serializable {
/**
* user : {"userId":"2056543507514097665","tenantId":"000000","deptId":null,"userName":null,"nickName":"给个回话","userType":"app_user","email":"","phonenumber":"133****6054","sex":"0","avatar":null,"password":"$2a$10$KsCb1Z1znyQgL7W.GoljuuVPctzZ7tS7obu8W2WkK5ydsejQOjRi2","status":"0","loginIp":"192.168.1.7","loginDate":"2026-05-21 08:44:20","remark":null,"createTime":"2026-05-19 09:12:36","deptName":null,"roles":[],"roleIds":null,"postIds":null,"roleId":null,"oldPassword":null}
* permissions : []
* roles : []
*/
private UserBean user;
private List<?> permissions;
private List<?> roles;
@NoArgsConstructor
@Data
public static class UserBean implements Serializable{
/** /**
* userId : 2056543507514097665 * userId : 2056543507514097665
* tenantId : 000000 * tenantId : 000000
* deptId : null * deptId : null
* userName : null * userName : null
* nickName : 用户1779153155517 * nickName : 给个回话
* userType : app_user * userType : app_user
* email : * email :
* phonenumber : 133****6054 * phonenumber : 133****6054
@@ -30,7 +44,7 @@ public class MineUserInfoBean implements Serializable {
* password : $2a$10$KsCb1Z1znyQgL7W.GoljuuVPctzZ7tS7obu8W2WkK5ydsejQOjRi2 * password : $2a$10$KsCb1Z1znyQgL7W.GoljuuVPctzZ7tS7obu8W2WkK5ydsejQOjRi2
* status : 0 * status : 0
* loginIp : 192.168.1.7 * loginIp : 192.168.1.7
* loginDate : 2026-05-19 11:06:22 * loginDate : 2026-05-21 08:44:20
* remark : null * remark : null
* createTime : 2026-05-19 09:12:36 * createTime : 2026-05-19 09:12:36
* deptName : null * deptName : null
@@ -64,3 +78,4 @@ public class MineUserInfoBean implements Serializable {
private Object oldPassword; private Object oldPassword;
private List<?> roles; private List<?> roles;
} }
}

View File

@@ -68,25 +68,35 @@ public class CustomTypeFilterPopupView extends PartShadowPopupView implements Vi
switch (v.getId()){ switch (v.getId()){
case R.id.tv_manual: case R.id.tv_manual:
if(mSelManual){ if(mSelManual){
// 已选中,取消选中
mSelManual = false; mSelManual = false;
tvManual.setTextColor(mContext.getColor(R.color.color_zhu)); tvManual.setTextColor(mContext.getColor(R.color.color_zhu));
tvManual.setSelected(mSelManual); tvManual.setSelected(false);
}else{ }else{
// 选中手动,同时取消自动
mSelManual = true; mSelManual = true;
mSelAuto = false;
tvManual.setTextColor(mContext.getColor(R.color.white)); tvManual.setTextColor(mContext.getColor(R.color.white));
tvManual.setSelected(mSelManual); tvManual.setSelected(true);
tvAuto.setTextColor(mContext.getColor(R.color.color_zhu));
tvAuto.setSelected(false);
} }
break; break;
case R.id.tv_auto: case R.id.tv_auto:
if(mSelAuto){ if(mSelAuto){
// 已选中,取消选中
mSelAuto = false; mSelAuto = false;
tvAuto.setTextColor(mContext.getColor(R.color.color_zhu)); tvAuto.setTextColor(mContext.getColor(R.color.color_zhu));
tvAuto.setSelected(mSelAuto); tvAuto.setSelected(false);
}else{ }else{
// 选中自动,同时取消手动
mSelAuto = true; mSelAuto = true;
mSelManual = false;
tvAuto.setTextColor(mContext.getColor(R.color.white)); tvAuto.setTextColor(mContext.getColor(R.color.white));
tvAuto.setSelected(mSelAuto); tvAuto.setSelected(true);
tvManual.setTextColor(mContext.getColor(R.color.color_zhu));
tvManual.setSelected(false);
} }
break; break;
@@ -95,8 +105,8 @@ public class CustomTypeFilterPopupView extends PartShadowPopupView implements Vi
mSelAuto = false; mSelAuto = false;
tvManual.setTextColor(mContext.getColor(R.color.color_zhu)); tvManual.setTextColor(mContext.getColor(R.color.color_zhu));
tvAuto.setTextColor(mContext.getColor(R.color.color_zhu)); tvAuto.setTextColor(mContext.getColor(R.color.color_zhu));
tvManual.setSelected(mSelManual); tvManual.setSelected(false);
tvAuto.setSelected(mSelAuto); tvAuto.setSelected(false);
break; break;
case R.id.tv_finish: case R.id.tv_finish:

View File

@@ -4,6 +4,7 @@ import static android.view.View.GONE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
import android.Manifest; import android.Manifest;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle; import android.os.Bundle;
@@ -20,7 +21,7 @@ import com.ckkj.water.databinding.AddDeviceLayoutBinding;
import com.ckkj.water.device.mvp.DeviceContract; import com.ckkj.water.device.mvp.DeviceContract;
import com.ckkj.water.device.mvp.DeviceImpl; import com.ckkj.water.device.mvp.DeviceImpl;
import com.ckkj.water.device.mvp.DevicePresenter; import com.ckkj.water.device.mvp.DevicePresenter;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.utils.manager.ActivityManager; import com.ckkj.water.utils.manager.ActivityManager;
import com.ckkj.water.utils.manager.ThemeManager; import com.ckkj.water.utils.manager.ThemeManager;
@@ -34,6 +35,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import no.nordicsemi.android.ble.BleManager;
import pub.devrel.easypermissions.EasyPermissions; import pub.devrel.easypermissions.EasyPermissions;
/** /**
@@ -73,7 +75,6 @@ public class AddDeviceActivity extends BaseActivity<AddDeviceLayoutBinding, Devi
if (animationDrawable.isRunning()) { if (animationDrawable.isRunning()) {
animationDrawable.stop(); animationDrawable.stop();
viewBinding.ivScanAnimation.setVisibility(GONE); viewBinding.ivScanAnimation.setVisibility(GONE);
viewBinding.imgDeviceItem.setVisibility(VISIBLE);
} }
} }
} }
@@ -85,7 +86,6 @@ public class AddDeviceActivity extends BaseActivity<AddDeviceLayoutBinding, Devi
private void initListener() { private void initListener() {
setClick(viewBinding.includedTitle.imgBack); setClick(viewBinding.includedTitle.imgBack);
setClick(viewBinding.tvScanAdd); setClick(viewBinding.tvScanAdd);
setClick(viewBinding.imgDeviceItem);
} }
private void setClick(View view) { private void setClick(View view) {
@@ -195,7 +195,7 @@ public class AddDeviceActivity extends BaseActivity<AddDeviceLayoutBinding, Devi
} }
@Override @Override
public void getDeviceDetailInfo(IndexDeviceEntity bean) { public void getDeviceDetailInfo(WaterDeviceEntity bean) {
} }

View File

@@ -0,0 +1,461 @@
package com.ckkj.water.device;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.AnimationDrawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.ParcelUuid;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.ckkj.water.BuildConfig;
import com.ckkj.water.ConstantUtil;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.custom.GridSpacingItemDecoration;
import com.ckkj.water.databinding.AddDeviceLayoutBinding;
import com.ckkj.water.device.adapter.BleScanDeviceAdapter;
import com.ckkj.water.device.mvp.DeviceContract;
import com.ckkj.water.device.mvp.DeviceImpl;
import com.ckkj.water.device.mvp.DevicePresenter;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.utils.manager.ActivityManager;
import com.ckkj.water.utils.manager.ThemeManager;
import com.ckkj.water.utils.manager.WaterDeviceManager;
import com.ckkj.water.utils.show.ToastUtil;
import com.gyf.immersionbar.ImmersionBar;
import com.maning.mlkitscanner.scan.MNScanManager;
import com.maning.mlkitscanner.scan.callback.act.MNScanCallback;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import no.nordicsemi.android.ble.observer.ConnectionObserver;
import no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerCompat;
import no.nordicsemi.android.support.v18.scanner.ScanCallback;
import no.nordicsemi.android.support.v18.scanner.ScanFilter;
import no.nordicsemi.android.support.v18.scanner.ScanRecord;
import no.nordicsemi.android.support.v18.scanner.ScanResult;
import no.nordicsemi.android.support.v18.scanner.ScanSettings;
import pub.devrel.easypermissions.EasyPermissions;
/**
* 添加设备页面
*/
public class AddDeviceActivity_copy extends BaseActivity<AddDeviceLayoutBinding, DevicePresenter>
implements DeviceContract.DeviceView, EasyPermissions.PermissionCallbacks {
// 蓝牙相关
private BluetoothAdapter bluetoothAdapter;
private static final int REQUEST_ENABLE_BT = 1001;
private static final int REQUEST_BLUETOOTH_PERMISSION = 1002;
private List<BluetoothDevice> discoveredDevices = new ArrayList<>();
private AlertDialog deviceListDialog;
private String mUuid = "1775244d-6b43-439b-877c-060f2d9bed07";
private ScanCallback mScanCallback;
private boolean bluetoothReady = false;
private BleScanDeviceAdapter bleAdapter;
private List<WaterDeviceEntity> mDeviceList = new ArrayList<>();
private Set<String> discoveredMacSet = new HashSet<>();
private WaterDeviceManager waterDeviceManager;
@Override
public DevicePresenter createPresenter() {
return new DevicePresenter(new DeviceImpl());
}
@Override
public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
ActivityManager.addActivity(this,getClass().getSimpleName() + "_" + ConstantUtil.ADD_DEVICE_FLAG);
ImmersionBar.with(this)
.statusBarColor(R.color.mainBackgroundColor) // 设置状态栏颜色
.statusBarDarkFont(ThemeManager.isAppThemeLight(mContext)) // 设置状态栏字体为黑色
.titleBar(viewBinding.rlTitle)
.init();
viewBinding.includedTitle.tvTitle.setText(R.string.add_device_title);
viewBinding.rvDevices.addItemDecoration(new GridSpacingItemDecoration(4, 10, true));
bleAdapter = new BleScanDeviceAdapter(mContext,R.layout.scan_ble_device_item,mDeviceList);
viewBinding.rvDevices.setAdapter(bleAdapter);
if(checkBluetoothPermissions()){
// 初始化蓝牙适配器
initBluetooth();
if (bluetoothReady) {
startBleScan();
}
}
// 启动帧动画
ImageView ivScanAnimation = viewBinding.ivScanAnimation;
if (ivScanAnimation.getDrawable() instanceof AnimationDrawable) {
AnimationDrawable animationDrawable = (AnimationDrawable) ivScanAnimation.getDrawable();
animationDrawable.start();
}
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// 停止帧动画
ImageView ivScanAnimation = viewBinding.ivScanAnimation;
if (ivScanAnimation.getDrawable() instanceof AnimationDrawable) {
AnimationDrawable animationDrawable = (AnimationDrawable) ivScanAnimation.getDrawable();
if (animationDrawable.isRunning()) {
animationDrawable.stop();
viewBinding.ivScanAnimation.setVisibility(GONE);
}
}
}
},3000);
initListener();
}
/**
* 初始化监听g
*/
private void initListener() {
setClick(viewBinding.includedTitle.imgBack);
setClick(viewBinding.tvScanAdd);
setClick(viewBinding.btnBleScan);
if(bleAdapter != null){
bleAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
WaterDeviceEntity device = mDeviceList.get(position);
String deviceName = TextUtils.isEmpty(device.getDeviceName()) ?
"未知设备" : device.getDeviceName();
// 停止扫描
stopBleScan();
Bundle bundle = new Bundle();
bundle.putInt(ConstantUtil.ACTIVITY_NAVIGATE_FLAG,100);
bundle.putSerializable("ble_device_entity",mDeviceList.get(position));
goTo(mContext, SelectWifiActivity.class,bundle);
}
});
}
}
/**
* 开始 BLE 扫描
*/
private void startBleScan() {
BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
UUID SERVICE_UUID = UUID.fromString(mUuid);//1775244d-6b43-439b-877c-060f2d9bed07
ParcelUuid parcelUuid = new ParcelUuid(SERVICE_UUID);
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setReportDelay(0)
.build();
List<ScanFilter> filters = new ArrayList<>();
filters.add(new ScanFilter.Builder().setServiceUuid(parcelUuid).build());
Log.e("TEST", "开始扫描");
mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, @NonNull ScanResult result) {
super.onScanResult(callbackType, result);
//Mac地址
String deviceAddress = result.getDevice().getAddress();
// 去重:已存在的设备不再添加
if (discoveredMacSet.contains(deviceAddress)) {
return;
}
discoveredMacSet.add(deviceAddress);
WaterDeviceEntity bean = new WaterDeviceEntity();
//设备名字
String deviceName = result.getScanRecord() != null ?
result.getScanRecord().getDeviceName() : "无名称";
bean.setDeviceName(deviceName);
bean.setMacAddress(deviceAddress);
mDeviceList.add(bean);
bleAdapter.notifyItemInserted(mDeviceList.size() - 1);
if(bleAdapter.getItemCount() != 0){
viewBinding.rvDevices.setVisibility(VISIBLE);
}
}
@Override
public void onBatchScanResults(@NonNull List<ScanResult> results) {
super.onBatchScanResults(results);
Log.e("TEST", "批量结果: " + results.size() + " 个设备");
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Log.e("TEST", "扫描失败: " + errorCode);
ToastUtil.showShort(mContext, "扫描失败,错误码: " + errorCode);
}
};
scanner.startScan(filters, settings, mScanCallback);
}
/**
* 停止 BLE 扫描
*/
private void stopBleScan() {
if (mScanCallback != null) {
BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
scanner.stopScan(mScanCallback);
Log.e("TEST", "停止扫描");
}
}
/**
* 初始化蓝牙适配器
*/
private void initBluetooth() {
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (bluetoothManager != null) {
bluetoothAdapter = bluetoothManager.getAdapter();
}
if (bluetoothAdapter == null) {
ToastUtil.showShort(mContext, "设备不支持蓝牙");
return;
}
// 检查蓝牙是否开启
if (!bluetoothAdapter.isEnabled()) {
Log.e("TEST", "initBluetooth: 蓝牙未开启,请求开启");
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
} else {
bluetoothReady = true;
}
}
/**
* 检查蓝牙权限
*/
private boolean checkBluetoothPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
String[] readPermission = new String[]{
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.ACCESS_FINE_LOCATION
};
if (!hasRecordPermission(readPermission)) {
// 没有权限只在ACTION_DOWN时去申请
getMorePermissionRequst(readPermission,"蓝牙扫描权限申请",
"智能浇水需要您的授权,获取蓝牙权限添加设备",REQUEST_EVENT_CODE_10003);
return false;
}
} else {
// Android 12 以下需要位置权限才能扫描蓝牙
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{
Manifest.permission.ACCESS_FINE_LOCATION
}, REQUEST_BLUETOOTH_PERMISSION);
return false;
}
}
return true;
}
private void setClick(View view) {
view.setOnClickListener(this::onClick);
}
public void onClick(View v){
switch (v.getId()){
case R.id.img_back:
finish();
break;
case R.id.tv_scan_add:
//检测有无相机权限
String readPermission = Manifest.permission.CAMERA;
if(!hasRecordPermission(readPermission)){
getPermissionRequst(readPermission,"权限申请",
"智能浇水需要您的授权访问相机,并使用扫一扫",REQUEST_EVENT_CODE_10001);
}else{
scanQrcode();
}
break;
case R.id.btn_ble_scan:
// 扫描蓝牙设备
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == RESULT_OK) {
ToastUtil.showShort(mContext, "蓝牙已开启");
Log.e("BluetoothScan", "onActivityResult: 蓝牙已开启,开始扫描");
bluetoothReady = true;
startBleScan();
} else {
ToastUtil.showShort(mContext, "请开启蓝牙以扫描设备");
Log.e("BluetoothScan", "onActivityResult: 用户拒绝开启蓝牙");
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull @NotNull String[] permissions, @NonNull @NotNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
hidePermissionDialog();
if (requestCode == REQUEST_BLUETOOTH_PERMISSION) {
boolean allGranted = true;
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
allGranted = false;
break;
}
}
if (allGranted) {
// 初始化蓝牙适配器
initBluetooth();
} else {
ToastUtil.showShort(mContext, "需要蓝牙权限才能扫描设备");
}
}
}
private void scanQrcode() {
//默认扫描
MNScanManager.startScan(mContext, new MNScanCallback() {
@Override
public void onActivityResult(int resultCode, Intent data) {
switch (resultCode) {
case MNScanManager.RESULT_SUCCESS:
ArrayList<String> results = data.getStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS);
if(results != null){
ToastUtil.showShort(mContext,results.get(0).toString());
}
break;
case MNScanManager.RESULT_FAIL:
String resultError = data.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR);
break;
case MNScanManager.RESULT_CANCLE:
ToastUtil.showShort(mContext,"取消扫码");
break;
}
}
});
}
@Override
protected void onPause() {
super.onPause();
// 停止帧动画
ImageView ivScanAnimation = viewBinding.ivScanAnimation;
if (ivScanAnimation.getDrawable() instanceof AnimationDrawable) {
AnimationDrawable animationDrawable = (AnimationDrawable) ivScanAnimation.getDrawable();
if (animationDrawable.isRunning()) {
animationDrawable.stop();
}
}
}
@Override
public int getLayoutResId(Bundle savedInstanceState) {
return 0;
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
@Override
public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
hidePermissionDialog();
if (requestCode == REQUEST_EVENT_CODE_10001) {
scanQrcode();
}
}
@Override
public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
}
@Override
public void addDeviceSuccess(BaseBean bean) {
}
@Override
public void getDeviceDetailInfo(WaterDeviceEntity bean) {
}
@Override
public void editDeviceInfoSuccess(BaseBean bean) {
}
@Override
public void deleteDeviceSuccess(BaseBean bean) {
}
@Override
public void turnOnOffDeviceSuccess(BaseBean bean) {
}
@Override
protected void onDestroy() {
super.onDestroy();
// 停止扫描
stopBleScan();
// 断开蓝牙连接
if (waterDeviceManager != null) {
waterDeviceManager.disconnect().enqueue();
waterDeviceManager.close();
waterDeviceManager = null;
}
}
}

View File

@@ -15,10 +15,9 @@ import com.ckkj.water.databinding.DeviceConnectLayoutBinding;
import com.ckkj.water.device.mvp.DeviceContract; import com.ckkj.water.device.mvp.DeviceContract;
import com.ckkj.water.device.mvp.DeviceImpl; import com.ckkj.water.device.mvp.DeviceImpl;
import com.ckkj.water.device.mvp.DevicePresenter; import com.ckkj.water.device.mvp.DevicePresenter;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.utils.manager.ActivityManager; import com.ckkj.water.utils.manager.ActivityManager;
import com.ckkj.water.utils.show.ToastUtil;
import com.gyf.immersionbar.ImmersionBar; import com.gyf.immersionbar.ImmersionBar;
/** /**
@@ -105,7 +104,7 @@ public class DeviceConnectActivity extends BaseActivity<DeviceConnectLayoutBindi
} }
@Override @Override
public void getDeviceDetailInfo(IndexDeviceEntity bean) { public void getDeviceDetailInfo(WaterDeviceEntity bean) {
} }

View File

@@ -2,6 +2,7 @@ package com.ckkj.water.device;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils;
import android.view.View; import android.view.View;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@@ -10,20 +11,21 @@ import com.chad.library.adapter.base.BaseQuickAdapter;
import com.ckkj.water.EventMessage; import com.ckkj.water.EventMessage;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity; import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.custom.GridSpacingItemDecoration; import com.ckkj.water.custom.GridSpacingItemDecoration;
import com.ckkj.water.custom.view.CustomAttachPopup;
import com.ckkj.water.custom.view.CustomBubbleAttachPopup; import com.ckkj.water.custom.view.CustomBubbleAttachPopup;
import com.ckkj.water.databinding.DeviceControlLayoutBinding; import com.ckkj.water.databinding.DeviceControlLayoutBinding;
import com.ckkj.water.device.adapter.DeviceTimeSelectAdapter; import com.ckkj.water.device.adapter.DeviceTimeSelectAdapter;
import com.ckkj.water.device.mvp.DeviceContract; import com.ckkj.water.device.mvp.DeviceContract;
import com.ckkj.water.device.mvp.DeviceImpl; import com.ckkj.water.device.mvp.DeviceImpl;
import com.ckkj.water.device.mvp.DevicePresenter; import com.ckkj.water.device.mvp.DevicePresenter;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.utils.manager.PowerIconManage;
import com.ckkj.water.utils.show.ToastUtil; import com.ckkj.water.utils.show.ToastUtil;
import com.gyf.immersionbar.ImmersionBar; import com.gyf.immersionbar.ImmersionBar;
import com.lxj.xpopup.XPopup; import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.core.BasePopupView;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -38,8 +40,11 @@ public class DeviceControlActivity extends BaseActivity<DeviceControlLayoutBindi
implements DeviceContract.DeviceView { implements DeviceContract.DeviceView {
private List<String> mTimeList = new ArrayList<>(); private List<String> mTimeList = new ArrayList<>();
private IndexDeviceEntity mDeviceEntity; private WaterDeviceEntity mDeviceEntity;
private WaterDeviceEntity mRemoteDeviceEntity;
private DeviceTimeSelectAdapter mAdapter; private DeviceTimeSelectAdapter mAdapter;
//用户自定义的浇水时长
private int mCustomDuration = 0;
@Override @Override
public DevicePresenter createPresenter() { public DevicePresenter createPresenter() {
return new DevicePresenter(new DeviceImpl()); return new DevicePresenter(new DeviceImpl());
@@ -50,11 +55,20 @@ public class DeviceControlActivity extends BaseActivity<DeviceControlLayoutBindi
super.initData(savedInstanceState); super.initData(savedInstanceState);
Bundle bundle = getIntent().getExtras(); Bundle bundle = getIntent().getExtras();
if(bundle != null){ if(bundle != null){
mDeviceEntity = (IndexDeviceEntity) bundle.getSerializable("device_info"); mDeviceEntity = (WaterDeviceEntity) bundle.getSerializable("device_info");
if(mDeviceEntity != null){ if(mDeviceEntity != null){
showLoadingDialog(); showLoadingDialog();
mPresenter.getDeviceDetailInfo(mDeviceEntity.getId()); mPresenter.getDeviceDetailInfo(mDeviceEntity.getId());
viewBinding.includedTitle.tvTitle.setText(mDeviceEntity.getDeviceName()); viewBinding.includedTitle.tvTitle.setText(mDeviceEntity.getDeviceName());
if(mDeviceEntity.getWorkStatus().equals("1")){
viewBinding.tvDeviceStatus.setText(getString(R.string.device_status_working));
viewBinding.tvDeviceStatus.setTextColor(mContext.getResources().getColor(R.color.color_zhu));
viewBinding.tvConfirm.setText(getString(R.string.device_control_stop));
}else{
viewBinding.tvDeviceStatus.setText(getString(R.string.device_status_not_working));
viewBinding.tvDeviceStatus.setTextColor(mContext.getResources().getColor(R.color.color_999999));
viewBinding.tvConfirm.setText(getString(R.string.device_control_start));
}
} }
} }
mTimeList.add("1min"); mTimeList.add("1min");
@@ -83,8 +97,15 @@ public class DeviceControlActivity extends BaseActivity<DeviceControlLayoutBindi
@Override @Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) { public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
mAdapter.setOnSelPosition(position); mAdapter.setOnSelPosition(position);
mCustomDuration = 0;
viewBinding.tvWorkDuartion.setHint(getString(R.string.device_custom_work_time));
viewBinding.tvWorkDuartion.setText("");
} }
}); });
//用户自定义时间
if(mCustomDuration == 0){
viewBinding.tvWorkDuartion.setHint(getString(R.string.device_custom_work_time));
}
initListener(); initListener();
} }
@@ -96,6 +117,7 @@ public class DeviceControlActivity extends BaseActivity<DeviceControlLayoutBindi
setClick(viewBinding.linearWifi); setClick(viewBinding.linearWifi);
setClick(viewBinding.linearBat); setClick(viewBinding.linearBat);
setClick(viewBinding.tvConfirm); setClick(viewBinding.tvConfirm);
setClick(viewBinding.tvWorkDuartion);
} }
private void setClick(View view) { private void setClick(View view) {
@@ -128,23 +150,118 @@ public class DeviceControlActivity extends BaseActivity<DeviceControlLayoutBindi
.isDestroyOnDismiss(true) //对于只使用一次的弹窗,推荐设置这个 .isDestroyOnDismiss(true) //对于只使用一次的弹窗,推荐设置这个
.atView(viewBinding.linearBat) .atView(viewBinding.linearBat)
.hasShadowBg(false) // 去掉半透明背景 .hasShadowBg(false) // 去掉半透明背景
.asCustom(new CustomBubbleAttachPopup(mContext,"设备电量:40% 更新时间: 05- 11 18:00")) .asCustom(new CustomBubbleAttachPopup(mContext,"设备电量:"+
mDeviceEntity.getPowerLevel() + "%" +
" 更新时间: 05- 11 18:00"))
.show(); .show();
break; break;
case R.id.tv_work_duartion:
inputDuration(mCustomDuration);
break;
case R.id.tv_confirm: case R.id.tv_confirm:
showCenterTipDialog(R.mipmap.icon_dialog_success,"开始浇水"); if(mCustomDuration == 0 && mAdapter.getmSelPostion() == -1){
ToastUtil.showShort(mContext,"请选择浇水时长");
return;
}
showCenterTipDialog(R.mipmap.icon_dialog_success,"开始浇水");//
String status = mDeviceEntity.getStatus();
if(status.equals("1")){
status = "0";
}else{
status = "1";
}
mPresenter.switchDeviceWork(mDeviceEntity.getId(),status,
mCustomDuration == 0 ? convertToMinutes(mTimeList.get(mAdapter.getmSelPostion()))
: mCustomDuration);
break; break;
} }
} }
/**
* 输入浇水时间
* @param currentDuration
*/
private void inputDuration(int currentDuration) {
showEditDialog(getString(R.string.device_work_times_title),
getString(R.string.input_water_plan_time),
currentDuration == 0 ? "" : currentDuration + "",
true,
getString(R.string.cancel_text),
getString(R.string.confirm_text),
INPUT_TYPE_NUMBER,
new BaseActivity.OnDialogClick() {
@Override
public void onCancelClick() {}
@Override
public void onConfirmClisk() {}
@Override
public void onConfirmClisk(String content) {
if (Integer.parseInt(content) <= 0) {
ToastUtil.showShort(mContext, getString(R.string.input_water_plan_time_error));
return;
}
viewBinding.tvWorkDuartion.setText(content);
mCustomDuration = Integer.parseInt(content);
if(mAdapter != null){
mAdapter.setOnSelPosition(-1);
}
}
@Override
public void onView1Click() {
}
});
}
/**
* 将时间字符串转换为分钟数
*
* 1min -> 1
* 10min -> 10
* 1h -> 60
* 2h -> 120
*
* @param timeValue 时间字符串
* @return 分钟数
*/
public static int convertToMinutes(String timeValue) {
if (TextUtils.isEmpty(timeValue)) {
return 0;
}
try {
if (timeValue.endsWith("min")) {
return Integer.parseInt(
timeValue.substring(0, timeValue.length() - 3)
);
}
if (timeValue.endsWith("h")) {
return Integer.parseInt(
timeValue.substring(0, timeValue.length() - 1)
) * 60;
}
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){ if(resultCode == RESULT_OK){
switch (requestCode){ switch (requestCode){
case REQUEST_EVENT_CODE_10002: case REQUEST_EVENT_CODE_10002:
mDeviceEntity = (IndexDeviceEntity) data.getSerializableExtra("device_entity"); mDeviceEntity = (WaterDeviceEntity) data.getSerializableExtra("device_entity");
viewBinding.includedTitle.tvTitle.setText(mDeviceEntity.getDeviceName()); viewBinding.includedTitle.tvTitle.setText(mDeviceEntity.getDeviceName());
break; break;
} }
@@ -165,9 +282,11 @@ public class DeviceControlActivity extends BaseActivity<DeviceControlLayoutBindi
* @param bean * @param bean
*/ */
@Override @Override
public void getDeviceDetailInfo(IndexDeviceEntity bean) { public void getDeviceDetailInfo(WaterDeviceEntity bean) {
hideDialogLoading(); hideDialogLoading();
viewBinding.imgBatStatus.setImageResource(PowerIconManage.getInstance().
getPowerVerIcon(Integer.parseInt(bean.getPowerLevel())));
mRemoteDeviceEntity = bean;
} }
@Override @Override

View File

@@ -9,7 +9,7 @@ import com.ckkj.water.databinding.DeviceInfoLayoutBinding;
import com.ckkj.water.device.mvp.DeviceContract; import com.ckkj.water.device.mvp.DeviceContract;
import com.ckkj.water.device.mvp.DeviceImpl; import com.ckkj.water.device.mvp.DeviceImpl;
import com.ckkj.water.device.mvp.DevicePresenter; import com.ckkj.water.device.mvp.DevicePresenter;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.gyf.immersionbar.ImmersionBar; import com.gyf.immersionbar.ImmersionBar;
@@ -73,7 +73,7 @@ public class DeviceInfoActivity extends BaseActivity<DeviceInfoLayoutBinding, De
} }
@Override @Override
public void getDeviceDetailInfo(IndexDeviceEntity bean) { public void getDeviceDetailInfo(WaterDeviceEntity bean) {
} }

View File

@@ -12,7 +12,7 @@ import com.ckkj.water.databinding.SetDeviceNameLayoutBinding;
import com.ckkj.water.device.mvp.DeviceContract; import com.ckkj.water.device.mvp.DeviceContract;
import com.ckkj.water.device.mvp.DeviceImpl; import com.ckkj.water.device.mvp.DeviceImpl;
import com.ckkj.water.device.mvp.DevicePresenter; import com.ckkj.water.device.mvp.DevicePresenter;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.utils.manager.ActivityManager; import com.ckkj.water.utils.manager.ActivityManager;
import com.ckkj.water.utils.show.ToastUtil; import com.ckkj.water.utils.show.ToastUtil;
@@ -87,7 +87,7 @@ public class DeviceReNameActivity extends BaseActivity<SetDeviceNameLayoutBindin
} }
@Override @Override
public void getDeviceDetailInfo(IndexDeviceEntity bean) { public void getDeviceDetailInfo(WaterDeviceEntity bean) {
} }

View File

@@ -16,14 +16,12 @@ import com.ckkj.water.databinding.DeviceSettingsLayoutBinding;
import com.ckkj.water.device.mvp.DeviceContract; import com.ckkj.water.device.mvp.DeviceContract;
import com.ckkj.water.device.mvp.DeviceImpl; import com.ckkj.water.device.mvp.DeviceImpl;
import com.ckkj.water.device.mvp.DevicePresenter; import com.ckkj.water.device.mvp.DevicePresenter;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.utils.show.ToastUtil; import com.ckkj.water.utils.show.ToastUtil;
import com.gyf.immersionbar.ImmersionBar; import com.gyf.immersionbar.ImmersionBar;
import de.greenrobot.event.EventBus; import de.greenrobot.event.EventBus;
import de.greenrobot.event.Subscribe;
import de.greenrobot.event.ThreadMode;
/** /**
* 设备控制页面 * 设备控制页面
@@ -31,7 +29,7 @@ import de.greenrobot.event.ThreadMode;
public class DeviceSettingsActivity extends BaseActivity<DeviceSettingsLayoutBinding, DevicePresenter> public class DeviceSettingsActivity extends BaseActivity<DeviceSettingsLayoutBinding, DevicePresenter>
implements DeviceContract.DeviceView { implements DeviceContract.DeviceView {
private IndexDeviceEntity mDeviceEntity; private WaterDeviceEntity mDeviceEntity;
@Override @Override
public DevicePresenter createPresenter() { public DevicePresenter createPresenter() {
return new DevicePresenter(new DeviceImpl()); return new DevicePresenter(new DeviceImpl());
@@ -42,7 +40,7 @@ public class DeviceSettingsActivity extends BaseActivity<DeviceSettingsLayoutBin
super.initData(savedInstanceState); super.initData(savedInstanceState);
Bundle bundle = getIntent().getExtras(); Bundle bundle = getIntent().getExtras();
if(bundle != null){ if(bundle != null){
mDeviceEntity = (IndexDeviceEntity) bundle.getSerializable("device_entity"); mDeviceEntity = (WaterDeviceEntity) bundle.getSerializable("device_entity");
viewBinding.tvDeviceName.setText(mDeviceEntity.getDeviceName()); viewBinding.tvDeviceName.setText(mDeviceEntity.getDeviceName());
viewBinding.tvWifiName.setText(mDeviceEntity.getWifiName()); viewBinding.tvWifiName.setText(mDeviceEntity.getWifiName());
@@ -83,7 +81,9 @@ public class DeviceSettingsActivity extends BaseActivity<DeviceSettingsLayoutBin
mDeviceEntity.getDeviceName(), mDeviceEntity.getDeviceName(),
true, true,
getString(R.string.cancel_text), getString(R.string.cancel_text),
getString(R.string.confirm_text), new OnDialogClick() { getString(R.string.confirm_text),
BaseActivity.INPUT_TYPE_NORMAL,
new OnDialogClick() {
@Override @Override
public void onCancelClick() { public void onCancelClick() {
} }
@@ -209,7 +209,7 @@ public class DeviceSettingsActivity extends BaseActivity<DeviceSettingsLayoutBin
} }
@Override @Override
public void getDeviceDetailInfo(IndexDeviceEntity bean) { public void getDeviceDetailInfo(WaterDeviceEntity bean) {
} }

View File

@@ -8,13 +8,12 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.wifi.ScanResult; import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import android.view.View; import android.view.View;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import com.ckkj.water.ConstantUtil; import com.ckkj.water.ConstantUtil;
import com.ckkj.water.R; import com.ckkj.water.R;
@@ -23,13 +22,14 @@ import com.ckkj.water.databinding.DeviceResetWifiBinding;
import com.ckkj.water.device.mvp.DeviceContract; import com.ckkj.water.device.mvp.DeviceContract;
import com.ckkj.water.device.mvp.DeviceImpl; import com.ckkj.water.device.mvp.DeviceImpl;
import com.ckkj.water.device.mvp.DevicePresenter; import com.ckkj.water.device.mvp.DevicePresenter;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.espBle.EspProvisionManager;
import com.ckkj.water.espBle.ProvisionCallback;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.permission.PermissionActivity; import com.ckkj.water.permission.PermissionActivity;
import com.ckkj.water.utils.manager.ActivityManager; import com.ckkj.water.utils.manager.ActivityManager;
import com.ckkj.water.utils.manager.ThemeManager; import com.ckkj.water.utils.manager.ThemeManager;
import com.ckkj.water.utils.show.ToastUtil; import com.ckkj.water.utils.show.ToastUtil;
import com.ckkj.water.utils.text.TextUtil;
import com.gyf.immersionbar.ImmersionBar; import com.gyf.immersionbar.ImmersionBar;
import java.util.ArrayList; import java.util.ArrayList;
@@ -37,6 +37,9 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
/**
* 配置wifi
*/
public class SelectWifiActivity extends BaseActivity<DeviceResetWifiBinding, DevicePresenter> public class SelectWifiActivity extends BaseActivity<DeviceResetWifiBinding, DevicePresenter>
implements DeviceContract.DeviceView { implements DeviceContract.DeviceView {
@@ -48,6 +51,11 @@ public class SelectWifiActivity extends BaseActivity<DeviceResetWifiBinding, Dev
private String mWifiName = ""; private String mWifiName = "";
private WaterDeviceEntity mBleDeviceEntity;
private EspProvisionManager espProvisionManager;
private boolean isBleConnecting = false;
private boolean isBleConnected = false;
@Override @Override
public DevicePresenter createPresenter() { public DevicePresenter createPresenter() {
return new DevicePresenter(new DeviceImpl()); return new DevicePresenter(new DeviceImpl());
@@ -73,12 +81,22 @@ public class SelectWifiActivity extends BaseActivity<DeviceResetWifiBinding, Dev
unregisterReceiver(wifiScanReceiver); unregisterReceiver(wifiScanReceiver);
} }
@Override
protected void onDestroy() {
super.onDestroy();
if (WITCH_FROM_CODE == 100 && espProvisionManager != null) {
espProvisionManager.disconnect();
espProvisionManager.setCallback(null);
}
}
@Override @Override
public void initData(Bundle savedInstanceState) { public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState); super.initData(savedInstanceState);
Bundle bundle = getIntent().getExtras(); Bundle bundle = getIntent().getExtras();
if(bundle != null){ if(bundle != null){
WITCH_FROM_CODE = bundle.getInt(ConstantUtil.ACTIVITY_NAVIGATE_FLAG); WITCH_FROM_CODE = bundle.getInt(ConstantUtil.ACTIVITY_NAVIGATE_FLAG);
mBleDeviceEntity = (WaterDeviceEntity) bundle.getSerializable("ble_device_entity");
} }
ImmersionBar.with(this) ImmersionBar.with(this)
@@ -93,6 +111,10 @@ public class SelectWifiActivity extends BaseActivity<DeviceResetWifiBinding, Dev
initListener(); initListener();
initWifiList(); initWifiList();
if (WITCH_FROM_CODE == 100) {
initEspProvision();
connectBleDevice();
}
} }
private void initWifiList() { private void initWifiList() {
@@ -145,7 +167,7 @@ public class SelectWifiActivity extends BaseActivity<DeviceResetWifiBinding, Dev
return; return;
} }
if(WITCH_FROM_CODE == 100){ if(WITCH_FROM_CODE == 100){
goTo(mContext,DeviceConnectActivity.class,null); provisionWifi();
}else{ }else{
Intent intent = new Intent(); Intent intent = new Intent();
intent.putExtra("wifi_name",mWifiName); intent.putExtra("wifi_name",mWifiName);
@@ -157,6 +179,98 @@ public class SelectWifiActivity extends BaseActivity<DeviceResetWifiBinding, Dev
} }
} }
/**
* 配置网络
*/
private void provisionWifi() {
if (espProvisionManager == null) {
ToastUtil.showShort(mContext, "设备连接未初始化");
return;
}
if (!isBleConnected) {
if (!isBleConnecting) {
connectBleDevice();
}
ToastUtil.showShort(mContext, "设备连接中,请稍后再试");
return;
}
espProvisionManager.provisionWifi(mWifiName, viewBinding.etInputPsd.getText().toString());
// goTo(mContext,DeviceConnectActivity.class,null);
}
private void initEspProvision() {
espProvisionManager = EspProvisionManager.init(mContext).setCallback(new ProvisionCallback() {
@Override
public void onConnecting() {
isBleConnecting = true;
isBleConnected = false;
Log.i("TEST","onConnecting");
}
@Override
public void onConnected() {
isBleConnecting = false;
isBleConnected = true;
Log.i("TEST","onConnected设备连接成功");
}
@Override
public void onProvisioning(int progress) {
Log.i("TEST","WIFI连接进度 == " + progress);
}
@Override
public void onSuccess(String deviceName, String deviceType) {
Log.i("TEST","deviceName" + deviceName + "连接成功");
}
@Override
public void onFailed(int errorCode, String message) {
isBleConnecting = false;
if (errorCode != 0) {
isBleConnected = espProvisionManager != null && espProvisionManager.isConnected();
}
Log.i("TEST","errorCode == " + errorCode + " message == " + message);
ToastUtil.showShort(mContext, message);
}
@Override
public void onDisconnected() {
isBleConnecting = false;
isBleConnected = false;
Log.i("TEST","onDisconnected");
}
@Override
public void onWifiListReceived(String[] wifiList) {
}
@Override
public void onWifiListFailed(String message) {
Log.i("TEST","onWifiListFailed-Msg==" + message);
}
@Override
public void onProvisioningRejected() {
Log.i("TEST","onProvisioningRejected");
}
});
}
/**
* 连接设备
*/
private void connectBleDevice() {
if (WITCH_FROM_CODE != 100 || mBleDeviceEntity == null || espProvisionManager == null) {
return;
}
if (isBleConnected || isBleConnecting) {
return;
}
espProvisionManager.connect(mBleDeviceEntity.getMacAddress(), mBleDeviceEntity.getDeviceName());
}
private void scanWifi() { private void scanWifi() {
showLoadingDialog(); showLoadingDialog();
viewBinding.tvNext.setVisibility(View.GONE); viewBinding.tvNext.setVisibility(View.GONE);
@@ -198,7 +312,7 @@ public class SelectWifiActivity extends BaseActivity<DeviceResetWifiBinding, Dev
} }
@Override @Override
public void getDeviceDetailInfo(IndexDeviceEntity bean) { public void getDeviceDetailInfo(WaterDeviceEntity bean) {
} }

View File

@@ -0,0 +1,31 @@
package com.ckkj.water.device.adapter;
import android.content.Context;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2026/6/3
* @description 扫描到的设备适配器
*/
public class BleScanDeviceAdapter extends BaseQuickAdapter<WaterDeviceEntity, BaseViewHolder> {
private Context mContext;
public BleScanDeviceAdapter(Context context,int layoutResId, @Nullable List<WaterDeviceEntity> data) {
super(layoutResId, data);
mContext = context;
}
@Override
protected void convert(BaseViewHolder helper, WaterDeviceEntity item) {
helper.setText(R.id.tv_device_name, TextUtils.isEmpty(item.getDeviceName())? "未知设备" : item.getDeviceName());
}
}

View File

@@ -17,6 +17,15 @@ public class DeviceTimeSelectAdapter extends BaseQuickAdapter<String, BaseViewHo
private List<String> mDatas = new ArrayList<>(); private List<String> mDatas = new ArrayList<>();
private int mSelPostion = -1; private int mSelPostion = -1;
public int getmSelPostion() {
return mSelPostion;
}
public void setmSelPostion(int mSelPostion) {
this.mSelPostion = mSelPostion;
}
public DeviceTimeSelectAdapter(Context context, int layoutResId, @Nullable List<String> data) { public DeviceTimeSelectAdapter(Context context, int layoutResId, @Nullable List<String> data) {
super(layoutResId, data); super(layoutResId, data);
this.mContext = context; this.mContext = context;

View File

@@ -0,0 +1,18 @@
package com.ckkj.water.device.manage;
import android.content.Context;
import androidx.annotation.NonNull;
import no.nordicsemi.android.ble.BleManager;
/**
* @author fengxiaoyang
* @date 2026/5/30
* @description TODO: 描述该类的作用
*/
public class DeviceBleManager extends BleManager {
public DeviceBleManager(@NonNull Context context) {
super(context);
}
}

View File

@@ -1,7 +1,7 @@
package com.ckkj.water.device.mvp; package com.ckkj.water.device.mvp;
import com.ckkj.water.base.IView; import com.ckkj.water.base.IView;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.index.mvp.IndexContract; import com.ckkj.water.index.mvp.IndexContract;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
@@ -25,7 +25,7 @@ public class DeviceContract {
void editDeviceInfo(JSONObject json, IndexContract.CallBack callBack); void editDeviceInfo(JSONObject json, IndexContract.CallBack callBack);
//删除设备信息 //删除设备信息
void deleteDevice(String id,JSONObject json, IndexContract.CallBack callBack); void deleteDevice(String id, IndexContract.CallBack callBack);
//手动开启关闭设备 //手动开启关闭设备
void turnOnOffDevice(JSONObject json, IndexContract.CallBack callBack); void turnOnOffDevice(JSONObject json, IndexContract.CallBack callBack);
@@ -34,7 +34,7 @@ public class DeviceContract {
public interface DeviceView extends IView { public interface DeviceView extends IView {
//添加设备成功g //添加设备成功g
void addDeviceSuccess(BaseBean bean); void addDeviceSuccess(BaseBean bean);
void getDeviceDetailInfo(IndexDeviceEntity bean); void getDeviceDetailInfo(WaterDeviceEntity bean);
void editDeviceInfoSuccess(BaseBean bean); void editDeviceInfoSuccess(BaseBean bean);
void deleteDeviceSuccess(BaseBean bean); void deleteDeviceSuccess(BaseBean bean);
void turnOnOffDeviceSuccess(BaseBean bean); void turnOnOffDeviceSuccess(BaseBean bean);

View File

@@ -1,7 +1,6 @@
package com.ckkj.water.device.mvp; package com.ckkj.water.device.mvp;
import com.ckkj.water.base.entity.MineUserInfoBean; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.index.entity.IndexDeviceEntity;
import com.ckkj.water.index.mvp.IndexContract; import com.ckkj.water.index.mvp.IndexContract;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.network.NetWorkManager; import com.ckkj.water.network.NetWorkManager;
@@ -25,13 +24,13 @@ public class DeviceImpl implements DeviceContract.DataModel{
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<IndexDeviceEntity>>() { .subscribe(new Observer<BaseBean<WaterDeviceEntity>>() {
@Override @Override
public void onSubscribe(@NonNull Disposable d) { public void onSubscribe(@NonNull Disposable d) {
} }
@Override @Override
public void onNext(@NonNull BaseBean<IndexDeviceEntity> bean) { public void onNext(@NonNull BaseBean<WaterDeviceEntity> bean) {
if (bean.getCode() == 200) { if (bean.getCode() == 200) {
callBack.success(bean.getData(),0); callBack.success(bean.getData(),0);
} }
@@ -130,11 +129,10 @@ public class DeviceImpl implements DeviceContract.DataModel{
/** /**
* 删除设备 * 删除设备
* @param json
* @param callBack * @param callBack
*/ */
@Override @Override
public void deleteDevice(String devID,JSONObject json, IndexContract.CallBack callBack) { public void deleteDevice(String devID, IndexContract.CallBack callBack) {
try { try {
NetWorkManager.getRequest().unBindDevice(NetWorkManager.getToken(), devID) NetWorkManager.getRequest().unBindDevice(NetWorkManager.getToken(), devID)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
@@ -168,8 +166,43 @@ public class DeviceImpl implements DeviceContract.DataModel{
} }
} }
/**
* 手动开启关闭设备
* @param json
* @param callBack
*/
@Override @Override
public void turnOnOffDevice(JSONObject json, IndexContract.CallBack callBack) { public void turnOnOffDevice(JSONObject json, IndexContract.CallBack callBack) {
try {
NetWorkManager.getRequest().switchDevice(NetWorkManager.getToken(), NetWorkManager.toRequestBody(json))
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean bean) {
if (bean.getCode() == 200) {
callBack.success(bean,0);
} else {
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
e.printStackTrace();
}
} }
} }

View File

@@ -1,11 +1,10 @@
package com.ckkj.water.device.mvp; package com.ckkj.water.device.mvp;
import com.ckkj.water.base.BasePresenter; import com.ckkj.water.base.BasePresenter;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.index.mvp.IndexContract; import com.ckkj.water.index.mvp.IndexContract;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@@ -61,9 +60,9 @@ public class DevicePresenter extends BasePresenter<DeviceContract.DeviceView> {
public void getDeviceDetailInfo(String deviceID) { public void getDeviceDetailInfo(String deviceID) {
Map<String,String> map = new HashMap<>(); Map<String,String> map = new HashMap<>();
map.put("id",deviceID); map.put("id",deviceID);
impl.getDeviceInfomation(map, new IndexContract.CallBack<IndexDeviceEntity>() { impl.getDeviceInfomation(map, new IndexContract.CallBack<WaterDeviceEntity>() {
@Override @Override
public void success(IndexDeviceEntity bean,int total) { public void success(WaterDeviceEntity bean, int total) {
if(DevicePresenter.this.getView() != null){ if(DevicePresenter.this.getView() != null){
DevicePresenter.this.getView().getDeviceDetailInfo(bean); DevicePresenter.this.getView().getDeviceDetailInfo(bean);
} }
@@ -82,7 +81,7 @@ public class DevicePresenter extends BasePresenter<DeviceContract.DeviceView> {
* 修改设备信息 * 修改设备信息
* @param mDeviceEntity * @param mDeviceEntity
*/ */
public void updateDeviceInfo(IndexDeviceEntity mDeviceEntity) { public void updateDeviceInfo(WaterDeviceEntity mDeviceEntity) {
try { try {
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
json.put("id",mDeviceEntity.getId()); json.put("id",mDeviceEntity.getId());
@@ -113,14 +112,8 @@ public class DevicePresenter extends BasePresenter<DeviceContract.DeviceView> {
* 解绑设备 * 解绑设备
* @param deviceEntity * @param deviceEntity
*/ */
public void unBindDevice(IndexDeviceEntity deviceEntity) { public void unBindDevice(WaterDeviceEntity deviceEntity) {
try { impl.deleteDevice(deviceEntity.getId(), new IndexContract.CallBack<BaseBean>() {
// 构造JSON数组格式的请求体 ["2052921001527869441"]
JSONArray jsonArray = new JSONArray();
jsonArray.put(deviceEntity.getId());
JSONObject json = new JSONObject();
json.put("ids", jsonArray);
impl.deleteDevice(deviceEntity.getId(),json, new IndexContract.CallBack<BaseBean>() {
@Override @Override
public void success(BaseBean bean, int total) { public void success(BaseBean bean, int total) {
if (DevicePresenter.this.getView() != null) { if (DevicePresenter.this.getView() != null) {
@@ -128,6 +121,36 @@ public class DevicePresenter extends BasePresenter<DeviceContract.DeviceView> {
} }
} }
@Override
public void fail(String msg) {
if (DevicePresenter.this.getView() != null) {
DevicePresenter.this.getView().showError(msg);
}
}
});
}
/**
* 开启/关闭浇水
* @param id
* @param status
* @param duration
*/
public void switchDeviceWork(String id, String status, int duration) {
try {
JSONObject json = new JSONObject();
json.put("id",id);
json.put("workStatus",status);
// json.put("startTime","09:50");
json.put("durationMin",duration + "");
impl.turnOnOffDevice(json, new IndexContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean,int total) {
if(DevicePresenter.this.getView() != null){
DevicePresenter.this.getView().turnOnOffDeviceSuccess(bean);
}
}
@Override @Override
public void fail(String msg) { public void fail(String msg) {
if(DevicePresenter.this.getView() != null){ if(DevicePresenter.this.getView() != null){

View File

@@ -0,0 +1,517 @@
package com.ckkj.water.espBle;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import com.ckkj.water.AppConfig;
import com.espressif.provisioning.DeviceConnectionEvent;
import com.espressif.provisioning.ESPConstants;
import com.espressif.provisioning.ESPDevice;
import com.espressif.provisioning.WiFiAccessPoint;
import com.espressif.provisioning.listeners.ProvisionListener;
import com.espressif.provisioning.listeners.WiFiScanListener;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.Set;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
/**
* @author fengxiaoyang
* @date 2026/6/4
* @description 鎿嶄綔钃濈墮绠$悊绫?
*/
public class EspProvisionManager {
private static volatile EspProvisionManager instance;
private final Context context;
private final Handler mainHandler;
private final com.espressif.provisioning.ESPProvisionManager provisionManager;
private ESPDevice espDevice;
private ProvisionCallback callback;
private boolean connecting;
private boolean connected;
private boolean provisioning;
private boolean eventBusRegistered;
private boolean ignoreNextDisconnectEvent;
private String currentDeviceName;
private String currentDeviceType = ProvisionConfig.TRANSPORT_BLE;
private final Runnable connectionTimeoutTask = new Runnable() {
@Override
public void run() {
if (connecting && !connected) {
connecting = false;
notifyFailed(ProvisionConfig.ERROR_CONNECT_TIMEOUT, "蓝牙连接超时");
disconnectDeviceOnly();
}
}
};
private final Runnable provisionTimeoutTask = new Runnable() {
@Override
public void run() {
if (provisioning) {
finishProvisionFailed(ProvisionConfig.ERROR_PROVISION_TIMEOUT, "配网超时");
}
}
};
private EspProvisionManager(Context context) {
this.context = context.getApplicationContext();
this.mainHandler = new Handler(Looper.getMainLooper());
this.provisionManager = com.espressif.provisioning.ESPProvisionManager.getInstance(this.context);
ensureEventBusRegistered();
}
public static EspProvisionManager init(Context context) {
if (instance == null) {
synchronized (EspProvisionManager.class) {
if (instance == null) {
instance = new EspProvisionManager(context);
}
}
}
return instance;
}
public static EspProvisionManager get() {
if (instance == null) {
throw new RuntimeException("Please call init()");
}
return instance;
}
public EspProvisionManager setCallback(ProvisionCallback callback) {
this.callback = callback;
return this;
}
public ESPDevice getEspDevice() {
return espDevice;
}
public boolean isConnected() {
return connected;
}
public boolean isProvisioning() {
return provisioning;
}
public void connect(String deviceAddress, String deviceName) {
connect(deviceAddress, deviceName, AppConfig.BLUETOOTH_DEVICE_UUID);
}
public void connect(String deviceAddress, String deviceName, String serviceUuid) {
connect(deviceAddress, deviceName, serviceUuid, "", ProvisionConfig.DEFAULT_SECURITY);
}
public void connect(String deviceAddress, String deviceName, String serviceUuid,
String proofOfPossession, int securityType) {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null || TextUtils.isEmpty(deviceAddress)) {
notifyFailed(ProvisionConfig.ERROR_INVALID_DEVICE, "蓝牙设备无效");
return;
}
try {
BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(deviceAddress);
connect(bluetoothDevice, deviceName, serviceUuid, proofOfPossession, securityType);
} catch (IllegalArgumentException e) {
notifyFailed(ProvisionConfig.ERROR_INVALID_DEVICE, "蓝牙设备地址无效");
}
}
public void connect(BluetoothDevice bluetoothDevice, String serviceUuid) {
connect(bluetoothDevice, null, serviceUuid, "", ProvisionConfig.DEFAULT_SECURITY);
}
public void connect(BluetoothDevice bluetoothDevice, String deviceName, String serviceUuid,
String proofOfPossession, int securityType) {
connect(bluetoothDevice, deviceName, serviceUuid, proofOfPossession, "", securityType);
}
public void connect(BluetoothDevice bluetoothDevice, String deviceName, String serviceUuid,
String proofOfPossession, String userName, int securityType) {
if (bluetoothDevice == null) {
notifyFailed(ProvisionConfig.ERROR_INVALID_DEVICE, "蓝牙设备无效");
return;
}
String primaryServiceUuid = TextUtils.isEmpty(serviceUuid) ? ProvisionConfig.SERVICE_UUID : serviceUuid;
String displayName = !TextUtils.isEmpty(deviceName) ? deviceName : bluetoothDevice.getName();
currentDeviceName = displayName;
currentDeviceType = ProvisionConfig.TRANSPORT_BLE;
ignoreNextDisconnectEvent = espDevice != null;
disconnectDeviceOnly();
ensureEventBusRegistered();
espDevice = provisionManager.createESPDevice(
ESPConstants.TransportType.TRANSPORT_BLE,
parseSecurityType(securityType)
);
espDevice.setBluetoothDevice(bluetoothDevice);
espDevice.setPrimaryServiceUuid(primaryServiceUuid);
espDevice.setDeviceName(displayName);
espDevice.setProofOfPossession(proofOfPossession == null ? "" : proofOfPossession);
espDevice.setUserName(userName == null ? "" : userName);
connecting = true;
connected = false;
provisioning = false;
mainHandler.removeCallbacks(connectionTimeoutTask);
mainHandler.postDelayed(connectionTimeoutTask, ProvisionConfig.CONNECTION_TIMEOUT);
notifyConnecting();
espDevice.connectBLEDevice(bluetoothDevice, primaryServiceUuid);
}
public void scanDeviceWifiList() {
if (!checkConnected()) {
notifyWifiListFailed("设备未连接");
return;
}
espDevice.scanNetworks(new WiFiScanListener() {
@Override
public void onWifiListReceived(ArrayList<WiFiAccessPoint> wifiList) {
Set<String> wifiNames = new LinkedHashSet<>();
if (wifiList != null) {
for (WiFiAccessPoint accessPoint : wifiList) {
if (accessPoint != null && !TextUtils.isEmpty(accessPoint.getWifiName())) {
wifiNames.add(accessPoint.getWifiName());
}
}
}
notifyWifiListReceived(wifiNames.toArray(new String[0]));
}
@Override
public void onWiFiScanFailed(Exception e) {
notifyWifiListFailed(getErrorMessage(e, "获取设备 WiFi 列表失败"));
}
});
}
public void provision(String ssid, String password) {
provisionWifi(ssid, password);
}
public void provisionWifi(String ssid, String password) {
if (!checkConnected()) {
notifyFailed(ProvisionConfig.ERROR_NOT_CONNECTED, "设备未连接");
return;
}
if (TextUtils.isEmpty(ssid)) {
notifyFailed(ProvisionConfig.ERROR_WIFI_CONFIG_FAILED, "WiFi 名称不能为空");
return;
}
provisioning = true;
mainHandler.removeCallbacks(provisionTimeoutTask);
mainHandler.postDelayed(provisionTimeoutTask, ProvisionConfig.PROVISION_TIMEOUT);
notifyProvisioning(0);
espDevice.provision(ssid, password == null ? "" : password, new ProvisionListener() {
@Override
public void createSessionFailed(Exception e) {
finishProvisionFailed(ProvisionConfig.ERROR_SESSION_FAILED, getErrorMessage(e, "创建配网会话失败"));
}
@Override
public void wifiConfigSent() {
notifyProvisioning(30);
}
@Override
public void wifiConfigFailed(Exception e) {
notifyProvisioningRejected();
finishProvisionFailed(ProvisionConfig.ERROR_WIFI_CONFIG_FAILED, getErrorMessage(e, "发送 WiFi 信息失败"));
}
@Override
public void wifiConfigApplied() {
notifyProvisioning(60);
}
@Override
public void wifiConfigApplyFailed(Exception e) {
finishProvisionFailed(ProvisionConfig.ERROR_WIFI_APPLY_FAILED, getErrorMessage(e, "应用 WiFi 信息失败"));
}
@Override
public void provisioningFailedFromDevice(ESPConstants.ProvisionFailureReason failureReason) {
finishProvisionFailed(ProvisionConfig.ERROR_PROVISION_FAILED, getProvisionFailureMessage(failureReason));
}
@Override
public void deviceProvisioningSuccess() {
finishProvisionSuccess();
}
@Override
public void onProvisioningFailed(Exception e) {
finishProvisionFailed(ProvisionConfig.ERROR_PROVISION_FAILED, getErrorMessage(e, "配网失败"));
}
});
}
public void disconnect() {
boolean shouldNotify = connected || connecting || provisioning;
disconnectDeviceOnly();
resetState();
if (shouldNotify) {
notifyDisconnected();
}
}
public void release() {
disconnect();
callback = null;
mainHandler.removeCallbacksAndMessages(null);
if (eventBusRegistered) {
EventBus.getDefault().unregister(this);
eventBusRegistered = false;
}
if (instance == this) {
instance = null;
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onDeviceConnectionEvent(DeviceConnectionEvent event) {
if (event == null) {
return;
}
switch (event.getEventType()) {
case ESPConstants.EVENT_DEVICE_CONNECTED:
mainHandler.removeCallbacks(connectionTimeoutTask);
connecting = false;
connected = true;
notifyConnected();
break;
case ESPConstants.EVENT_DEVICE_CONNECTION_FAILED:
mainHandler.removeCallbacks(connectionTimeoutTask);
mainHandler.removeCallbacks(provisionTimeoutTask);
boolean wasConnecting = connecting;
connecting = false;
connected = false;
provisioning = false;
if (wasConnecting) {
notifyFailed(ProvisionConfig.ERROR_CONNECT_FAILED, "蓝牙连接失败");
} else {
notifyFailed(ProvisionConfig.ERROR_PROVISION_FAILED, "设备通信失败");
}
break;
case ESPConstants.EVENT_DEVICE_DISCONNECTED:
if (ignoreNextDisconnectEvent) {
ignoreNextDisconnectEvent = false;
return;
}
mainHandler.removeCallbacks(connectionTimeoutTask);
mainHandler.removeCallbacks(provisionTimeoutTask);
boolean shouldNotify = connected || connecting || provisioning;
resetState();
if (shouldNotify) {
notifyDisconnected();
}
break;
default:
break;
}
}
private boolean checkConnected() {
return espDevice != null && connected;
}
private void ensureEventBusRegistered() {
if (!eventBusRegistered) {
EventBus.getDefault().register(this);
eventBusRegistered = true;
}
}
private void disconnectDeviceOnly() {
if (espDevice != null) {
try {
espDevice.disconnectDevice();
} catch (Exception ignored) {
}
}
}
private void resetState() {
mainHandler.removeCallbacks(connectionTimeoutTask);
mainHandler.removeCallbacks(provisionTimeoutTask);
connecting = false;
connected = false;
provisioning = false;
ignoreNextDisconnectEvent = false;
}
private ESPConstants.SecurityType parseSecurityType(int securityType) {
if (securityType == ProvisionConfig.SECURITY_0) {
return ESPConstants.SecurityType.SECURITY_0;
} else if (securityType == ProvisionConfig.SECURITY_1) {
return ESPConstants.SecurityType.SECURITY_1;
} else {
return ESPConstants.SecurityType.SECURITY_2;
}
}
private void finishProvisionSuccess() {
mainHandler.removeCallbacks(provisionTimeoutTask);
provisioning = false;
notifyProvisioning(100);
notifySuccess();
}
private void finishProvisionFailed(int errorCode, String message) {
mainHandler.removeCallbacks(provisionTimeoutTask);
provisioning = false;
notifyFailed(errorCode, message);
}
private String getProvisionFailureMessage(ESPConstants.ProvisionFailureReason failureReason) {
if (failureReason == ESPConstants.ProvisionFailureReason.AUTH_FAILED) {
return "WiFi 密码错误";
} else if (failureReason == ESPConstants.ProvisionFailureReason.NETWORK_NOT_FOUND) {
return "未找到指定 WiFi";
} else if (failureReason == ESPConstants.ProvisionFailureReason.DEVICE_DISCONNECTED) {
return "设备已断开连接";
} else {
return "设备配网失败";
}
}
private String getErrorMessage(Exception e, String defaultMessage) {
if (e != null && !TextUtils.isEmpty(e.getMessage())) {
return e.getMessage();
}
return defaultMessage;
}
private void runOnMainThread(Runnable runnable) {
if (Looper.myLooper() == Looper.getMainLooper()) {
runnable.run();
} else {
mainHandler.post(runnable);
}
}
private void notifyConnecting() {
runOnMainThread(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.onConnecting();
}
}
});
}
private void notifyConnected() {
runOnMainThread(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.onConnected();
}
}
});
}
private void notifyProvisioning(final int progress) {
runOnMainThread(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.onProvisioning(progress);
}
}
});
}
private void notifySuccess() {
runOnMainThread(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.onSuccess(currentDeviceName, currentDeviceType);
}
}
});
}
private void notifyFailed(final int errorCode, final String message) {
runOnMainThread(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.onFailed(errorCode, message);
}
}
});
}
private void notifyDisconnected() {
runOnMainThread(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.onDisconnected();
}
}
});
}
private void notifyWifiListReceived(final String[] wifiList) {
runOnMainThread(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.onWifiListReceived(wifiList);
}
}
});
}
private void notifyWifiListFailed(final String message) {
runOnMainThread(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.onWifiListFailed(message);
}
}
});
}
private void notifyProvisioningRejected() {
runOnMainThread(new Runnable() {
@Override
public void run() {
if (callback != null) {
callback.onProvisioningRejected();
}
}
});
}
}

View File

@@ -0,0 +1,61 @@
package com.ckkj.water.espBle;
/**
* @author fengxiaoyang
* @date 2026/6/4
* @description 蓝牙设备配网回调接口
*/
public interface ProvisionCallback {
/**
* 正在连接设备
*/
void onConnecting();
/**
* 设备连接成功
*/
void onConnected();
/**
* 正在配网中
* @param progress 配网进度 (0-100)
*/
void onProvisioning(int progress);
/**
* 配网成功
* @param deviceName 设备名称
* @param deviceType 设备类型
*/
void onSuccess(String deviceName, String deviceType);
/**
* 配网失败
* @param errorCode 错误码
* @param message 错误信息
*/
void onFailed(int errorCode, String message);
/**
* 设备断开连接
*/
void onDisconnected();
/**
* WiFi列表获取成功
* @param wifiList WiFi列表
*/
void onWifiListReceived(String[] wifiList);
/**
* 获取WiFi列表失败
* @param message 错误信息
*/
void onWifiListFailed(String message);
/**
* 配网被拒绝(设备端拒绝配网请求)
*/
void onProvisioningRejected();
}

View File

@@ -0,0 +1,125 @@
package com.ckkj.water.espBle;
import android.os.Build;
import com.espressif.provisioning.ESPConstants;
/**
* @author fengxiaoyang
* @date 2026/6/4
* @description 蓝牙配网配置管理类
*/
public class ProvisionConfig {
/**
* ESP BLE Service UUID
*/
public static final String SERVICE_UUID =
"0000ffff-0000-1000-8000-00805f9b34fb";
/**
* ESP BLE Characteristic UUID for writes
*/
public static final String CHARACTERISTIC_UUID =
"0000ff01-0000-1000-8000-00805f9b34fb";
/**
* ESP BLE Characteristic UUID for notifications
*/
public static final String NOTIFY_UUID =
"0000ff02-0000-1000-8000-00805f9b34fb";
/**
* 设备传输的协议类型
*/
public static final String TRANSPORT_BLE = "ble";
/**
* 设备前缀 (用于过滤设备)
*/
public static final String DEVICE_PREFIX = "PROV_";
/**
* 安全类型 - SECURITY_0 (无安全)
*/
public static final int SECURITY_0 = ESPConstants.SecurityType.SECURITY_0.ordinal();
/**
* 安全类型 - SECURITY_1 (推荐)
*/
public static final int SECURITY_1 = ESPConstants.SecurityType.SECURITY_1.ordinal();
/**
* 默认安全类型
*/
public static final int DEFAULT_SECURITY = SECURITY_1;
/**
* 连接超时时间 (毫秒)
*/
public static final int CONNECTION_TIMEOUT = 30000;
/**
* 配网超时时间 (毫秒)
*/
public static final int PROVISION_TIMEOUT = 120000;
public static final int ERROR_NOT_INITIALIZED = 1000;
public static final int ERROR_INVALID_DEVICE = 1001;
public static final int ERROR_CONNECT_TIMEOUT = 1002;
public static final int ERROR_CONNECT_FAILED = 1003;
public static final int ERROR_NOT_CONNECTED = 1004;
public static final int ERROR_SESSION_FAILED = 1005;
public static final int ERROR_WIFI_CONFIG_FAILED = 1006;
public static final int ERROR_WIFI_APPLY_FAILED = 1007;
public static final int ERROR_PROVISION_FAILED = 1008;
public static final int ERROR_PROVISION_TIMEOUT = 1009;
public static final int ERROR_WIFI_SCAN_FAILED = 1010;
/**
* 配网版本 (可根据实际固件调整)
*/
public static final String VERSION = "v1.1";
/**
* 生成蓝牙扫描过滤器
* @return 服务UUID数组
*/
public static String[] getScanServiceUuids() {
return new String[]{SERVICE_UUID};
}
/**
* 生成设备前缀过滤器 (用于过滤非ESP设备)
* @return 设备前缀
*/
public static String getDevicePrefix() {
return DEVICE_PREFIX;
}
/**
* 获取当前Android版本号
* @return Android版本号
*/
public static int getAndroidVersion() {
return Build.VERSION.SDK_INT;
}
/**
* 检查是否为Android 10及以上版本
* @return true 表示支持
*/
public static boolean isAndroid10OrAbove() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
}
}

View File

@@ -135,6 +135,11 @@ public class GuideActivity extends BaseActivity<GuideActivityLayoutBinding, Logi
public void loginBySmsCodeSuccess(LoginEntity entity) { public void loginBySmsCodeSuccess(LoginEntity entity) {
} }
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
}
class MyAdapter extends PagerAdapter { class MyAdapter extends PagerAdapter {
@Override @Override
public int getCount() { public int getCount() {

View File

@@ -10,6 +10,8 @@ import androidx.fragment.app.Fragment;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.base.BaseFragment; import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.databinding.HistoryFragmentLayoutBinding; import com.ckkj.water.databinding.HistoryFragmentLayoutBinding;
import com.ckkj.water.history.entity.WaterStatisticsEntity;
import com.ckkj.water.history.entity.WateringRecord;
import com.ckkj.water.history.mvp.HistoryContract; import com.ckkj.water.history.mvp.HistoryContract;
import com.ckkj.water.history.mvp.HistoryPresenter; import com.ckkj.water.history.mvp.HistoryPresenter;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
@@ -97,4 +99,19 @@ public class HistoryFragment extends BaseFragment<HistoryFragmentLayoutBinding,
public void logOut(BaseBean bean) { public void logOut(BaseBean bean) {
} }
@Override
public void getHistoryListSuccess(List<WateringRecord> msg, int total) {
}
@Override
public void deleteHistorySuccess(BaseBean msg, int position) {
}
@Override
public void getHistoryStatisticsSuccess(WaterStatisticsEntity entity) {
}
} }

View File

@@ -4,25 +4,56 @@ import android.os.Bundle;
import com.ckkj.water.base.BaseFragment; import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.databinding.WaterCountFragmentLayoutBinding; import com.ckkj.water.databinding.WaterCountFragmentLayoutBinding;
import com.ckkj.water.history.entity.WaterStatisticsEntity;
import com.ckkj.water.history.entity.WateringRecord;
import com.ckkj.water.history.mvp.HistoryContract;
import com.ckkj.water.history.mvp.HistoryImpl;
import com.ckkj.water.history.mvp.HistoryPresenter;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.plan.mvp.WaterPlanContract; import com.ckkj.water.plan.mvp.WaterPlanContract;
import com.ckkj.water.plan.mvp.WaterPlanImpl;
import com.ckkj.water.plan.mvp.WaterPlanPresenter; import com.ckkj.water.plan.mvp.WaterPlanPresenter;
import com.ckkj.water.utils.show.ToastUtil;
import java.util.List;
/** /**
* @author fengxiaoyang * @author fengxiaoyang
* @date 2026/5/16 * @date 2026/5/16
* @description TODO: 描述该类的作用 * @description TODO: 统计界面
*/ */
public class StatisticFragment extends BaseFragment<WaterCountFragmentLayoutBinding, WaterPlanPresenter> public class StatisticFragment extends BaseFragment<WaterCountFragmentLayoutBinding, HistoryPresenter>
implements WaterPlanContract.WaterPlanView { implements HistoryContract.HistoryView {
@Override
protected void onResumeInitData() {
super.onResumeInitData();
showLoadingDialog();
mPresenter.getWaterStatistic();
}
@Override @Override
public void initData(Bundle state) { public void initData(Bundle state) {
} }
@Override @Override
public WaterPlanPresenter createPresenter() { public void getHistoryStatisticsSuccess(WaterStatisticsEntity entity) {
return null; hideDialogLoading();
viewBinding.tvTotalValue.setText(entity.getCount()+"");
viewBinding.tvThisWeekValue.setText(entity.getWeekCount()+"");
viewBinding.tvThisMonthValue.setText(entity.getMonCount()+"");
viewBinding.tvPlanValue.setText(entity.getSchedule()+"");
viewBinding.tvManuallyValue.setText(entity.getManualNum()+"");
viewBinding.tvTotalDurationValue.setText(entity.getAllTime()+"");
// viewBinding.tvTotalValue.setText(entity.getCount()+"");
}
@Override
public HistoryPresenter createPresenter() {
return new HistoryPresenter(new HistoryImpl());
} }
@Override @Override
@@ -32,11 +63,24 @@ public class StatisticFragment extends BaseFragment<WaterCountFragmentLayoutBind
@Override @Override
public void showError(String message) { public void showError(String message) {
hideDialogLoading();
ToastUtil.showShort(mContext,message);
} }
@Override @Override
public void logOut(BaseBean bean) { public void logOut(BaseBean bean) {
} }
@Override
public void getHistoryListSuccess(List<WateringRecord> msg, int total) {
}
@Override
public void deleteHistorySuccess(BaseBean msg, int position) {
}
} }

View File

@@ -8,10 +8,13 @@ import com.ckkj.water.R;
import com.ckkj.water.base.BaseFragment; import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.custom.CustomTimeFilterPopupView; import com.ckkj.water.custom.CustomTimeFilterPopupView;
import com.ckkj.water.custom.CustomTypeFilterPopupView; import com.ckkj.water.custom.CustomTypeFilterPopupView;
import com.ckkj.water.custom.view.CustomRefreshHeader;
import com.ckkj.water.databinding.TabHistoryFragmentLayoutBinding; import com.ckkj.water.databinding.TabHistoryFragmentLayoutBinding;
import com.ckkj.water.history.adapter.WateringHistoryAdapter; import com.ckkj.water.history.adapter.WateringHistoryAdapter;
import com.ckkj.water.history.entity.WaterStatisticsEntity;
import com.ckkj.water.history.entity.WateringRecord; import com.ckkj.water.history.entity.WateringRecord;
import com.ckkj.water.history.mvp.HistoryContract; import com.ckkj.water.history.mvp.HistoryContract;
import com.ckkj.water.history.mvp.HistoryImpl;
import com.ckkj.water.history.mvp.HistoryPresenter; import com.ckkj.water.history.mvp.HistoryPresenter;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity; import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
@@ -21,6 +24,8 @@ import com.google.gson.reflect.TypeToken;
import com.lxj.xpopup.XPopup; import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.core.BasePopupView; import com.lxj.xpopup.core.BasePopupView;
import com.lxj.xpopup.interfaces.SimpleCallback; import com.lxj.xpopup.interfaces.SimpleCallback;
import com.scwang.smart.refresh.footer.ClassicsFooter;
import com.scwang.smart.refresh.layout.api.RefreshHeader;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
@@ -34,16 +39,43 @@ import java.util.List;
public class TabHistoryFragment extends BaseFragment<TabHistoryFragmentLayoutBinding, HistoryPresenter> public class TabHistoryFragment extends BaseFragment<TabHistoryFragmentLayoutBinding, HistoryPresenter>
implements HistoryContract.HistoryView { implements HistoryContract.HistoryView {
List<WateringRecord> recordList = new ArrayList<>(); private List<WateringRecord> recordList = new ArrayList<>();
private WateringHistoryAdapter mAdapter; private WateringHistoryAdapter mAdapter;
private int mCurrentPage = 1;
private String mFilterStartTime = "";
private String mFilterEndTime = "";
private int mFilterType = -1; //0-排程 1-手动
@Override
protected void onResumeInitData() {
super.onResumeInitData();
showLoadingDialog();
getWaterHistoryList();
}
@Override @Override
public void initData(Bundle state) { public void initData(Bundle state) {
String jsonContent = getString(R.string.watering_device_list_json);
Type type = new TypeToken<List<WateringRecord>>() {}.getType();
recordList = new Gson().fromJson(jsonContent, type);
mAdapter = new WateringHistoryAdapter(mContext,R.layout.tab_history_item_layout,recordList); mAdapter = new WateringHistoryAdapter(mContext,R.layout.tab_history_item_layout,recordList);
viewBinding.rvHisttory.setAdapter(mAdapter); viewBinding.rvHisttory.setAdapter(mAdapter);
initListener(); initListener();
RefreshHeader header = new CustomRefreshHeader(mContext);
viewBinding.refresh.setRefreshHeader(header);
viewBinding.refresh.setRefreshFooter(new ClassicsFooter(mContext));
viewBinding.refresh.setOnRefreshListener(layout -> {
mCurrentPage = 1;
viewBinding.refresh.setNoMoreData(false);
getWaterHistoryList();
});
viewBinding.refresh.setOnLoadMoreListener(layout -> {
mCurrentPage++;
getWaterHistoryList();
});
}
private void getWaterHistoryList(){
mPresenter.getWaterHistoryList(mCurrentPage,mFilterStartTime,mFilterEndTime,mFilterType);
} }
private void initListener() { private void initListener() {
@@ -63,7 +95,8 @@ public class TabHistoryFragment extends BaseFragment<TabHistoryFragmentLayoutBin
@Override @Override
public void onConfirmClick() { public void onConfirmClick() {
mAdapter.remove(position); showLoadingDialog();
mPresenter.deleteWaterHistory(recordList.get(position).getId(),position);
} }
}); });
break; break;
@@ -100,7 +133,9 @@ public class TabHistoryFragment extends BaseFragment<TabHistoryFragmentLayoutBin
.asCustom(new CustomTimeFilterPopupView(getContext(), new CustomTimeFilterPopupView.OnClickListener() { .asCustom(new CustomTimeFilterPopupView(getContext(), new CustomTimeFilterPopupView.OnClickListener() {
@Override @Override
public void callBack(String startTime, String endTime) { public void callBack(String startTime, String endTime) {
ToastUtil.showShort(mContext,startTime + "---" + endTime); mFilterStartTime = startTime;
mFilterEndTime = endTime;
getWaterHistoryList();
} }
})); }));
popupView.show(); popupView.show();
@@ -128,7 +163,13 @@ public class TabHistoryFragment extends BaseFragment<TabHistoryFragmentLayoutBin
.asCustom(new CustomTypeFilterPopupView(getContext(), new CustomTypeFilterPopupView.OnClickListener() { .asCustom(new CustomTypeFilterPopupView(getContext(), new CustomTypeFilterPopupView.OnClickListener() {
@Override @Override
public void callBack(boolean mSelManual, boolean mSelAuto) { public void callBack(boolean mSelManual, boolean mSelAuto) {
if(mSelManual){
mFilterType = 1;
}
if(mSelAuto){
mFilterType = 0;
}
getWaterHistoryList();
} }
})); }));
typePopupView.show(); typePopupView.show();
@@ -137,9 +178,66 @@ public class TabHistoryFragment extends BaseFragment<TabHistoryFragmentLayoutBin
} }
} }
/**
* 获取浇水记录成功
* @param list
* @param total
*/
@Override
public void getHistoryListSuccess(List<WateringRecord> list, int total) {
hideDialogLoading();
List<WateringRecord> pageList = list == null ? new ArrayList<>() : list;
if (mCurrentPage == 1) {
viewBinding.refresh.finishRefresh(300);
recordList.clear(); // 只在刷新时清除
recordList = pageList;
} else {
viewBinding.refresh.finishLoadMore(300);
recordList.addAll(pageList);
}
mAdapter.setNewData(recordList);
// 4. 判断是否还有更多数据
if (mAdapter.getItemCount() >= total || pageList.size() == 0) {
// 使用 post 延迟调用,避免内部状态冲突导致的循环调用
viewBinding.refresh.postDelayed(() -> viewBinding.refresh.setNoMoreData(true), 300);
viewBinding.relNoMore.setVisibility(View.VISIBLE); // 自定义底部提示"暂无更多数据"
} else {
viewBinding.refresh.setNoMoreData(false);
viewBinding.relNoMore.setVisibility(View.GONE);
}
// 5. 控制空布局和内容显示
if (mAdapter.getItemCount() != 0) {
viewBinding.refresh.setVisibility(View.VISIBLE);
viewBinding.relNoresult.setVisibility(View.GONE);
} else {
viewBinding.refresh.setVisibility(View.GONE);
viewBinding.relNoresult.setVisibility(View.VISIBLE);
}
}
/**
* 删除历史记录成功
* @param bean
* @param position
*/
@Override
public void deleteHistorySuccess(BaseBean bean, int position) {
hideDialogLoading();
recordList.remove(position);
mAdapter.notifyItemRemoved(position);
}
@Override
public void getHistoryStatisticsSuccess(WaterStatisticsEntity entity) {
}
@Override @Override
public HistoryPresenter createPresenter() { public HistoryPresenter createPresenter() {
return null; return new HistoryPresenter(new HistoryImpl());
} }
@Override @Override
@@ -149,11 +247,14 @@ public class TabHistoryFragment extends BaseFragment<TabHistoryFragmentLayoutBin
@Override @Override
public void showError(String message) { public void showError(String message) {
hideDialogLoading();
ToastUtil.showShort(mContext,message);
} }
@Override @Override
public void logOut(BaseBean bean) { public void logOut(BaseBean bean) {
} }
} }

View File

@@ -8,6 +8,7 @@ import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder; import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.history.entity.WateringRecord; import com.ckkj.water.history.entity.WateringRecord;
import com.ckkj.water.utils.time.ZYTimeUtils;
import java.util.List; import java.util.List;
@@ -26,11 +27,12 @@ public class WateringHistoryAdapter extends BaseQuickAdapter<WateringRecord, Bas
@Override @Override
protected void convert(BaseViewHolder helper, WateringRecord item) { protected void convert(BaseViewHolder helper, WateringRecord item) {
helper.setText(R.id.tv_device_name,item.getDeviceName()); helper.setText(R.id.tv_device_name,item.getDeviceName());
helper.setText(R.id.tv_device_serial,item.getDeviceCode()); helper.setText(R.id.tv_device_serial,item.getDeviceNo());
helper.setText(R.id.tv_plan_time,mContext.getString(R.string.history_watering_adapter_time) helper.setText(R.id.tv_plan_time,mContext.getString(R.string.history_watering_adapter_time)
+ ":" + item.getStartTime() + "-" + item.getEndTime()); + ":" + ZYTimeUtils.timeWithoutMillis(item.getStartTime())
+ "-" + ZYTimeUtils.timeWithoutMillis(item.getEndTime()));
helper.setText(R.id.tv_plan_duration,mContext.getString(R.string.device_work_times_title) helper.setText(R.id.tv_plan_duration,mContext.getString(R.string.device_work_times_title)
+ ":" + item.getDuration()); + ":" + item.getDurationMin() + "min");
helper.setText(R.id.tv_plan_type,mContext.getString(R.string.tab_filter_type) helper.setText(R.id.tv_plan_type,mContext.getString(R.string.tab_filter_type)
+ ":" + item.getTriggerType()); + ":" + item.getTriggerType());
helper.addOnClickListener(R.id.img_delete); helper.addOnClickListener(R.id.img_delete);

View File

@@ -0,0 +1,34 @@
package com.ckkj.water.history.entity;
import java.io.Serializable;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author fengxiaoyang
* @date 2026/6/2
* @description 历史记录数据统计
*/
@NoArgsConstructor
@Data
public class WaterStatisticsEntity implements Serializable {
/**
* schedule : 0
* manualNum : 2
* averageTime : 2
* count : 2
* weekCount : 1
* monCount : 1
* allTime : 5
*/
private int schedule;//排程次数
private int manualNum;//手动浇水次数
private int averageTime;//平均浇水时长
private int count;//总次数
private int weekCount;//本周浇水次数
private int monCount;//本月浇水次数
private int allTime;//总浇水时长
}

View File

@@ -8,10 +8,10 @@ import lombok.NoArgsConstructor;
/** /**
* @author fengxiaoyang * @author fengxiaoyang
* @date 2026/5/15 * @date 2026/5/15
* @description TODO: 描述该类的作用 * @description 浇水历史记录
*/ */
@NoArgsConstructor
@Data @Data
@NoArgsConstructor
public class WateringRecord implements Serializable { public class WateringRecord implements Serializable {
/** /**
@@ -29,4 +29,25 @@ public class WateringRecord implements Serializable {
private String endTime; private String endTime;
private String duration; private String duration;
private String triggerType; private String triggerType;
/**
* id : 2060156839441596420
* userId : 2056543507514097665
* deviceId : 2056641699765178369
* scheduleId : 1
* durationMin : 2
* zones : null
* createTime : 2026-06-09 09:30:41
*/
private String id;
private String userId;
private String deviceNo;
private String deviceId;
private int scheduleId;
private String durationMin;
private Object zones;
private String createTime;
} }

View File

@@ -1,16 +1,34 @@
package com.ckkj.water.history.mvp; package com.ckkj.water.history.mvp;
import com.ckkj.water.base.IView; import com.ckkj.water.base.IView;
import com.ckkj.water.history.entity.WaterStatisticsEntity;
import com.ckkj.water.history.entity.WateringRecord;
import com.ckkj.water.network.BaseBean;
import java.util.List;
import java.util.Map;
public class HistoryContract { public class HistoryContract {
public interface CallBack<T> { public interface CallBack<T> {
void success(T msg); void success(T msg, int total);
void fail(String msg); void fail(String msg);
} }
public interface DataModel{ public interface DataModel{
//历史列表
void getHistoryList(Map<String, String> map, CallBack callBack);
//删除某一历史记录
void deleteHistory(String logID, CallBack callBack);
//浇水的数据统计
void getWateringStatistics(Map<String, String> map, CallBack callBack);
} }
public interface HistoryView extends IView { public interface HistoryView extends IView {
//历史记录成功
void getHistoryListSuccess(List<WateringRecord> msg, int total);
//删除历史记录成功
void deleteHistorySuccess(BaseBean msg, int position);
//数据统计成功
void getHistoryStatisticsSuccess(WaterStatisticsEntity entity);
} }
} }

View File

@@ -1,5 +1,128 @@
package com.ckkj.water.history.mvp; package com.ckkj.water.history.mvp;
import com.ckkj.water.base.entity.MineUserInfoBean;
import com.ckkj.water.history.entity.WaterStatisticsEntity;
import com.ckkj.water.history.entity.WateringRecord;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.network.NetWorkManager;
import java.util.List;
import java.util.Map;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
public class HistoryImpl implements HistoryContract.DataModel{ public class HistoryImpl implements HistoryContract.DataModel{
/**
* 查询浇水历史
* @param map
* @param callBack
*/
@Override
public void getHistoryList(Map<String, String> map, HistoryContract.CallBack callBack) {
NetWorkManager.getRequest().waterLogList(NetWorkManager.getToken(), map)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<List<WateringRecord>>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<List<WateringRecord>> bean) {
if (bean.getCode() == 200) {
callBack.success(bean.getRows(),bean.getTotal());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
}
/**
* 删除某一历史记录
* @param logID
* @param callBack
*/
@Override
public void deleteHistory(String logID, HistoryContract.CallBack callBack) {
try {
NetWorkManager.getRequest().deleteWaterLog(NetWorkManager.getToken(), logID)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean bean) {
if (bean.getCode() == 200) {
callBack.success(bean,0);
} else {
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 浇水的数据统计
* @param map
* @param callBack
*/
@Override
public void getWateringStatistics(Map<String, String> map, HistoryContract.CallBack callBack) {
NetWorkManager.getRequest().getDataStatistics(NetWorkManager.getToken())
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<WaterStatisticsEntity>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<WaterStatisticsEntity> bean) {
if (bean.getCode() == 200) {
callBack.success(bean.getData(),0);
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
}
} }

View File

@@ -1,6 +1,15 @@
package com.ckkj.water.history.mvp; package com.ckkj.water.history.mvp;
import android.text.TextUtils;
import com.ckkj.water.base.BasePresenter; import com.ckkj.water.base.BasePresenter;
import com.ckkj.water.history.entity.WaterStatisticsEntity;
import com.ckkj.water.history.entity.WateringRecord;
import com.ckkj.water.network.BaseBean;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HistoryPresenter extends BasePresenter<HistoryContract.HistoryView> { public class HistoryPresenter extends BasePresenter<HistoryContract.HistoryView> {
private HistoryImpl impl; private HistoryImpl impl;
@@ -8,4 +17,88 @@ public class HistoryPresenter extends BasePresenter<HistoryContract.HistoryView>
public HistoryPresenter(HistoryImpl impl) { public HistoryPresenter(HistoryImpl impl) {
this.impl = impl; this.impl = impl;
} }
/**
* 查询历史列表
* @param mCurrentPage
* @param mFilterStartTime
* @param mFilterEndTime
* @param mFilterType
*/
public void getWaterHistoryList(int mCurrentPage, String mFilterStartTime, String mFilterEndTime, int mFilterType) {
Map<String,String> map = new HashMap<>();
map.put("pageNum",mCurrentPage+"");
if(!TextUtils.isEmpty(mFilterStartTime)){
// map.put("beginTime",mFilterStartTime);
map.put("param[beginTime]", mFilterStartTime);
}
if(!TextUtils.isEmpty(mFilterStartTime)){
// map.put("endTime",mFilterEndTime);
map.put("param[endTime]", mFilterEndTime);
}
if(mFilterType != -1){
map.put("triggerType",mFilterType+"");
}
impl.getHistoryList(map, new HistoryContract.CallBack<List<WateringRecord>>() {
@Override
public void success(List<WateringRecord> list,int total) {
if(HistoryPresenter.this.getView() != null){
HistoryPresenter.this.getView().getHistoryListSuccess(list,total);
}
}
@Override
public void fail(String msg) {
if(HistoryPresenter.this.getView() != null){
HistoryPresenter.this.getView().showMessage(msg);
}
}
});
}
/**
* 删除历史记录
* @param id
* @param position
*/
public void deleteWaterHistory(String id, int position) {
impl.deleteHistory(id, new HistoryContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean, int total) {
if(HistoryPresenter.this.getView() != null){
HistoryPresenter.this.getView().deleteHistorySuccess(bean,position);
}
}
@Override
public void fail(String msg) {
if(HistoryPresenter.this.getView() != null){
HistoryPresenter.this.getView().showMessage(msg);
}
}
});
}
/**
* 获取浇水统计
*/
public void getWaterStatistic() {
impl.getWateringStatistics(null, new HistoryContract.CallBack<WaterStatisticsEntity>() {
@Override
public void success(WaterStatisticsEntity entity, int total) {
if(HistoryPresenter.this.getView() != null){
HistoryPresenter.this.getView().getHistoryStatisticsSuccess(entity);
}
}
@Override
public void fail(String msg) {
if(HistoryPresenter.this.getView() != null){
HistoryPresenter.this.getView().showMessage(msg);
}
}
});
}
} }

View File

@@ -3,6 +3,7 @@ package com.ckkj.water.index;
import android.Manifest; import android.Manifest;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -14,14 +15,17 @@ import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.custom.view.CustomRefreshHeader; import com.ckkj.water.custom.view.CustomRefreshHeader;
import com.ckkj.water.databinding.IndexFragmentLayoutBinding; import com.ckkj.water.databinding.IndexFragmentLayoutBinding;
import com.ckkj.water.device.AddDeviceActivity; import com.ckkj.water.device.AddDeviceActivity;
import com.ckkj.water.device.AddDeviceActivity_copy;
import com.ckkj.water.device.DeviceControlActivity; import com.ckkj.water.device.DeviceControlActivity;
import com.ckkj.water.history.entity.WateringRecord;
import com.ckkj.water.index.adapter.DeviceAdapter; import com.ckkj.water.index.adapter.DeviceAdapter;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.index.mvp.IndexContract; import com.ckkj.water.index.mvp.IndexContract;
import com.ckkj.water.index.mvp.IndexImpl; import com.ckkj.water.index.mvp.IndexImpl;
import com.ckkj.water.index.mvp.IndexPresenter; import com.ckkj.water.index.mvp.IndexPresenter;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.permission.PermissionActivity; import com.ckkj.water.permission.PermissionActivity;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.utils.show.ToastUtil; import com.ckkj.water.utils.show.ToastUtil;
import com.maning.mlkitscanner.scan.MNScanManager; import com.maning.mlkitscanner.scan.MNScanManager;
import com.maning.mlkitscanner.scan.callback.act.MNScanCallback; import com.maning.mlkitscanner.scan.callback.act.MNScanCallback;
@@ -37,7 +41,7 @@ public class IndexFragment extends BaseFragment<IndexFragmentLayoutBinding, Inde
implements IndexContract.IndexView , EasyPermissions.PermissionCallbacks{ implements IndexContract.IndexView , EasyPermissions.PermissionCallbacks{
private DeviceAdapter deviceAdapter; private DeviceAdapter deviceAdapter;
private List<IndexDeviceEntity> devList = new ArrayList<>(); private List<WaterDeviceEntity> devList = new ArrayList<>();
private int mCurrentPage = 1; private int mCurrentPage = 1;
@Override @Override
@@ -110,7 +114,7 @@ public class IndexFragment extends BaseFragment<IndexFragmentLayoutBinding, Inde
if(!hasPermission){ if(!hasPermission){
goTo(mContext, PermissionActivity.class,null); goTo(mContext, PermissionActivity.class,null);
}else{ }else{
goTo(mContext, AddDeviceActivity.class,null); goTo(mContext, AddDeviceActivity_copy.class,null);
} }
break; break;
} }
@@ -153,24 +157,26 @@ public class IndexFragment extends BaseFragment<IndexFragmentLayoutBinding, Inde
* 获取设备列表成功 * 获取设备列表成功
*/ */
@Override @Override
public void getDeviceListSuccess(List<IndexDeviceEntity> list,int total) { public void getDeviceListSuccess(List<WaterDeviceEntity> list, int total) {
hideDialogLoading(); hideDialogLoading();
viewBinding.refresh.finishRefresh(300); List<WaterDeviceEntity> pageList = list == null ? new ArrayList<>() : list;
viewBinding.refresh.finishLoadMore(300);
if (mCurrentPage == 1) { if (mCurrentPage == 1) {
viewBinding.refresh.finishRefresh(300);
devList.clear(); // 只在刷新时清除 devList.clear(); // 只在刷新时清除
devList = list; devList = pageList;
} else { } else {
devList.addAll(list); viewBinding.refresh.finishLoadMore(300);
devList.addAll(pageList);
} }
deviceAdapter.setNewData(devList); deviceAdapter.setNewData(devList);
// 4. 判断是否还有更多数据 // 4. 判断是否还有更多数据
if (total == deviceAdapter.getItemCount() || list == null || list.size() == 0) { if (deviceAdapter.getItemCount() >= total || pageList.size() == 0) {
// ✅ 告诉 SmartRefreshLayout 没有更多数据了 // 使用 post 延迟调用,避免内部状态冲突导致的循环调用
viewBinding.refresh.setNoMoreData(true); viewBinding.refresh.postDelayed(() -> viewBinding.refresh.setNoMoreData(true), 300);
viewBinding.relNoMore.setVisibility(View.VISIBLE); // 自定义底部提示暂无更多数据 viewBinding.relNoMore.setVisibility(View.VISIBLE); // 自定义底部提示"暂无更多数据"
} else { } else {
viewBinding.refresh.setNoMoreData(false); // 重置状态 viewBinding.refresh.setNoMoreData(false);
viewBinding.relNoMore.setVisibility(View.GONE); viewBinding.relNoMore.setVisibility(View.GONE);
} }

View File

@@ -1,36 +1,45 @@
package com.ckkj.water.index.adapter; package com.ckkj.water.index.adapter;
import android.content.Context; import android.content.Context;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder; import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.utils.manager.PowerIconManage;
import com.esafirm.imagepicker.model.Image;
import java.util.List; import java.util.List;
public class DeviceAdapter extends BaseQuickAdapter<IndexDeviceEntity, BaseViewHolder> { public class DeviceAdapter extends BaseQuickAdapter<WaterDeviceEntity, BaseViewHolder> {
public DeviceAdapter(Context context, int layoutResId, @Nullable List<IndexDeviceEntity> data) { public DeviceAdapter(Context context, int layoutResId, @Nullable List<WaterDeviceEntity> data) {
super(layoutResId, data); super(layoutResId, data);
this.mContext = context; this.mContext = context;
this.mData = data; this.mData = data;
} }
@Override @Override
protected void convert(BaseViewHolder holder, IndexDeviceEntity item) { protected void convert(BaseViewHolder holder, WaterDeviceEntity item) {
ImageView imgPower = holder.getView(R.id.img_battery);
View viewStatus = holder.getView(R.id.view_status_dot);
holder.setText(R.id.tv_device_name,item.getDeviceName()); holder.setText(R.id.tv_device_name,item.getDeviceName());
holder.setText(R.id.tv_device_serial,item.getDeviceSn()); holder.setText(R.id.tv_device_serial,item.getDeviceSn());
holder.setText(R.id.tv_device_status,"工作中"); holder.setText(R.id.tv_device_status,item.getWorkStatus().equals("0") ?
holder.setText(R.id.tv_battery_level,"80"); mContext.getString(R.string.device_status_not_working) :
mContext.getString(R.string.device_status_working));
holder.setTextColor(R.id.tv_device_status,item.getWorkStatus().equals("0") ?
mContext.getResources().getColor(R.color.color_999999) :
mContext.getResources().getColor(R.color.color_24B326));
viewStatus.setBackground(item.getWorkStatus().equals("0") ?
mContext.getResources().getDrawable(R.drawable.shape_status_dot_999999)
: mContext.getResources().getDrawable(R.drawable.shape_status_dot_green));
holder.setText(R.id.tv_battery_level,item.getPowerLevel());
imgPower.setImageResource(PowerIconManage.getInstance().getPowerIcon(Integer.parseInt(item.getPowerLevel())));
} }

View File

@@ -1,13 +1,14 @@
package com.ckkj.water.index.entity; package com.ckkj.water.index.entity;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data @Data
public class IndexDeviceEntity implements Serializable { @NoArgsConstructor
public class WaterDeviceEntity implements Serializable {
/** /**
* id : 2056638783822123010 * id : 2056638783822123010
@@ -33,7 +34,29 @@ public class IndexDeviceEntity implements Serializable {
private String deviceName; private String deviceName;
private Object deviceImg; private Object deviceImg;
private String status; private String status;
private Object powerLevel; private String workStatus;
private String powerLevel;
private Object powerLevelUpdatatime;
private String wifiName;
private String wifiPassword;
private String deviceEm;
private String deviceSn;
private String fwVer;
private String macAddress;
private Object expirationTime;
private List<DeviceListBean> deviceList;
@NoArgsConstructor
@Data
public static class DeviceListBean implements Serializable{
private String id;
private String deviceNo;
private String userId;
private String deviceName;
private Object deviceImg;
private String status;
private String workStatus;
private String powerLevel;
private Object powerLevelUpdatatime; private Object powerLevelUpdatatime;
private String wifiName; private String wifiName;
private String wifiPassword; private String wifiPassword;
@@ -43,3 +66,4 @@ public class IndexDeviceEntity implements Serializable {
private String macAddress; private String macAddress;
private Object expirationTime; private Object expirationTime;
} }
}

View File

@@ -1,11 +1,7 @@
package com.ckkj.water.index.mvp; package com.ckkj.water.index.mvp;
import com.ckkj.water.base.IView; import com.ckkj.water.base.IView;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.login.entity.LoginEntity;
import com.ckkj.water.network.BaseBean;
import org.json.JSONObject;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -29,6 +25,6 @@ public class IndexContract {
} }
public interface IndexView extends IView{ public interface IndexView extends IView{
void getDeviceListSuccess(List<IndexDeviceEntity> list,int total); void getDeviceListSuccess(List<WaterDeviceEntity> list, int total);
} }
} }

View File

@@ -1,11 +1,9 @@
package com.ckkj.water.index.mvp; package com.ckkj.water.index.mvp;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.network.NetWorkManager; import com.ckkj.water.network.NetWorkManager;
import org.json.JSONObject;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -28,13 +26,13 @@ public class IndexImpl implements IndexContract.DataModel{
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<List<IndexDeviceEntity>>>() { .subscribe(new Observer<BaseBean<List<WaterDeviceEntity>>>() {
@Override @Override
public void onSubscribe(@NonNull Disposable d) { public void onSubscribe(@NonNull Disposable d) {
} }
@Override @Override
public void onNext(@NonNull BaseBean<List<IndexDeviceEntity>> bean) { public void onNext(@NonNull BaseBean<List<WaterDeviceEntity>> bean) {
if (bean.getCode() == 200) { if (bean.getCode() == 200) {
callBack.success(bean.getRows(),bean.getTotal()); callBack.success(bean.getRows(),bean.getTotal());
} }

View File

@@ -1,7 +1,7 @@
package com.ckkj.water.index.mvp; package com.ckkj.water.index.mvp;
import com.ckkj.water.base.BasePresenter; import com.ckkj.water.base.BasePresenter;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -18,10 +18,10 @@ public class IndexPresenter extends BasePresenter<IndexContract.IndexView>{
* 查询设备列表 * 查询设备列表
*/ */
public void getDevicesList(int mCurrentPage) { public void getDevicesList(int mCurrentPage) {
mImpl.getDeviceList(new HashMap<>(), new IndexContract.CallBack<List<IndexDeviceEntity>>() { mImpl.getDeviceList(new HashMap<>(), new IndexContract.CallBack<List<WaterDeviceEntity>>() {
@Override @Override
public void success(List<IndexDeviceEntity> list, int total) { public void success(List<WaterDeviceEntity> list, int total) {
if(IndexPresenter.this.getView() != null){ if(IndexPresenter.this.getView() != null){
IndexPresenter.this.getView().getDeviceListSuccess(list,total); IndexPresenter.this.getView().getDeviceListSuccess(list,total);
} }

View File

@@ -71,11 +71,44 @@ public class ForgetPasswordActivity extends BaseActivity<RegisterLayoutBinding,
ToastUtil.showShort(mContext, getString(R.string.login_error_phone_invalid)); ToastUtil.showShort(mContext, getString(R.string.login_error_phone_invalid));
return; return;
} }
cdTimer.start(); mPresenter.getPhoneCode(viewBinding.etAccount.getText().toString(),"");
// cdTimer.start();
break; break;
case R.id.tv_commit: case R.id.tv_commit:
goTo(mContext, RegisterSuccessActivity.class,null); if (TextUtils.isEmpty(viewBinding.etAccount.getText().toString())) {
ToastUtil.showShort(mContext, getString(R.string.login_error_phone_empty));
return;
}
if (!PhoneNumberUtils.checkPhoneNum(viewBinding.etAccount.getText().toString().trim()) &&
!PhoneNumberUtils.checkEmail(viewBinding.etAccount.getText().toString().trim())) {
ToastUtil.showShort(mContext, getString(R.string.login_error_phone_invalid));
return;
}
if (TextUtils.isEmpty(viewBinding.etVerfiCode.getText().toString())) {
ToastUtil.showShort(mContext, getString(R.string.login_error_code_empty));
return;
}
if (TextUtils.isEmpty(viewBinding.etInputPsd.getText().toString())) {
ToastUtil.showShort(mContext, getString(R.string.login_error_psd_empty));
return;
}
if (TextUtils.isEmpty(viewBinding.etInputPsdAgin.getText().toString())) {
ToastUtil.showShort(mContext, getString(R.string.login_error_psd_agin_empty));
return;
}
if(!(viewBinding.etInputPsd.getText().toString()).equals(
viewBinding.etInputPsdAgin.getText().toString())){
ToastUtil.showShort(mContext, getString(R.string.hint_input_psd_not_match));
return;
}
showLoadingDialog();
mPresenter.updatePsdByVerifyCode(viewBinding.etAccount.getText().toString(),
viewBinding.etVerfiCode.getText().toString(),
viewBinding.etInputPsd.getText().toString());
break; break;
} }
} }
@@ -101,6 +134,16 @@ public class ForgetPasswordActivity extends BaseActivity<RegisterLayoutBinding,
} }
}; };
/**
* 修改密码成功
* @param bean
*/
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
hideDialogLoading();
ToastUtil.showShort(mContext,getString(R.string.hint_update_psd_success));
finish();
}
@Override @Override
public void registerSuccess(BaseBean bean) { public void registerSuccess(BaseBean bean) {
@@ -117,6 +160,7 @@ public class ForgetPasswordActivity extends BaseActivity<RegisterLayoutBinding,
} }
@Override @Override
public void showError(String message) { public void showError(String message) {
ToastUtil.showShort(mContext,message); ToastUtil.showShort(mContext,message);

View File

@@ -221,6 +221,11 @@ public class LoginActivity extends BaseActivity<LoginLayoutBinding, LoginPresent
R.layout.select_language_item R.layout.select_language_item
).show(); ).show();
break; break;
case R.id.tv_reset_psd ://重置密码
goTo(mContext, ForgetPasswordActivity.class,null);
break;
// case R.id.checkbox_read: // case R.id.checkbox_read:
// if (mYinsiConfirm) { // if (mYinsiConfirm) {
// mYinsiConfirm = false; // mYinsiConfirm = false;
@@ -326,6 +331,11 @@ public class LoginActivity extends BaseActivity<LoginLayoutBinding, LoginPresent
}, 200); }, 200);
} }
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
}
@Override @Override
public int getLayoutResId(Bundle savedInstanceState) { public int getLayoutResId(Bundle savedInstanceState) {
return 0; return 0;

View File

@@ -85,11 +85,7 @@ public class RegisterActivity extends BaseActivity<RegisterLayoutBinding, LoginP
return; return;
} }
if (TextUtils.isEmpty(viewBinding.etVerfiCode.getText().toString())) { if (TextUtils.isEmpty(viewBinding.etVerfiCode.getText().toString())) {
ToastUtil.showShort(mContext, getString(R.string.login_error_phone_empty)); ToastUtil.showShort(mContext, getString(R.string.login_error_code_empty));
return;
}
if (TextUtils.isEmpty(viewBinding.etVerfiCode.getText().toString())) {
ToastUtil.showShort(mContext, getString(R.string.login_error_phone_empty));
return; return;
} }
@@ -155,6 +151,15 @@ public class RegisterActivity extends BaseActivity<RegisterLayoutBinding, LoginP
} }
/**
* 修改密码成功
* @param bean
*/
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
hideDialogLoading();
}
@Override @Override
public void showError(String message) { public void showError(String message) {
hideDialogLoading(); hideDialogLoading();

View File

@@ -94,6 +94,11 @@ public class RegisterSuccessActivity extends BaseActivity<RegisterSuccessLayoutB
} }
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
}
@Override @Override
public void showError(String message) { public void showError(String message) {

View File

@@ -27,6 +27,10 @@ public class LoginContract {
void getPhoneCode(Map<String,Object> map, CallBack callBack); void getPhoneCode(Map<String,Object> map, CallBack callBack);
//手机验证码登录 //手机验证码登录
void loginBySmsCode(JSONObject json, CallBack callBack); void loginBySmsCode(JSONObject json, CallBack callBack);
//通过账户+验证码 修改密码
void updatePsdByVerifyCode(JSONObject json, CallBack callBack);
//退出登录
void logout(JSONObject json, CallBack callBack);
} }
public interface LoginView extends IView{ public interface LoginView extends IView{
@@ -35,5 +39,7 @@ public class LoginContract {
void getPhoneCodeSuccess(BaseBean bean); void getPhoneCodeSuccess(BaseBean bean);
//验证码登录成功 //验证码登录成功
void loginBySmsCodeSuccess(LoginEntity entity); void loginBySmsCodeSuccess(LoginEntity entity);
//通过验证码修改密码成功
void updateUserPasswordSuccess(BaseBean bean);
} }
} }

View File

@@ -105,6 +105,11 @@ public class LoginImpl implements LoginContract.DataModel {
} }
} }
/**
* 使用验证码登录
* @param json
* @param callBack
*/
@Override @Override
public void loginBySmsCode(JSONObject json, LoginContract.CallBack callBack) { public void loginBySmsCode(JSONObject json, LoginContract.CallBack callBack) {
try { try {
@@ -141,4 +146,84 @@ public class LoginImpl implements LoginContract.DataModel {
e.printStackTrace(); e.printStackTrace();
} }
} }
/**
* 通过验证码修改密码
* @param json
* @param callBack
*/
@Override
public void updatePsdByVerifyCode(JSONObject json, LoginContract.CallBack callBack) {
try {
NetWorkManager.getRequest().updatePasswordByVerifyCode(NetWorkManager.getToken(),NetWorkManager.toRequestBody(json))
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean bean) {
if (bean.getCode() == 200) {
callBack.success(bean);
} else {
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 退出登录
* @param json
* @param callBack
*/
@Override
public void logout(JSONObject json, LoginContract.CallBack callBack) {
try {
NetWorkManager.getRequest().logout(NetWorkManager.toRequestBody(json))
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean bean) {
if (bean.getCode() == 200) {
callBack.success(bean.getData());
} else {
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
} }

View File

@@ -3,6 +3,8 @@ package com.ckkj.water.login.mvp;
import com.ckkj.water.AppConfig; import com.ckkj.water.AppConfig;
import com.ckkj.water.base.BasePresenter; import com.ckkj.water.base.BasePresenter;
import com.ckkj.water.login.entity.LoginEntity; import com.ckkj.water.login.entity.LoginEntity;
import com.ckkj.water.mine.mvp.MineContract;
import com.ckkj.water.mine.mvp.MinePresenter;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import org.json.JSONException; import org.json.JSONException;
@@ -146,4 +148,35 @@ public class LoginPresenter extends BasePresenter<LoginContract.LoginView> {
} }
/**
* 通过验证码修改密码
* @param account
* @param code
* @param psd
*/
public void updatePsdByVerifyCode(String account, String code, String psd) {
try {
JSONObject json = new JSONObject();
json.put("userName", account);
json.put("code", code);
json.put("password", psd);
mImpl.updatePsdByVerifyCode(json, new LoginContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean) {
if(LoginPresenter.this.getView() != null){
LoginPresenter.this.getView().updateUserPasswordSuccess(bean);
}
}
@Override
public void fail(String msg) {
if(LoginPresenter.this.getView() != null){
LoginPresenter.this.getView().showError(msg);
}
}
});
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
} }

View File

@@ -102,4 +102,19 @@ public class AppThemActivity extends BaseActivity<AppThemeChangeLayoutBinding, M
public void getUserInfoSuccess(MineUserInfoBean bean) { public void getUserInfoSuccess(MineUserInfoBean bean) {
} }
@Override
public void updateUserInfoSuccess(BaseBean bean) {
}
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
}
@Override
public void logOutSuccess(BaseBean bean) {
}
} }

View File

@@ -136,4 +136,19 @@ public class ChangePhoneActivity extends BaseActivity<ChangePhoneActivityBinding
public void getUserInfoSuccess(MineUserInfoBean bean) { public void getUserInfoSuccess(MineUserInfoBean bean) {
} }
@Override
public void updateUserInfoSuccess(BaseBean bean) {
}
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
}
@Override
public void logOutSuccess(BaseBean bean) {
}
} }

View File

@@ -3,6 +3,7 @@ package com.ckkj.water.mine;
import static android.view.View.INVISIBLE; import static android.view.View.INVISIBLE;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils;
import android.view.View; import android.view.View;
import com.ckkj.water.AppConfig; import com.ckkj.water.AppConfig;
@@ -12,6 +13,7 @@ import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.base.entity.MineUserInfoBean; import com.ckkj.water.base.entity.MineUserInfoBean;
import com.ckkj.water.databinding.MineFragmentBinding; import com.ckkj.water.databinding.MineFragmentBinding;
import com.ckkj.water.databinding.MineFragmentLayoutBinding; import com.ckkj.water.databinding.MineFragmentLayoutBinding;
import com.ckkj.water.login.LoginActivity;
import com.ckkj.water.main.entity.CheckVersionEntity; import com.ckkj.water.main.entity.CheckVersionEntity;
import com.ckkj.water.mine.entity.MemberComboEntity; import com.ckkj.water.mine.entity.MemberComboEntity;
import com.ckkj.water.mine.mvp.MineContract; import com.ckkj.water.mine.mvp.MineContract;
@@ -19,6 +21,7 @@ import com.ckkj.water.mine.mvp.MineImpl;
import com.ckkj.water.mine.mvp.MinePresenter; import com.ckkj.water.mine.mvp.MinePresenter;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.utils.dataUtil.SharePreUtil; import com.ckkj.water.utils.dataUtil.SharePreUtil;
import com.ckkj.water.utils.manager.ActivityManager;
import com.ckkj.water.utils.manager.ThemeManager; import com.ckkj.water.utils.manager.ThemeManager;
import com.ckkj.water.utils.manager.WaterUserInfoManager; import com.ckkj.water.utils.manager.WaterUserInfoManager;
import com.ckkj.water.utils.show.ToastUtil; import com.ckkj.water.utils.show.ToastUtil;
@@ -29,6 +32,8 @@ import com.lxj.xpopup.interfaces.OnSelectListener;
import java.util.List; import java.util.List;
import de.greenrobot.event.EventBus;
/** /**
* @author fengxiaoyang * @author fengxiaoyang
* @date 2026/5/16 * @date 2026/5/16
@@ -36,6 +41,7 @@ import java.util.List;
*/ */
public class MineCenterFragment extends BaseFragment<MineFragmentLayoutBinding, MinePresenter> public class MineCenterFragment extends BaseFragment<MineFragmentLayoutBinding, MinePresenter>
implements MineContract.MineView { implements MineContract.MineView {
private MineUserInfoBean mUserBean;
@Override @Override
public void initData(Bundle state) { public void initData(Bundle state) {
ImmersionBar.with(mContext) ImmersionBar.with(mContext)
@@ -57,10 +63,11 @@ public class MineCenterFragment extends BaseFragment<MineFragmentLayoutBinding,
} }
private void initListener() { private void initListener() {
setClick(viewBinding.imgAvatar); setClick(viewBinding.linearInfo);
setClick(viewBinding.linearLanguage); setClick(viewBinding.linearLanguage);
setClick(viewBinding.linearPsdManage); setClick(viewBinding.linearPsdManage);
setClick(viewBinding.linearTheme); setClick(viewBinding.linearTheme);
setClick(viewBinding.btnDelete);
} }
private void setClick(View view) { private void setClick(View view) {
@@ -69,8 +76,10 @@ public class MineCenterFragment extends BaseFragment<MineFragmentLayoutBinding,
public void onClick(View v){ public void onClick(View v){
switch (v.getId()){ switch (v.getId()){
case R.id.img_avatar: case R.id.linear_info:
goTo(mContext, MineInfomationActivity.class,null); Bundle bundle = new Bundle();
bundle.putSerializable(ConstantUtil.USER_INFO_JSON_CONTENT,mUserBean);
goTo(mContext, MineInfomationActivity.class,bundle);
break; break;
case R.id.linear_theme: case R.id.linear_theme:
@@ -101,6 +110,26 @@ public class MineCenterFragment extends BaseFragment<MineFragmentLayoutBinding,
case R.id.linear_psd_manage: case R.id.linear_psd_manage:
goTo(mContext, PsdManageActivity.class,null); goTo(mContext, PsdManageActivity.class,null);
break; break;
case R.id.btn_delete:
showDialogtext(null,
false,
false,
getString(R.string.tip_text),
getString(R.string.logout_tips),
getString(R.string.cancel_text),
getString(R.string.confirm_text),
new OnDialogClick() {
@Override
public void onCancelClick() {
}
@Override
public void onConfirmClick() {
mPresenter.logout();
}
});
break;
} }
} }
@@ -114,9 +143,38 @@ public class MineCenterFragment extends BaseFragment<MineFragmentLayoutBinding,
String userInfoJson = gson.toJson(bean); String userInfoJson = gson.toJson(bean);
SharePreUtil.putString(ConstantUtil.SHARE_PRE_NAME,mContext,ConstantUtil.USER_INFO_JSON_CONTENT,userInfoJson); SharePreUtil.putString(ConstantUtil.SHARE_PRE_NAME,mContext,ConstantUtil.USER_INFO_JSON_CONTENT,userInfoJson);
WaterUserInfoManager.getInstance().setUserInfo(bean); WaterUserInfoManager.getInstance().setUserInfo(bean);
mUserBean = bean;
viewBinding.tvUserName.setText(bean.getUser().getNickName());
if(TextUtils.isEmpty(bean.getUser().getPhonenumber())){
viewBinding.tvUserAccount.setText(bean.getUser().getEmail());
}else{
viewBinding.tvUserAccount.setText(bean.getUser().getPhonenumber());
}
}
/**
* 退出登录
* @param bean
*/
@Override
public void logOutSuccess(BaseBean bean) {
WaterUserInfoManager.getInstance().clearUser(mContext);
ActivityManager.removeAllActivity();
goTo(mContext, LoginActivity.class,null);
}
@Override
public void updateUserInfoSuccess(BaseBean bean) {
} }
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
}
@Override @Override
public MinePresenter createPresenter() { public MinePresenter createPresenter() {
return new MinePresenter(new MineImpl()); return new MinePresenter(new MineImpl());

View File

@@ -266,4 +266,19 @@ public class MineFragment extends BaseFragment<MineFragmentBinding, MinePresente
public void getUserInfoSuccess(MineUserInfoBean bean) { public void getUserInfoSuccess(MineUserInfoBean bean) {
} }
@Override
public void updateUserInfoSuccess(BaseBean bean) {
}
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
}
@Override
public void logOutSuccess(BaseBean bean) {
}
} }

View File

@@ -3,12 +3,14 @@ package com.ckkj.water.mine;
import android.Manifest; import android.Manifest;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.ckkj.water.ConstantUtil;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity; import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.base.entity.MineUserInfoBean; import com.ckkj.water.base.entity.MineUserInfoBean;
@@ -40,6 +42,7 @@ import pub.devrel.easypermissions.EasyPermissions;
*/ */
public class MineInfomationActivity extends BaseActivity<MineInformationLayoutBinding, MinePresenter> public class MineInfomationActivity extends BaseActivity<MineInformationLayoutBinding, MinePresenter>
implements MineContract.MineView, EasyPermissions.PermissionCallbacks{ implements MineContract.MineView, EasyPermissions.PermissionCallbacks{
private MineUserInfoBean mUserBean;
@Override @Override
public MinePresenter createPresenter() { public MinePresenter createPresenter() {
return new MinePresenter(new MineImpl()); return new MinePresenter(new MineImpl());
@@ -48,7 +51,16 @@ public class MineInfomationActivity extends BaseActivity<MineInformationLayoutBi
@Override @Override
public void initData(Bundle savedInstanceState) { public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState); super.initData(savedInstanceState);
Bundle bundle = getIntent().getExtras();
if(bundle != null){
mUserBean = (MineUserInfoBean) bundle.getSerializable(ConstantUtil.USER_INFO_JSON_CONTENT);
viewBinding.tvNicknameValue.setText(mUserBean.getUser().getNickName());
if(TextUtils.isEmpty(mUserBean.getUser().getEmail())){
viewBinding.tvBindPhoneValue.setText(mUserBean.getUser().getPhonenumber());
}else{
viewBinding.tvBindPhoneValue.setText(mUserBean.getUser().getEmail());
}
}
ImmersionBar.with(this) ImmersionBar.with(this)
.statusBarColor(R.color.white) // 设置状态栏颜色 .statusBarColor(R.color.white) // 设置状态栏颜色
.statusBarDarkFont(true) // 设置状态栏字体为黑色 .statusBarDarkFont(true) // 设置状态栏字体为黑色
@@ -62,6 +74,7 @@ public class MineInfomationActivity extends BaseActivity<MineInformationLayoutBi
setClick(viewBinding.includedTitle.imgBack); setClick(viewBinding.includedTitle.imgBack);
setClick(viewBinding.imgAvatar); setClick(viewBinding.imgAvatar);
setClick(viewBinding.imgCamera); setClick(viewBinding.imgCamera);
setClick(viewBinding.rlNickname);
} }
private void setClick(View view) { private void setClick(View view) {
@@ -99,6 +112,38 @@ public class MineInfomationActivity extends BaseActivity<MineInformationLayoutBi
} }
}).show(); }).show();
break; break;
case R.id.rl_nickname:
showEditDialog("修改昵称",
"请输入昵称",
mUserBean.getUser().getNickName(),
true,
"取消",
"确定",
INPUT_TYPE_NORMAL,
new OnDialogClick() {
@Override
public void onCancelClick() {
}
@Override
public void onConfirmClisk() {
}
@Override
public void onConfirmClisk(String content) {
showLoadingDialog();
mPresenter.updateUserInfo(content);
mUserBean.getUser().setNickName(content);
viewBinding.tvNicknameValue.setText(content);
}
@Override
public void onView1Click() {
}
});
break;
} }
} }
@@ -125,6 +170,25 @@ public class MineInfomationActivity extends BaseActivity<MineInformationLayoutBi
} }
} }
/**
* 获取个人信息成功
* @param bean
*/
@Override
public void updateUserInfoSuccess(BaseBean bean) {
hideDialogLoading();
}
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
}
@Override
public void logOutSuccess(BaseBean bean) {
}
private void getCompressFile(File file) { private void getCompressFile(File file) {
LubanCompressUtil.getInstance().getCompressFile(mContext, file, new LubanCompressUtil.CompressCallback() { LubanCompressUtil.getInstance().getCompressFile(mContext, file, new LubanCompressUtil.CompressCallback() {
@@ -176,7 +240,8 @@ public class MineInfomationActivity extends BaseActivity<MineInformationLayoutBi
@Override @Override
public void showError(String message) { public void showError(String message) {
hideDialogLoading();
ToastUtil.showShort(mContext,message);
} }
@Override @Override
@@ -210,4 +275,6 @@ public class MineInfomationActivity extends BaseActivity<MineInformationLayoutBi
public void getUserInfoSuccess(MineUserInfoBean bean) { public void getUserInfoSuccess(MineUserInfoBean bean) {
} }
} }

View File

@@ -85,4 +85,19 @@ public class PsdManageActivity extends BaseActivity<PasswordManLayoutBinding, Mi
public void getUserInfoSuccess(MineUserInfoBean bean) { public void getUserInfoSuccess(MineUserInfoBean bean) {
} }
@Override
public void updateUserInfoSuccess(BaseBean bean) {
}
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
}
@Override
public void logOutSuccess(BaseBean bean) {
}
} }

View File

@@ -72,11 +72,29 @@ public class ResetPsdActivity extends BaseActivity<ResetPsdLayoutBinding, MinePr
ToastUtil.showShort(mContext,getString(R.string.hint_input_psd_not_match)); ToastUtil.showShort(mContext,getString(R.string.hint_input_psd_not_match));
return; return;
} }
ToastUtil.showShort(mContext,"接口触发"); showLoadingDialog();
mPresenter.updateUserPsdByOld(viewBinding.etCurrentPsd.getText().toString(),
viewBinding.etInputConfirmPsd.getText().toString());
break; break;
} }
} }
/**
* 密码重置成功
* @param bean
*/
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
hideDialogLoading();
ToastUtil.showShort(mContext,"密码重置成功");
finish();
}
@Override
public void logOutSuccess(BaseBean bean) {
}
@Override @Override
public MinePresenter createPresenter() { public MinePresenter createPresenter() {
return new MinePresenter(new MineImpl()); return new MinePresenter(new MineImpl());
@@ -89,7 +107,8 @@ public class ResetPsdActivity extends BaseActivity<ResetPsdLayoutBinding, MinePr
@Override @Override
public void showError(String message) { public void showError(String message) {
hideDialogLoading();
ToastUtil.showShort(mContext,message);
} }
@Override @Override
@@ -101,4 +120,11 @@ public class ResetPsdActivity extends BaseActivity<ResetPsdLayoutBinding, MinePr
public void getUserInfoSuccess(MineUserInfoBean bean) { public void getUserInfoSuccess(MineUserInfoBean bean) {
} }
@Override
public void updateUserInfoSuccess(BaseBean bean) {
}
} }

View File

@@ -206,4 +206,19 @@ public class SettingsActivity extends BaseActivity<ActivitySettingsLayoutBinding
public void getUserInfoSuccess(MineUserInfoBean bean) { public void getUserInfoSuccess(MineUserInfoBean bean) {
} }
@Override
public void updateUserInfoSuccess(BaseBean bean) {
}
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
}
@Override
public void logOutSuccess(BaseBean bean) {
}
} }

View File

@@ -116,4 +116,19 @@ public class UserLogOffAccountActivity extends BaseActivity<UserLogOffActivityBi
public void getUserInfoSuccess(MineUserInfoBean bean) { public void getUserInfoSuccess(MineUserInfoBean bean) {
} }
@Override
public void updateUserInfoSuccess(BaseBean bean) {
}
@Override
public void updateUserPasswordSuccess(BaseBean bean) {
}
@Override
public void logOutSuccess(BaseBean bean) {
}
} }

View File

@@ -29,13 +29,24 @@ public class MineContract {
public interface DataModel{ public interface DataModel{
//获取个人信息 //获取个人信息
void getUserInfo(Map<String,Object> map, CallBack callBack); void getUserInfo(Map<String,Object> map, CallBack callBack);
//更新个人信息
void updateUserInfo(JSONObject json, CallBack callBack);
//通过旧密码,修改新密码
void updateUserPwdByOld(JSONObject json, CallBack callBack);
} }
public interface MineView extends IView { public interface MineView extends IView {
//获取个人信息
void getUserInfoSuccess(MineUserInfoBean bean); void getUserInfoSuccess(MineUserInfoBean bean);
//更新个人信息成功
void updateUserInfoSuccess(BaseBean bean);
//密码重设完成
void updateUserPasswordSuccess(BaseBean bean);
//退出登录
void logOutSuccess(BaseBean bean);
} }
public interface RecommendModel{ public interface RecommendModel{

View File

@@ -4,6 +4,7 @@ import com.ckkj.water.base.entity.MineUserInfoBean;
import com.ckkj.water.login.mvp.LoginContract; import com.ckkj.water.login.mvp.LoginContract;
import com.ckkj.water.mine.entity.MemberComboEntity; import com.ckkj.water.mine.entity.MemberComboEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.network.LoginStateManager;
import com.ckkj.water.network.NetWorkManager; import com.ckkj.water.network.NetWorkManager;
import org.json.JSONObject; import org.json.JSONObject;
@@ -59,4 +60,84 @@ public class MineImpl implements MineContract.DataModel {
} }
}); });
} }
/**
* 更新用户信息
* @param json
* @param callBack
*/
@Override
public void updateUserInfo(JSONObject json, MineContract.CallBack callBack) {
try {
NetWorkManager.getRequest().updateUserInfo(NetWorkManager.getToken(),NetWorkManager.toRequestBody(json))
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean bean) {
if (bean.getCode() == 200) {
callBack.success(bean);
} else {
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 通过旧密码更新密码
* @param json
* @param callBack
*/
@Override
public void updateUserPwdByOld(JSONObject json, MineContract.CallBack callBack) {
try {
NetWorkManager.getRequest().updatePasswordByOld(NetWorkManager.getToken(),NetWorkManager.toRequestBody(json))
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean bean) {
if (bean.getCode() == 200) {
callBack.success(bean);
} else {
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
} }

View File

@@ -1,15 +1,22 @@
package com.ckkj.water.mine.mvp; package com.ckkj.water.mine.mvp;
import android.text.Editable;
import android.text.TextUtils; import android.text.TextUtils;
import com.ckkj.water.ConstantUtil; import com.ckkj.water.ConstantUtil;
import com.ckkj.water.base.BasePresenter; import com.ckkj.water.base.BasePresenter;
import com.ckkj.water.base.entity.MineUserInfoBean; import com.ckkj.water.base.entity.MineUserInfoBean;
import com.ckkj.water.base.entity.UserInfoEntity; import com.ckkj.water.base.entity.UserInfoEntity;
import com.ckkj.water.login.mvp.LoginContract;
import com.ckkj.water.login.mvp.LoginImpl;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.utils.dataUtil.SharePreUtil; import com.ckkj.water.utils.dataUtil.SharePreUtil;
import com.ckkj.water.utils.manager.WaterUserInfoManager; import com.ckkj.water.utils.manager.WaterUserInfoManager;
import com.google.gson.Gson; import com.google.gson.Gson;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -49,4 +56,83 @@ public class MinePresenter extends BasePresenter<MineContract.MineView> {
}); });
} }
/**
* 修改用户信息
* @param content
*/
public void updateUserInfo(String content) {
try {
JSONObject json = new JSONObject();
json.put("nickName", content);
impl.updateUserInfo(json, new MineContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean) {
if(MinePresenter.this.getView() != null){
MinePresenter.this.getView().updateUserInfoSuccess(bean);
}
}
@Override
public void fail(String msg) {
if(MinePresenter.this.getView() != null){
MinePresenter.this.getView().showError(msg);
}
}
});
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
/**
* 通过旧密码更新密码
* @param oldPsd
* @param newPsd
*/
public void updateUserPsdByOld(String oldPsd, String newPsd) {
try {
JSONObject json = new JSONObject();
json.put("oldPassword", oldPsd);
json.put("password", newPsd);
impl.updateUserPwdByOld(json, new MineContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean) {
if(MinePresenter.this.getView() != null){
MinePresenter.this.getView().updateUserPasswordSuccess(bean);
}
}
@Override
public void fail(String msg) {
if(MinePresenter.this.getView() != null){
MinePresenter.this.getView().showError(msg);
}
}
});
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
/**
* 退出登录
*/
public void logout() {
JSONObject json = new JSONObject();
new LoginImpl().logout(json, new LoginContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean) {
if(MinePresenter.this.getView() != null){
MinePresenter.this.getView().logOutSuccess(bean);
}
}
@Override
public void fail(String msg) {
if(MinePresenter.this.getView() != null){
MinePresenter.this.getView().showError(msg);
}
}
});
}
} }

View File

@@ -3,9 +3,12 @@ package com.ckkj.water.network;
import com.ckkj.water.base.entity.MineUserInfoBean; import com.ckkj.water.base.entity.MineUserInfoBean;
import com.ckkj.water.index.entity.IndexDeviceEntity; import com.ckkj.water.history.entity.WaterStatisticsEntity;
import com.ckkj.water.history.entity.WateringRecord;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.login.entity.LoginEntity; import com.ckkj.water.login.entity.LoginEntity;
import com.ckkj.water.main.entity.CheckVersionEntity; import com.ckkj.water.main.entity.CheckVersionEntity;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.plate.entity.BaziResultBean; import com.ckkj.water.plate.entity.BaziResultBean;
import com.ckkj.water.plate.entity.BaziSaveSuccessEntity; import com.ckkj.water.plate.entity.BaziSaveSuccessEntity;
import com.ckkj.water.plate.entity.PaipanHistoryEntity; import com.ckkj.water.plate.entity.PaipanHistoryEntity;
@@ -18,7 +21,6 @@ import okhttp3.RequestBody;
import retrofit2.http.Body; import retrofit2.http.Body;
import retrofit2.http.DELETE; import retrofit2.http.DELETE;
import retrofit2.http.GET; import retrofit2.http.GET;
import retrofit2.http.HTTP;
import retrofit2.http.HeaderMap; import retrofit2.http.HeaderMap;
import retrofit2.http.POST; import retrofit2.http.POST;
import retrofit2.http.PUT; import retrofit2.http.PUT;
@@ -37,32 +39,99 @@ public interface Request {
//注册 //注册
@POST("auth/register") @POST("auth/register")
Observable<BaseBean> register(@Body RequestBody requestBody); Observable<BaseBean> register(@Body RequestBody requestBody);
//退出登录
@POST("auth/logout")
Observable<BaseBean> logout(@Body RequestBody requestBody);
//登录 //登录
@POST("auth/login") @POST("auth/login")
Observable<BaseBean<LoginEntity>> loginBySmsCode(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody); Observable<BaseBean<LoginEntity>> loginBySmsCode(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody);
//获取个人信息 //获取个人信息
@GET("app/v1/getUserInfo") @GET("app/v1/getUserInfo")
Observable<BaseBean<MineUserInfoBean>> getMineUserInfo(@HeaderMap Map<String, String> headMap, @QueryMap Map<String, Object> map); Observable<BaseBean<MineUserInfoBean>> getMineUserInfo(@HeaderMap Map<String, String> headMap, @QueryMap Map<String, Object> map);
//修改个人信息
@PUT("app/v1/updataUser")
Observable<BaseBean> updateUserInfo(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody);
//首页设备列表 //首页设备列表
@GET("app/v1/deviceList") @GET("app/v1/deviceList")
Observable<BaseBean<List<IndexDeviceEntity>>> getIndexDeviceList(@HeaderMap Map<String, String> headMap); Observable<BaseBean<List<WaterDeviceEntity>>> getIndexDeviceList(@HeaderMap Map<String, String> headMap);
//添加设备 //添加设备
@POST("app/v1/addDevice") @POST("app/v1/addDevice")
Observable<BaseBean> addDevice(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody); Observable<BaseBean> addDevice(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody);
//获取设备详细信息 //获取设备详细信息
@GET("app/v1/device/{id}") @GET("app/v1/device/{id}")
Observable<BaseBean<IndexDeviceEntity>> getDeviceDetailInfo(@HeaderMap Map<String, String> headMap, @Path("id") String id); Observable<BaseBean<WaterDeviceEntity>> getDeviceDetailInfo(@HeaderMap Map<String, String> headMap, @Path("id") String id);
//开启/关闭设备
@PUT("app/v1/switchDevice")
Observable<BaseBean<WaterPlanWeekEntity>> switchDevice(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody);
//修改更新设备信息 //修改更新设备信息
@PUT("app/v1/updateDeviceInfo") @PUT("app/v1/updateDeviceInfo")
Observable<BaseBean> updateDeviceInfo(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody); Observable<BaseBean> updateDeviceInfo(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody);
//解绑信息 //通过旧密码修改密码
// 示例:ids array[string] @PUT("app/v1/updataPassword")
//["2052921001527869441"] Observable<BaseBean> updatePasswordByOld(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody);
//通过手机、邮箱验证码修改密码
@POST("app/v1/retrievePassword")
Observable<BaseBean> updatePasswordByVerifyCode(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody);
//查询排程列表
@GET("app/v1/schedulelist")
Observable<BaseBean<List<WaterPlanWeekEntity>>> scheduleList(@HeaderMap Map<String, String> headMap,@QueryMap Map<String, String> map);
//添加排程信息
@POST("app/v1/addschedule")
Observable<BaseBean<WaterPlanWeekEntity>> addSchedule(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody);
//编辑排程,更新
@PUT("app/v1/updataschedule")
Observable<BaseBean<WaterPlanWeekEntity>> updateSchedule(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody);
//查询排程可绑定设备列表
@GET("app/v1/scheduleDeviceList/{id}")
Observable<BaseBean<WaterDeviceEntity>> getPlanBindDeviceList(@HeaderMap Map<String, String> headMap, @Path("id") String id);
//查询排程详情
@GET("app/v1/schedule/{id}")
Observable<BaseBean<WaterPlanWeekEntity>> getPlanDetailInfo(@HeaderMap Map<String, String> headMap, @Path("id") String id);
//排程绑定设备
@POST("app/v1/addScheduleDevice")
Observable<BaseBean> planBindDevice(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody);
//更新排程状态
@PUT("app/v1/editScheduleStatus")
Observable<BaseBean<WaterPlanWeekEntity>> updateScheduleStatus(@HeaderMap Map<String, String> headMap, @Body RequestBody requestBody);
//删除排程
@DELETE("app/v1/deleteschedule/{ids}")
Observable<BaseBean> deletePlanById(@HeaderMap Map<String,String> headMap, @Path("ids") String id);
//删除设备
@DELETE("app/v1/deleteDevice/{ids}") @DELETE("app/v1/deleteDevice/{ids}")
Observable<BaseBean> unBindDevice(@HeaderMap Map<String,String> headMap, @Path("ids") String id); Observable<BaseBean> unBindDevice(@HeaderMap Map<String,String> headMap, @Path("ids") String id);
//排程解绑设备
@DELETE("app/v1/deleteScheduleDevice")
Observable<BaseBean> planUnBindDevice(@HeaderMap Map<String,String> headMap,@QueryMap Map<String, String> map);
//浇水历史记录
@GET("app/v1/waterLogList")
Observable<BaseBean<List<WateringRecord>>> waterLogList(@HeaderMap Map<String, String> headMap, @QueryMap Map<String, String> map);
//删除某一条历史记录
@DELETE("app/v1/waterLog/{id}")
Observable<BaseBean> deleteWaterLog(@HeaderMap Map<String,String> headMap, @Path("id") String id);
//浇水历史数据统计
@GET("app/v1/dataStatistics")
Observable<BaseBean<WaterStatisticsEntity>> getDataStatistics(@HeaderMap Map<String, String> headMap);

View File

@@ -1,40 +1,50 @@
package com.ckkj.water.plan; package com.ckkj.water.plan;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils;
import android.view.View; import android.view.View;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity; import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.databinding.AddWaterPlanLayoutBinding; import com.ckkj.water.databinding.AddWaterPlanLayoutBinding;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity; import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.plan.mvp.WaterPlanContract; import com.ckkj.water.plan.mvp.WaterPlanContract;
import com.ckkj.water.plan.mvp.WaterPlanImpl; import com.ckkj.water.plan.mvp.WaterPlanImpl;
import com.ckkj.water.plan.mvp.WaterPlanPresenter; import com.ckkj.water.plan.mvp.WaterPlanPresenter;
import com.ckkj.water.plate.adapter.ViewPagerAdapter; import com.ckkj.water.plate.adapter.ViewPagerAdapter;
import com.ckkj.water.utils.show.ToastUtil;
import com.gyf.immersionbar.ImmersionBar; import com.gyf.immersionbar.ImmersionBar;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* 添加浇水排程 * 添加/编辑浇水排程
*/ */
public class AddWaterPlanActivity extends BaseActivity<AddWaterPlanLayoutBinding, WaterPlanPresenter> public class AddWaterPlanActivity extends BaseActivity<AddWaterPlanLayoutBinding, WaterPlanPresenter>
implements WaterPlanContract.WaterPlanView { implements WaterPlanContract.WaterPlanView {
private List<Fragment> mFragmentList = new ArrayList<>(); private List<Fragment> mFragmentList = new ArrayList<>();
private List<WaterPlanWeekEntity.DeviceEntity> mSelectedDevices = new ArrayList<>(); private boolean mIsEditMode = false;
private WaterPlanWeekEntity mEditEntity;
public List<WaterPlanWeekEntity.DeviceEntity> getSelectedDevices() { private WaterPlanWeekEntity mNewAddEntity;
return mSelectedDevices; // private List<WaterPlanWeekEntity.DeviceEntity> mSelectedDevices = new ArrayList<>();
} //
// public List<WaterPlanWeekEntity.DeviceEntity> getSelectedDevices() {
public void setSelectedDevices(List<WaterPlanWeekEntity.DeviceEntity> selectedDevices) { // return mSelectedDevices;
this.mSelectedDevices = selectedDevices; // }
} //
// public void setSelectedDevices(List<WaterPlanWeekEntity.DeviceEntity> selectedDevices) {
// this.mSelectedDevices = selectedDevices;
// }
@Override @Override
public WaterPlanPresenter createPresenter() { public WaterPlanPresenter createPresenter() {
@@ -51,8 +61,24 @@ public class AddWaterPlanActivity extends BaseActivity<AddWaterPlanLayoutBinding
.statusBarDarkFont(true) // 设置状态栏字体为黑色 .statusBarDarkFont(true) // 设置状态栏字体为黑色
.titleBar(viewBinding.rlTitle) .titleBar(viewBinding.rlTitle)
.init(); .init();
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
mIsEditMode = bundle.getBoolean("is_edit", false);
mEditEntity = (WaterPlanWeekEntity) bundle.getSerializable("plan_entity");
}
// 根据模式设置标题
if (mIsEditMode) {
viewBinding.includedTitle.tvTitle.setText(R.string.edit_water_plan_title);
viewBinding.tvBound.setVisibility(VISIBLE);
} else {
viewBinding.includedTitle.tvTitle.setText(R.string.add_water_plan_title); viewBinding.includedTitle.tvTitle.setText(R.string.add_water_plan_title);
mFragmentList.add(new WaterConfigFragment()); viewBinding.tvBound.setVisibility(GONE);
}
mFragmentList.add(new WaterConfigFragment_copy());
mFragmentList.add(new PlanBoundDeviceFragment());
mFragmentList.add(new BindDeviceFragment()); mFragmentList.add(new BindDeviceFragment());
ViewPagerAdapter adapter = new ViewPagerAdapter(mContext, mFragmentList); ViewPagerAdapter adapter = new ViewPagerAdapter(mContext, mFragmentList);
viewBinding.viewpage.setAdapter(adapter); viewBinding.viewpage.setAdapter(adapter);
@@ -63,11 +89,23 @@ public class AddWaterPlanActivity extends BaseActivity<AddWaterPlanLayoutBinding
viewBinding.tvConfig.setSelected(true); viewBinding.tvConfig.setSelected(true);
viewBinding.tvBind.setSelected(false); viewBinding.tvBind.setSelected(false);
initListener(); initListener();
// 编辑模式下,延迟传递数据给 WaterConfigFragment等 viewBinding 初始化完成后调用
if (mIsEditMode && mEditEntity != null) {
viewBinding.viewpage.post(() -> {
WaterConfigFragment_copy configFragment = (WaterConfigFragment_copy) mFragmentList.get(0);
configFragment.setEditEntity(mEditEntity);
PlanBoundDeviceFragment boundDeviceFragment = (PlanBoundDeviceFragment) mFragmentList.get(1);
boundDeviceFragment.setEditEntity(mEditEntity);
});
}
} }
private void initListener() { private void initListener() {
setClick(viewBinding.includedTitle.imgBack); setClick(viewBinding.includedTitle.imgBack);
setClick(viewBinding.tvConfig); setClick(viewBinding.tvConfig);
setClick(viewBinding.tvBound);
setClick(viewBinding.tvBind); setClick(viewBinding.tvBind);
} }
@@ -84,19 +122,114 @@ public class AddWaterPlanActivity extends BaseActivity<AddWaterPlanLayoutBinding
case R.id.tv_config: case R.id.tv_config:
viewBinding.tvConfig.setSelected(true); viewBinding.tvConfig.setSelected(true);
viewBinding.tvBind.setSelected(false); viewBinding.tvBind.setSelected(false);
viewBinding.tvBound.setSelected(false);
viewBinding.viewpage.setCurrentItem(0); viewBinding.viewpage.setCurrentItem(0);
break; break;
case R.id.tv_bind: case R.id.tv_bound:
viewBinding.tvConfig.setSelected(false); viewBinding.tvConfig.setSelected(false);
viewBinding.tvBind.setSelected(true); viewBinding.tvBound.setSelected(true);
viewBinding.tvBind.setSelected(false);
viewBinding.viewpage.setCurrentItem(1); viewBinding.viewpage.setCurrentItem(1);
// 传递编辑实体给 PlanBoundDeviceFragment
PlanBoundDeviceFragment boundDeviceFragment = (PlanBoundDeviceFragment) mFragmentList.get(1);
boundDeviceFragment.setEditEntity(mEditEntity);
break;
case R.id.tv_bind:
WaterConfigFragment_copy configFragment = (WaterConfigFragment_copy) mFragmentList.get(0);
// 检查是否有未保存的数据变更
if (configFragment.hasDataChanged()) {
showDialogtext(null, false, false, true,
"提示", "数据已发生变更,是否保存?",
getString(R.string.cancel_text), "保存", new BaseFragment.OnDialogClick() {
@Override
public void onCancelClick() {
}
@Override
public void onConfirmClick() {
// 更新配置
configFragment.updateConfig();
}
});
return;
}
if (!configFragment.isConfigSubmitted()) {
// 校验新增排程的配置
if (!mIsEditMode) {
if (TextUtils.isEmpty(configFragment.getPlanName())) {
ToastUtil.showShort(mContext, getString(R.string.plan_name_text_empty_hint));
return;
}
if (!configFragment.hasTimeConfig()) {
ToastUtil.showShort(mContext, "请至少配置一天的时间");
return;
}
}
showDialogtext(null, false, false, true,
"提示", "关联设备需要保存排程配置,是否继续?",
getString(R.string.cancel_text), "继续", new BaseFragment.OnDialogClick() {
@Override
public void onCancelClick() {
}
@Override
public void onConfirmClick() {
configFragment.commitConfig();
}
});
return;
}
proceedToBindDevice();
break;
default:
break; break;
} }
} }
private void selectTabBind(WaterPlanWeekEntity entity) {
if (entity == null) {
entity = mIsEditMode ? mEditEntity : mNewAddEntity;
}
if (entity == null) {
ToastUtil.showShort(mContext, "请先保存排程");
return;
}
viewBinding.tvConfig.setSelected(false);
viewBinding.tvBound.setSelected(false);
viewBinding.tvBind.setSelected(true);
viewBinding.viewpage.setCurrentItem(2);
// 传递排程数据给 BindDeviceFragment
BindDeviceFragment bindDeviceFragment = (BindDeviceFragment) mFragmentList.get(2);
bindDeviceFragment.setPlanEntity(entity);
}
/**
* 切换到绑定设备页面
*/
private void proceedToBindDevice() {
WaterConfigFragment_copy configFragment = (WaterConfigFragment_copy) mFragmentList.get(0);
WaterPlanWeekEntity entity = mIsEditMode ? mEditEntity : mNewAddEntity;
if (entity == null) {
entity = configFragment.getRemoteEntity();
}
selectTabBind(entity);
}
public void onConfigSaved(WaterPlanWeekEntity entity) {
mNewAddEntity = entity;
selectTabBind(entity);
}
@Override @Override
public int getLayoutResId(Bundle savedInstanceState) { public int getLayoutResId(Bundle savedInstanceState) {
return 0; return 0;
@@ -111,4 +244,50 @@ public class AddWaterPlanActivity extends BaseActivity<AddWaterPlanLayoutBinding
public void logOut(BaseBean bean) { public void logOut(BaseBean bean) {
} }
@Override
public void getWaterConfigListSuccess(List<WaterPlanWeekEntity> list,int total) {
}
@Override
public void saveConfigSuccess(WaterPlanWeekEntity entity) {
}
@Override
public void updateConfigSuccess(WaterPlanWeekEntity entity) {
}
@Override
public void updatePlanStatusSuccess(BaseBean bean, String status) {
}
@Override
public void getPlanDetailInfo(WaterPlanWeekEntity entity) {
}
@Override
public void getPlanBindDeviceList(WaterDeviceEntity bean) {
}
@Override
public void planBindDeviceSuccess(BaseBean bean) {
}
@Override
public void deletePlanSuccess(BaseBean bean) {
}
@Override
public void planUnbindDeviceSuccess(BaseBean bean, int position) {
}
} }

View File

@@ -1,26 +1,25 @@
package com.ckkj.water.plan; package com.ckkj.water.plan;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.view.View; import android.view.View;
import androidx.databinding.BindingAdapter;
import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.BaseQuickAdapter;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.base.BaseFragment; import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.databinding.PlanBindDeviceLayoutBinding; import com.ckkj.water.databinding.PlanBindDeviceLayoutBinding;
import com.ckkj.water.main.activity.MainActivity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
//import com.ckkj.water.plan.adapter.BindDeviceAdapter;
import com.ckkj.water.plan.adapter.BindDeviceAdapter; import com.ckkj.water.plan.adapter.BindDeviceAdapter;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity; import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.plan.mvp.WaterPlanContract; import com.ckkj.water.plan.mvp.WaterPlanContract;
import com.ckkj.water.plan.mvp.WaterPlanImpl; import com.ckkj.water.plan.mvp.WaterPlanImpl;
import com.ckkj.water.plan.mvp.WaterPlanPresenter; import com.ckkj.water.plan.mvp.WaterPlanPresenter;
import com.google.gson.Gson; import com.ckkj.water.utils.show.ToastUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* 排程关联设备 * 排程关联设备
@@ -29,36 +28,144 @@ public class BindDeviceFragment extends BaseFragment<PlanBindDeviceLayoutBinding
implements WaterPlanContract.WaterPlanView { implements WaterPlanContract.WaterPlanView {
private List<WaterPlanWeekEntity> weekList = new ArrayList<>(); private List<WaterPlanWeekEntity> weekList = new ArrayList<>();
private List<WaterDeviceEntity.DeviceListBean> mDeviceList = new ArrayList<>();
private WaterPlanWeekEntity mPlanEntity;
private BindDeviceAdapter mAdapter; private BindDeviceAdapter mAdapter;
@Override @Override
public void initData(Bundle state) { public void initData(Bundle state) {
String jsonContent = getString(R.string.plan_water_entity_json); initListener();
WaterPlanWeekEntity entity = new Gson().fromJson(jsonContent, WaterPlanWeekEntity.class); mAdapter = new BindDeviceAdapter(mContext,R.layout.plan_bind_device_item,mDeviceList);
weekList.add(entity);
mAdapter = new BindDeviceAdapter(mContext,R.layout.plan_bind_device_item,weekList.get(0).getDeviceList());
viewBinding.rvDevices.setAdapter(mAdapter); viewBinding.rvDevices.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() { mAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override @Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) { public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
mAdapter.toggleSelection(position); mAdapter.toggleSelection(position);
syncSelectedDevices(); if(mDeviceList.get(position).getStatus().equals("0")){
mDeviceList.get(position).setStatus("1");
}else{
mDeviceList.get(position).setStatus("0");
}
} }
}); });
if (mPlanEntity != null) {
mPresenter.getPlanBindDevices(mPlanEntity);
}
} }
private void syncSelectedDevices() { private void initListener() {
Set<Integer> selectedPositions = mAdapter.getSelectedPositions(); setClick(viewBinding.tvCommit);
List<WaterPlanWeekEntity.DeviceEntity> selected = new ArrayList<>(); }
for (int pos : selectedPositions) { private void setClick(View view) {
if (pos >= 0 && pos < weekList.get(0).getDeviceList().size()) { view.setOnClickListener(this::onClick);
selected.add(weekList.get(0).getDeviceList().get(pos)); }
public void onClick(View v){
switch (v.getId()){
case R.id.tv_commit:
if (mPlanEntity == null) {
ToastUtil.showShort(mContext, "请先保存排程");
return;
}
boolean isSelected = false;
List<String> selected = new ArrayList<>();
for(WaterDeviceEntity.DeviceListBean bean : mDeviceList){
if(bean.getStatus().equals("1")){
isSelected = true;
selected.add(bean.getId());
} }
} }
if(!isSelected){
ToastUtil.showShort(mContext, getString(R.string.select_the_device_to_link));
return;
}
String selDevice = "";
for(String id : selected){
selDevice += id + ",";
}
selDevice = selDevice.substring(0,selDevice.length()-1);
//提交绑定
mPresenter.planBindWithDevices(mPlanEntity,selDevice);
break;
}
}
@Override
protected void onResumeInitData() {
super.onResumeInitData();
}
/**
* 设置排程实体,用于关联设备接口请求
* @param entity 排程实体
*/
public void setPlanEntity(WaterPlanWeekEntity entity) {
this.mPlanEntity = entity;
if (mPlanEntity != null) {
if(mPresenter != null){
mPresenter.getPlanBindDevices(mPlanEntity);
}
}
}
/**
* 查询到了可绑定的设备
* @param bean
*/
@Override
public void getPlanBindDeviceList(WaterDeviceEntity bean) {
hideDialogLoading();
if(mAdapter != null){
mDeviceList = bean.getDeviceList();
mAdapter.setNewData(mDeviceList);
if (mAdapter.getItemCount() != 0) {
viewBinding.relNoresult.setVisibility(View.GONE);
viewBinding.linearContent.setVisibility(View.VISIBLE);
} else {
viewBinding.relNoresult.setVisibility(View.VISIBLE);
viewBinding.linearContent.setVisibility(View.GONE);
}
}
}
@Override
public void planBindDeviceSuccess(BaseBean bean) {
hideDialogLoading();
ToastUtil.showShort(mContext, "绑定成功");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (getActivity() instanceof AddWaterPlanActivity) { if (getActivity() instanceof AddWaterPlanActivity) {
((AddWaterPlanActivity) getActivity()).setSelectedDevices(selected); ((AddWaterPlanActivity) getActivity()).finish();
} }
} }
},800);
}
@Override
public void deletePlanSuccess(BaseBean bean) {
}
@Override
public void planUnbindDeviceSuccess(BaseBean bean, int position) {
}
// private void syncSelectedDevices() {
// Set<Integer> selectedPositions = mAdapter.getSelectedPositions();
// List<WaterPlanWeekEntity.DeviceEntity> selected = new ArrayList<>();
// for (int pos : selectedPositions) {
// if (pos >= 0 && pos < weekList.get(0).getDeviceList().size()) {
// selected.add(weekList.get(0).getDeviceList().get(pos));
// }
// }
// if (getActivity() instanceof AddWaterPlanActivity) {
// ((AddWaterPlanActivity) getActivity()).setSelectedDevices(selected);
// }
// }
@Override @Override
public WaterPlanPresenter createPresenter() { public WaterPlanPresenter createPresenter() {
@@ -79,4 +186,31 @@ public class BindDeviceFragment extends BaseFragment<PlanBindDeviceLayoutBinding
public void logOut(BaseBean bean) { public void logOut(BaseBean bean) {
} }
@Override
public void getWaterConfigListSuccess(List<WaterPlanWeekEntity> list,int total) {
}
@Override
public void saveConfigSuccess(WaterPlanWeekEntity entity) {
}
@Override
public void updateConfigSuccess(WaterPlanWeekEntity entity) {
}
@Override
public void updatePlanStatusSuccess(BaseBean bean, String status) {
}
@Override
public void getPlanDetailInfo(WaterPlanWeekEntity entity) {
}
} }

View File

@@ -0,0 +1,193 @@
package com.ckkj.water.plan;
import android.os.Bundle;
import android.view.View;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.databinding.PlanBoundDeviceLayoutBinding;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plan.adapter.PlanBoundDeviceAdapter;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.plan.mvp.WaterPlanContract;
import com.ckkj.water.plan.mvp.WaterPlanImpl;
import com.ckkj.water.plan.mvp.WaterPlanPresenter;
import com.ckkj.water.utils.show.ToastUtil;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2026/5/29
* @description 已绑定的设备列表
*/
public class PlanBoundDeviceFragment extends BaseFragment<PlanBoundDeviceLayoutBinding, WaterPlanPresenter>
implements WaterPlanContract.WaterPlanView{
private WaterPlanWeekEntity mEditEntity;
private PlanBoundDeviceAdapter mAdapter;
@Override
public void initData(Bundle state) {
// 初始化适配器,如果有数据则设置
if (mEditEntity != null && mEditEntity.getDeviceIds() != null) {
mAdapter = new PlanBoundDeviceAdapter(mContext, R.layout.plan_bound_device_item, mEditEntity.getDeviceIds());
viewBinding.rvDevices.setAdapter(mAdapter);
// 根据数据状态显示/隐藏视图
if (mEditEntity.getDeviceIds().isEmpty()) {
viewBinding.linearContent.setVisibility(View.GONE);
viewBinding.relNoresult.setVisibility(View.VISIBLE);
} else {
viewBinding.linearContent.setVisibility(View.VISIBLE);
viewBinding.relNoresult.setVisibility(View.GONE);
}
} else {
// 无数据时显示空状态
viewBinding.linearContent.setVisibility(View.GONE);
viewBinding.relNoresult.setVisibility(View.VISIBLE);
}
if(mAdapter != null){
mAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
switch (view.getId()){
case R.id.img_delete:
showDialogtext(null, false, false, "提示",
"确定解绑该设备?", "取消", "解绑",
new OnDialogClick() {
@Override
public void onCancelClick() {
}
@Override
public void onConfirmClick() {
showLoadingDialog();
mPresenter.planUnbindDevice(mEditEntity.getId(),
mEditEntity.getDeviceIds().get(position).getId(),
position);
}
});
break;
}
}
});
}
}
public void setEditEntity(WaterPlanWeekEntity entity) {
this.mEditEntity = entity;
// 使用 getView().post() 确保视图已初始化完成
if (getView() != null) {
getView().post(() -> {
if (viewBinding != null) {
updateUI();
}
});
}
}
private void updateUI() {
if (viewBinding == null) {
return;
}
if (mEditEntity == null || mEditEntity.getDeviceIds() == null) {
viewBinding.linearContent.setVisibility(View.GONE);
viewBinding.relNoresult.setVisibility(View.VISIBLE);
return;
}
if (mEditEntity.getDeviceIds().isEmpty()) {
viewBinding.linearContent.setVisibility(View.GONE);
viewBinding.relNoresult.setVisibility(View.VISIBLE);
} else {
viewBinding.linearContent.setVisibility(View.VISIBLE);
viewBinding.relNoresult.setVisibility(View.GONE);
if (mAdapter != null) {
mAdapter.setNewData(mEditEntity.getDeviceIds());
}
}
}
public WaterPlanWeekEntity getEditEntity() {
return mEditEntity;
}
@Override
public WaterPlanPresenter createPresenter() {
return new WaterPlanPresenter(new WaterPlanImpl());
}
@Override
public void getWaterConfigListSuccess(List<WaterPlanWeekEntity> list, int total) {
}
@Override
public void saveConfigSuccess(WaterPlanWeekEntity entity) {
}
@Override
public void updateConfigSuccess(WaterPlanWeekEntity entity) {
}
@Override
public void updatePlanStatusSuccess(BaseBean bean, String status) {
}
@Override
public void getPlanDetailInfo(WaterPlanWeekEntity entity) {
}
@Override
public void getPlanBindDeviceList(WaterDeviceEntity bean) {
}
@Override
public void planBindDeviceSuccess(BaseBean bean) {
}
@Override
public void deletePlanSuccess(BaseBean bean) {
}
@Override
public void planUnbindDeviceSuccess(BaseBean bean, int position) {
hideDialogLoading();
ToastUtil.showShort(mContext, "解绑成功");
mAdapter.notifyItemRemoved(position);
mEditEntity.getDeviceIds().remove(position);
if (mAdapter.getItemCount() != 0) {
viewBinding.relNoresult.setVisibility(View.GONE);
viewBinding.linearContent.setVisibility(View.VISIBLE);
} else {
viewBinding.relNoresult.setVisibility(View.VISIBLE);
viewBinding.linearContent.setVisibility(View.GONE);
}
}
@Override
public void onNetChange(int netModel) {
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
}

View File

@@ -1,33 +1,63 @@
package com.ckkj.water.plan; package com.ckkj.water.plan;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity; import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.databinding.WaterPlanDetailLayoutBinding; import com.ckkj.water.databinding.WaterPlanDetailLayoutBinding;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
//import com.ckkj.water.plan.adapter.PlanDetailDeviceAdapter;
//import com.ckkj.water.plan.adapter.PlanDetailTimeAdapter;
import com.ckkj.water.plan.adapter.PlanDetailDeviceAdapter; import com.ckkj.water.plan.adapter.PlanDetailDeviceAdapter;
import com.ckkj.water.plan.adapter.PlanDetailTimeAdapter; import com.ckkj.water.plan.adapter.PlanDetailTimeAdapter;
import com.ckkj.water.plan.adapter.PlanWeekDaysAdapter;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity; import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.plan.mvp.WaterPlanContract; import com.ckkj.water.plan.mvp.WaterPlanContract;
import com.ckkj.water.plan.mvp.WaterPlanImpl; import com.ckkj.water.plan.mvp.WaterPlanImpl;
import com.ckkj.water.plan.mvp.WaterPlanPresenter; import com.ckkj.water.plan.mvp.WaterPlanPresenter;
import com.ckkj.water.utils.show.ToastUtil;
import com.ckkj.water.utils.time.ZYTimeUtils;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.gyf.immersionbar.ImmersionBar; import com.gyf.immersionbar.ImmersionBar;
import java.util.ArrayList;
import java.util.List;
/** /**
* 排程详情页面 * 排程详情页面
*/ */
public class PlanDetailActivity extends BaseActivity<WaterPlanDetailLayoutBinding, WaterPlanPresenter> public class PlanDetailActivity extends BaseActivity<WaterPlanDetailLayoutBinding, WaterPlanPresenter>
implements WaterPlanContract.WaterPlanView { implements WaterPlanContract.WaterPlanView {
//列表页面传的的,用于获取详情
private WaterPlanWeekEntity mPlanEntity;
//查询到的排程详情
private WaterPlanWeekEntity mDetailEntity;
private PlanWeekDaysAdapter mAdapter;
private PlanDetailDeviceAdapter deviceAdapter;
private List<WaterPlanWeekEntity.DetailsBean> mList = new ArrayList<>();
@Override
protected void onResume() {
super.onResume();
showLoadingDialog();
mPresenter.getPlanDetailInfo(mPlanEntity);
}
@Override @Override
public void initData(Bundle savedInstanceState) { public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState); super.initData(savedInstanceState);
Bundle bundle = getIntent().getExtras();
if(bundle != null){
mPlanEntity = (WaterPlanWeekEntity) bundle.getSerializable("plan_entity");
}
String jsonContent = getString(R.string.plan_water_entity_json); String jsonContent = getString(R.string.plan_water_entity_json);
WaterPlanWeekEntity entity = new Gson().fromJson(jsonContent, WaterPlanWeekEntity.class); WaterPlanWeekEntity entity = new Gson().fromJson(jsonContent, WaterPlanWeekEntity.class);
ImmersionBar.with(this) ImmersionBar.with(this)
.statusBarColor(R.color.color_F9F9F9) // 设置状态栏颜色 .statusBarColor(R.color.color_F9F9F9) // 设置状态栏颜色
.statusBarDarkFont(true) // 设置状态栏字体为黑色 .statusBarDarkFont(true) // 设置状态栏字体为黑色
@@ -35,14 +65,34 @@ public class PlanDetailActivity extends BaseActivity<WaterPlanDetailLayoutBindin
.init(); .init();
viewBinding.includedTitle.tvTitle.setText(R.string.plan_detail_title); viewBinding.includedTitle.tvTitle.setText(R.string.plan_detail_title);
initListener(); initListener();
PlanDetailTimeAdapter timeAdapter = new PlanDetailTimeAdapter(R.layout.plan_detail_time_item,entity.getWashCycleList()); mAdapter = new PlanWeekDaysAdapter(R.layout.single_recycleview_item,mList);
viewBinding.rvPlanTime.setAdapter(timeAdapter); viewBinding.rvPlanTime.setAdapter(mAdapter);
PlanDetailDeviceAdapter deviceAdapter = new PlanDetailDeviceAdapter(R.layout.plan_detail_bind_device_item,entity.getDeviceList()); List<WaterDeviceEntity> deviceList = new ArrayList<>();
deviceAdapter = new PlanDetailDeviceAdapter(R.layout.plan_detail_bind_device_item,deviceList);
viewBinding.rvBindDevices.setAdapter(deviceAdapter); viewBinding.rvBindDevices.setAdapter(deviceAdapter);
} }
private void initListener() { private void initListener() {
setClick(viewBinding.includedTitle.imgBack); setClick(viewBinding.includedTitle.imgBack);
setClick(viewBinding.btnEdit);
setClick(viewBinding.btnDelete);
setClick(viewBinding.switchButton);
// viewBinding.switchButton.setOnTouchListener(new View.OnTouchListener() {
// @Override
// public boolean onTouch(View v, MotionEvent event) {
// if (event.getAction() == MotionEvent.ACTION_DOWN) {
// if (viewBinding.switchButton.isChecked()) {
// // 当前是开启状态,下一步将是关闭 -> 屏蔽动画时长设为0
// 0
// } else {
// // 当前是关闭状态,下一步将是开启 -> 开启动画(恢复默认的 250ms 或你想要的时长)
// viewBinding.switchButton.setAnimationDuration(250);
// }
// }
// // 返回 false 以便将触摸事件继续传递给 SwitchButton 内部的点击/滑动逻辑
// return false;
// }
// });
} }
private void setClick(View view) { private void setClick(View view) {
@@ -55,9 +105,162 @@ public class PlanDetailActivity extends BaseActivity<WaterPlanDetailLayoutBindin
finish(); finish();
break; break;
case R.id.btn_edit://编辑
if(mDetailEntity != null){
Bundle bundle = new Bundle();
bundle.putSerializable("plan_entity", mDetailEntity);
bundle.putBoolean("is_edit", true);
goTo(mContext, AddWaterPlanActivity.class,bundle);
}
break;
case R.id.btn_delete://删除
showDialogtext(null, false, false, true,
getString(R.string.tip_text), getString(R.string.delete_plan_tip),
getString(R.string.cancel_text), getString(R.string.confirm_text), new BaseFragment.OnDialogClick() {
@Override
public void onCancelClick() {
}
@Override
public void onConfirmClick() {
mPresenter.deletePlan(mDetailEntity);
}
});
break;
case R.id.switch_button://切换状态
// 先恢复 Switch 到原始状态,避免点击时立即改变
viewBinding.switchButton.setChecked(mDetailEntity.getStatus().equals("1"));
if(mDetailEntity.getStatus().equals("1")){
showDialogtext(null, false, false, true,
getString(R.string.tip_text), getString(R.string.close_plan_dialog_tip),
getString(R.string.cancel_text), getString(R.string.confirm_text), new BaseFragment.OnDialogClick() {
@Override
public void onCancelClick() {
// 取消操作,恢复 Switch 状态
viewBinding.switchButton.setChecked(true);
}
@Override
public void onConfirmClick() {
// 确认关闭任务,调用接口后再更新 Switch
showLoadingDialog();
mPresenter.updatePlanStatus(mDetailEntity, "0");
}
});
}else{
// 开启任务,调用接口后再更新 Switch
mPresenter.updatePlanStatus(mDetailEntity, "1");
}
break;
}
}
/**
* 获取配成详情成功
* @param entity
*/
@Override
public void getPlanDetailInfo(WaterPlanWeekEntity entity) {
hideDialogLoading();
mDetailEntity = entity;
viewBinding.tvPlanName.setText(entity.getName());
if(entity.getStatus().equals("1")){
viewBinding.switchButton.setChecked(true);
}else{
viewBinding.switchButton.setChecked(false);
}
//针对周一 --- 周日的日期,只显示勾选的日期
List<WaterPlanWeekEntity.DetailsBean> list = new ArrayList<>();
for(WaterPlanWeekEntity.DetailsBean bean : entity.getDetails()){
if(bean.getStatus().equals("1")){
// 检查该日期是否有有效的时间配置
boolean hasValidTime = false;
if(bean.getTimeData() != null){
for(WaterPlanWeekEntity.TimeDataBean timeBean : bean.getTimeData()){
if(!TextUtils.isEmpty(timeBean.getStartTime())
&& timeBean.getDurationMin() != 0){
hasValidTime = true;
bean.setWeekName(ZYTimeUtils.getWeekName(bean.getWeekday() - 1));
break;
}
}
}
if(hasValidTime){
list.add(bean);
}
}
}
//日期显示
if(mAdapter != null){
mAdapter.setNewData(list);
}
//设备显示
if(deviceAdapter != null){
deviceAdapter.setNewData(entity.getDeviceIds());
if(deviceAdapter.getItemCount() == 0){
viewBinding.rvBindDevices.setVisibility(View.GONE);
viewBinding.tvNoDevice.setVisibility(View.VISIBLE);
}else{
viewBinding.rvBindDevices.setVisibility(View.VISIBLE);
viewBinding.tvNoDevice.setVisibility(View.GONE);
}
}
}
/**
* 删除排程成功
* @param bean
*/
@Override
public void deletePlanSuccess(BaseBean bean) {
hideDialogLoading();
ToastUtil.showShort(mContext,getString(R.string.delete_plan_success));
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
finish();
}
},500);
}
@Override
public void planUnbindDeviceSuccess(BaseBean bean, int position) {
} }
/**
* 更新排程状态成功
*
* @param bean
* @param status
*/
@Override
public void updatePlanStatusSuccess(BaseBean bean, String status) {
hideDialogLoading();
mDetailEntity.setStatus(status);
if(status.equals("1")){
showCenterTipDialog(R.mipmap.icon_dialog_success,"任务已开启");
viewBinding.switchButton.setChecked(true);
}else{
viewBinding.switchButton.setChecked(false);
} }
}
@Override
public void getPlanBindDeviceList(WaterDeviceEntity bean) {
}
@Override
public void planBindDeviceSuccess(BaseBean bean) {
}
@Override @Override
public WaterPlanPresenter createPresenter() { public WaterPlanPresenter createPresenter() {
@@ -71,11 +274,29 @@ public class PlanDetailActivity extends BaseActivity<WaterPlanDetailLayoutBindin
@Override @Override
public void showError(String message) { public void showError(String message) {
hideDialogLoading();
ToastUtil.showShort(mContext,message);
} }
@Override @Override
public void logOut(BaseBean bean) { public void logOut(BaseBean bean) {
} }
@Override
public void getWaterConfigListSuccess(List<WaterPlanWeekEntity> list,int total) {
}
@Override
public void saveConfigSuccess(WaterPlanWeekEntity entity) {
}
@Override
public void updateConfigSuccess(WaterPlanWeekEntity entity) {
}
} }

View File

@@ -11,104 +11,227 @@ import com.bigkoo.pickerview.listener.OnTimeSelectListener;
import com.bigkoo.pickerview.view.TimePickerView; import com.bigkoo.pickerview.view.TimePickerView;
import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.BaseQuickAdapter;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.base.BaseFragment; import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.databinding.WaterConfigFragmentLayoutBinding; import com.ckkj.water.databinding.WaterConfigFragmentLayoutBinding;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plan.adapter.WaterPlanWeekAdapter; import com.ckkj.water.plan.adapter.WaterPlanWeekAdapter;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity; import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.plan.mvp.WaterPlanContract; import com.ckkj.water.plan.mvp.WaterPlanContract;
import com.ckkj.water.plan.mvp.WaterPlanImpl; import com.ckkj.water.plan.mvp.WaterPlanImpl;
import com.ckkj.water.plan.mvp.WaterPlanPresenter; import com.ckkj.water.plan.mvp.WaterPlanPresenter;
import com.ckkj.water.utils.show.ToastUtil;
import com.ckkj.water.utils.time.ZYTimeUtils; import com.ckkj.water.utils.time.ZYTimeUtils;
import com.google.gson.Gson;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
/**
* 配置信息页面
*/
public class WaterConfigFragment extends BaseFragment<WaterConfigFragmentLayoutBinding, WaterPlanPresenter> public class WaterConfigFragment extends BaseFragment<WaterConfigFragmentLayoutBinding, WaterPlanPresenter>
implements WaterPlanContract.WaterPlanView { implements WaterPlanContract.WaterPlanView {
private List<WaterPlanWeekEntity> weekList = new ArrayList<>(); private List<WaterPlanWeekEntity.DetailsBean> mConfigList = new ArrayList<>();
//用户本地操作排程时的数据
private WaterPlanWeekEntity mConfigEntity;
//排程接口新增成功之后,接口返回的该排程在远端的数据信息
private WaterPlanWeekEntity mRemoteConfigEntity;
private WaterPlanWeekAdapter mWeekAdapter; private WaterPlanWeekAdapter mWeekAdapter;
private String mPlanName = "";
public static boolean isConfigSave;
//当下是否编辑模式
private boolean mIsEditMode = false;
@Override @Override
public void initData(Bundle state) { public void initData(Bundle state) {
String jsonContent = getString(R.string.plan_water_entity_json); mConfigEntity = new WaterPlanWeekEntity();
WaterPlanWeekEntity entity = new Gson().fromJson(jsonContent, WaterPlanWeekEntity.class); List<WaterPlanWeekEntity.DetailsBean> list = new ArrayList<>();
weekList.add(entity); for(int i = 0; i < 7; i++){
mWeekAdapter = new WaterPlanWeekAdapter(mContext, R.layout.plan_period_item,weekList.get(0).getWashCycleList()); WaterPlanWeekEntity.DetailsBean bean = new WaterPlanWeekEntity.DetailsBean();
viewBinding.rvWeek.setAdapter(mWeekAdapter); bean.setWeekday(i + 1);
bean.setStatus("0");
bean.setWeekName(ZYTimeUtils.getWeekName(i));
list.add(bean);
}
mConfigEntity.setDetails(list);
mWeekAdapter = new WaterPlanWeekAdapter(mContext,R.layout.plan_week_config_item, mConfigEntity.getDetails());
viewBinding.rvWeekConfig.setAdapter(mWeekAdapter);
initListener(); initListener();
} }
/**
* 设置编辑模式的排程数据
* @param entity 从详情页传来的排程数据
*/
public void setEditEntity(WaterPlanWeekEntity entity) {
if (entity == null) {
return;
}
mIsEditMode = true;
// 深拷贝数据到 mConfigEntity用于本地编辑
mConfigEntity = cloneEntity(entity);
// 保存远程原始数据,用于后续变化检测
mRemoteConfigEntity = entity;
isConfigSave = true;
// 初始化 UI
viewBinding.etPlanName.setText(entity.getName());
mPlanName = entity.getName();
// 更新周配置列表的显示,使用 mConfigEntity.getDetails() 保证数据一致
if (mConfigEntity.getDetails() != null) {
mWeekAdapter.setNewData(mConfigEntity.getDetails());
}
}
/**
* 深拷贝 WaterPlanWeekEntity
*/
private WaterPlanWeekEntity cloneEntity(WaterPlanWeekEntity source) {
if (source == null) {
return null;
}
WaterPlanWeekEntity target = new WaterPlanWeekEntity();
target.setId(source.getId());
target.setName(source.getName());
target.setStatus(source.getStatus());
if (source.getDetails() != null) {
List<WaterPlanWeekEntity.DetailsBean> detailsList = new ArrayList<>();
for (WaterPlanWeekEntity.DetailsBean bean : source.getDetails()) {
WaterPlanWeekEntity.DetailsBean newBean = new WaterPlanWeekEntity.DetailsBean();
newBean.setId(bean.getId());
newBean.setWeekday(bean.getWeekday());
newBean.setWeekName(ZYTimeUtils.getWeekName(bean.getWeekday() - 1));
newBean.setStatus(bean.getStatus());
newBean.setStartTime(ZYTimeUtils.formatHHmm(bean.getStartTime()));
newBean.setDurationMin(bean.getDurationMin());
detailsList.add(newBean);
}
target.setDetails(detailsList);
}
return target;
}
private void initListener() { private void initListener() {
setClick(viewBinding.tvCommit); setClick(viewBinding.tvCommit);
setClick(viewBinding.tvSelectTime); mWeekAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
viewBinding.etPlanTime.addTextChangedListener(new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
switch (view.getId()){
case R.id.linear_week://选中
case R.id.checkbox:
if(mConfigEntity.getDetails().get(position).getStatus().equals("1")){
mConfigEntity.getDetails().get(position).setStatus("0");
}else{
mConfigEntity.getDetails().get(position).setStatus("1");
} }
mWeekAdapter.notifyItemChanged(position);
break;
case R.id.tv_select_time:
selectStartTime(position);
break;
case R.id.tv_plan_duration:
inputDuration(position);
break;
}
}
});
viewBinding.etPlanName.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override @Override
public void onTextChanged(CharSequence s, int start, int before, int count) { public void onTextChanged(CharSequence s, int start, int before, int count) {}
}
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
if(weekList != null){ if(!TextUtils.isEmpty(s.toString())){
String time = s.toString(); mPlanName = s.toString();
if(TextUtils.isEmpty(time)){ mConfigEntity.setName(s.toString());
weekList.get(0).getWashCycleList().get(mWeekAdapter.getmPos()).setDuration("");
}else{
weekList.get(0).getWashCycleList().get(mWeekAdapter.getmPos()).setDuration(time);
}
} }
} }
}); });
mWeekAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
mWeekAdapter.setSelPos(position);
String planStartTime = weekList.get(0).getWashCycleList().get(position).getTime();
String planTime = weekList.get(0).getWashCycleList().get(position).getDuration();
if(TextUtils.isEmpty(planStartTime)){
viewBinding.tvSelectTime.setHint(getString(R.string.select_water_time));
viewBinding.tvSelectTime.setText("");
}else{
viewBinding.tvSelectTime.setText(planStartTime);
}
if(TextUtils.isEmpty(planTime)){
viewBinding.etPlanTime.setHint(getString(R.string.input_water_plan_time));
viewBinding.etPlanTime.setText("");
}else{
viewBinding.etPlanTime.setText(planTime);
}
}
});
}
private void setClick(View view) {
view.setOnClickListener(this::onClick);
} }
public void onClick(View v){ public void onClick(View v){
switch (v.getId()){ switch (v.getId()){
case R.id.tv_select_time: case R.id.tv_commit:
commitConfig();
break;
}
}
public void commitConfig(){
if (!checkConfigFinish()) {
return;
}
// mRemoteConfigEntity 为空,说明是新增场景
if (mRemoteConfigEntity == null) {
mPresenter.saveConfig(mConfigEntity);
return;
}
// mRemoteConfigEntity 不为空,说明是更新场景
if (isConfigChanged()) {
// TODO: 触发更新接口,调用 mPresenter.updateConfig(mConfigEntity)
mPresenter.updateConfig(mConfigEntity);
} else {
ToastUtil.showShort(mContext, "配置没有变化,无需保存");
}
}
private void inputDuration(int position) {
showEditDialog(getString(R.string.device_work_times_title),
getString(R.string.input_water_plan_time),
mConfigEntity.getDetails().get(position).getDurationMin() == 0 ?
"" : mConfigEntity.getDetails().get(position).getDurationMin() + "",
true,
getString(R.string.cancel_text),
getString(R.string.confirm_text),
BaseFragment.INPUT_TYPE_NUMBER,
new BaseActivity.OnDialogClick() {
@Override
public void onCancelClick() {
}
@Override
public void onConfirmClisk() {
}
@Override
public void onConfirmClisk(String content) {
if(Integer.parseInt(content) <= 0){
ToastUtil.showShort(mContext, getString(R.string.input_water_plan_time_error));
return;
}
mConfigEntity.getDetails().get(position).setDurationMin(Integer.parseInt(content));
mWeekAdapter.notifyItemChanged(position);
}
@Override
public void onView1Click() {
}
});
}
private void selectStartTime(int position) {
boolean times[] = {false, false, false, true, true, false}; boolean times[] = {false, false, false, true, true, false};
//时间选择器 //时间选择器
TimePickerView pvTime = new TimePickerBuilder(mContext, new OnTimeSelectListener() { TimePickerView pvTime = new TimePickerBuilder(mContext, new OnTimeSelectListener() {
@Override @Override
public void onTimeSelect(Date date, View v) { public void onTimeSelect(Date date, View v) {
viewBinding.tvSelectTime.setText(ZYTimeUtils.getStrTimeData_H_M(date)); //用于提交接口
if(weekList != null){ mConfigEntity.getDetails().get(position).setStartTime(ZYTimeUtils.getStrTimeData_H_M(date));
String startTime = ZYTimeUtils.getStrTimeData_H_M(date).trim(); mWeekAdapter.notifyItemChanged(position);
weekList.get(0).getWashCycleList().get(mWeekAdapter.getmPos()).setTime(startTime);
}
} }
}).setType(times) }).setType(times)
.setCancelColor(mContext.getColor(R.color.color_999999)) .setCancelColor(mContext.getColor(R.color.color_999999))
@@ -116,25 +239,155 @@ public class WaterConfigFragment extends BaseFragment<WaterConfigFragmentLayoutB
.setTextColorCenter(mContext.getColor(R.color.color_zhu)) .setTextColorCenter(mContext.getColor(R.color.color_zhu))
.build(); .build();
pvTime.show(); pvTime.show();
break; }
case R.id.tv_commit: private void setClick(View view) {
List<WaterPlanWeekEntity.DeviceEntity> list = getSelectedDevices(); view.setOnClickListener(this::onClick);
}
/**
* 比较本地配置和远程配置是否有变化
* @return true 表示有变化false 表示无变化
*/
public boolean isConfigChanged() {
if (mRemoteConfigEntity == null || mRemoteConfigEntity.getDetails() == null) {
return true;
}
// 比对排程名称
if (!equalsString(mConfigEntity.getName(), mRemoteConfigEntity.getName())) {
return true;
}
List<WaterPlanWeekEntity.DetailsBean> localDetails = mConfigEntity.getDetails();
List<WaterPlanWeekEntity.DetailsBean> remoteDetails = mRemoteConfigEntity.getDetails();
for (int i = 0; i < localDetails.size(); i++) {
WaterPlanWeekEntity.DetailsBean local = localDetails.get(i);
WaterPlanWeekEntity.DetailsBean remote = remoteDetails.get(i);
// 勾选状态下对比状态、时间、时长
if ("1".equals(local.getStatus())) {
if (!equalsString(local.getStatus(), remote.getStatus())
|| !equalsString(local.getStartTime(), ZYTimeUtils.formatHHmm(remote.getStartTime()))
|| local.getDurationMin() != remote.getDurationMin()) {
return true;
}
} else {
// 未勾选状态下只对比勾选状态,不关心时间/时长
if (!equalsString(local.getStatus(), remote.getStatus())) {
return true;
}
}
}
return false;
}
private boolean equalsString(String s1, String s2) {
if (s1 == null && s2 == null) return true;
if (s1 == null || s2 == null) return false;
return s1.equals(s2);
}
/**
* 检查配置信息是否完成
* @return
*/
public boolean checkConfigFinish() {
if(TextUtils.isEmpty(viewBinding.etPlanName.getText().toString())){
ToastUtil.showShort(mContext,getString(R.string.plan_name_text_empty_hint));
return false;
}
List<WaterPlanWeekEntity.DetailsBean> list = mConfigEntity.getDetails();
//是否勾选了排程日期
boolean isSelectOne = false;
if(list != null){ if(list != null){
for(WaterPlanWeekEntity.DetailsBean bean : list){
if(bean.getStatus().equals("1")){
isSelectOne = true;
}
}
}
if(!isSelectOne){
ToastUtil.showShort(mContext,getString(R.string.plan_week_empty_hint));
return false;
}
//是否配置了排程日期的时间
boolean isPlanConfig = false;
for(WaterPlanWeekEntity.DetailsBean bean : list){
if(bean.getStatus().equals("1")){
if((TextUtils.isEmpty(bean.getStartTime()) ||
bean.getDurationMin() == 0)){
ToastUtil.showShort(mContext,"请完成" + bean.getWeekName() + "的时间配置");
return false;
} }
break;
} }
} }
return true;
}
private List<WaterPlanWeekEntity.DeviceEntity> getSelectedDevices() { @Override
public void getWaterConfigListSuccess(List<WaterPlanWeekEntity> list,int total) {
}
@Override
public void saveConfigSuccess(WaterPlanWeekEntity entity) {
ToastUtil.showShort(mContext, "排程新增成功");
isConfigSave = true;
// 把接口返回的 ID 设置到 mConfigEntity便于后续更新操作
mConfigEntity.setId(entity.getId());
// 把 details 中每个 bean 的 id 也设置到 mConfigEntity便于后续更新操作
if (entity.getDetails() != null && mConfigEntity.getDetails() != null) {
for (int i = 0; i < entity.getDetails().size() && i < mConfigEntity.getDetails().size(); i++) {
mConfigEntity.getDetails().get(i).setId(entity.getDetails().get(i).getId());
}
}
//接口请求之后返回的数据,方便后面做对比
mRemoteConfigEntity = entity;
if (getActivity() instanceof AddWaterPlanActivity) { if (getActivity() instanceof AddWaterPlanActivity) {
return ((AddWaterPlanActivity) getActivity()).getSelectedDevices(); ((AddWaterPlanActivity) getActivity()).onConfigSaved(entity);
} }
return new ArrayList<>();
} }
/**
* 更新排程成功
* @param entity
*/
@Override
public void updateConfigSuccess(WaterPlanWeekEntity entity) {
ToastUtil.showShort(mContext, "排程更新成功");
mRemoteConfigEntity = entity;
}
@Override
public void updatePlanStatusSuccess(BaseBean bean, String status) {
}
@Override
public void getPlanDetailInfo(WaterPlanWeekEntity entity) {
}
@Override
public void getPlanBindDeviceList(WaterDeviceEntity bean) {
}
@Override
public void planBindDeviceSuccess(BaseBean bean) {
}
@Override
public void deletePlanSuccess(BaseBean bean) {
}
@Override
public void planUnbindDeviceSuccess(BaseBean bean, int position) {
}
@Override @Override
public WaterPlanPresenter createPresenter() { public WaterPlanPresenter createPresenter() {
return new WaterPlanPresenter(new WaterPlanImpl()); return new WaterPlanPresenter(new WaterPlanImpl());
@@ -154,4 +407,6 @@ public class WaterConfigFragment extends BaseFragment<WaterConfigFragmentLayoutB
public void logOut(BaseBean bean) { public void logOut(BaseBean bean) {
} }
} }

View File

@@ -0,0 +1,715 @@
package com.ckkj.water.plan;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView;
import com.bigkoo.pickerview.builder.TimePickerBuilder;
import com.bigkoo.pickerview.listener.OnTimeSelectListener;
import com.bigkoo.pickerview.view.TimePickerView;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.databinding.WaterConfigFragmentLayoutBinding;
import com.ckkj.water.databinding.WaterConfigFragmentLayoutCopyBinding;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plan.adapter.WaterPlanTimeDataAdapter;
import com.ckkj.water.plan.adapter.WaterPlanWeekAdapter;
import com.ckkj.water.plan.adapter.WaterPlanWeekAdapter_copy;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.plan.mvp.WaterPlanContract;
import com.ckkj.water.plan.mvp.WaterPlanImpl;
import com.ckkj.water.plan.mvp.WaterPlanPresenter;
import com.ckkj.water.utils.show.ToastUtil;
import com.ckkj.water.utils.time.ZYTimeUtils;
import com.google.gson.Gson;
import com.yanzhenjie.recyclerview.OnItemMenuClickListener;
import com.yanzhenjie.recyclerview.SwipeMenu;
import com.yanzhenjie.recyclerview.SwipeMenuBridge;
import com.yanzhenjie.recyclerview.SwipeMenuCreator;
import com.yanzhenjie.recyclerview.SwipeMenuItem;
import com.yanzhenjie.recyclerview.SwipeRecyclerView;
import com.yanzhenjie.recyclerview.widget.DefaultItemDecoration;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class WaterConfigFragment_copy extends BaseFragment<WaterConfigFragmentLayoutCopyBinding, WaterPlanPresenter>
implements WaterPlanContract.WaterPlanView {
//本地新增排程时的实体
private WaterPlanWeekEntity mLocalEntity;
//新增之后返回的实体
private WaterPlanWeekEntity mRemoteEntity;
private List<WaterPlanWeekEntity.DetailsBean> weekList = new ArrayList<>();
private List<WaterPlanWeekEntity.TimeDataBean> timeList = new ArrayList<>();
private WaterPlanWeekAdapter_copy mWeekAdapter;
private WaterPlanTimeDataAdapter mTimeAdapter;
private RecyclerView.ItemDecoration itemDecoration;
private boolean isConfigSubmitted = false;
//当下是否编辑模式
private boolean mIsEditMode = false;
@Override
public void initData(Bundle state) {
// 设置菜单创建器。
viewBinding.rvTimes.setSwipeMenuCreator(mSwipeMenuCreator);
viewBinding.rvTimes.setOnItemMenuClickListener(mItemMenuClickListener);
itemDecoration = new DefaultItemDecoration
(mContext.getColor(R.color.transparent),20,40);
viewBinding.rvTimes.addItemDecoration(itemDecoration);
List<WaterPlanWeekEntity.DetailsBean> list = new ArrayList<>();
for(int i = 0; i < 7; i++){
WaterPlanWeekEntity.DetailsBean bean = new WaterPlanWeekEntity.DetailsBean();
WaterPlanWeekEntity.TimeDataBean timeData = new WaterPlanWeekEntity.TimeDataBean();
List<WaterPlanWeekEntity.TimeDataBean> timeDataList = new ArrayList<>();
timeDataList.add(timeData);
bean.setTimeData(timeDataList);
bean.setWeekday(i + 1);
bean.setStatus("1");
bean.setWeekName(ZYTimeUtils.getWeekName(i));
bean.setTriggerType("0");
list.add(bean);
}
weekList = list;
//这里先处理新增,后面再处理编辑
mLocalEntity = new WaterPlanWeekEntity();
mLocalEntity.setStatus("1");
mLocalEntity.setDetails(weekList);
//顶部周一、周二。。。。。
mWeekAdapter = new WaterPlanWeekAdapter_copy(mContext, R.layout.plan_period_item,list);
viewBinding.rvWeek.setAdapter(mWeekAdapter);
//周期对应的 时间配置
List<WaterPlanWeekEntity.TimeDataBean> timeList = weekList.get(0).getTimeData();
mTimeAdapter = new WaterPlanTimeDataAdapter(mContext,R.layout.include_plan_time_item_layout,timeList);
viewBinding.rvTimes.setAdapter(mTimeAdapter);
initListener();
}
private void initListener() {
setClick(viewBinding.tvCommit);
setClick(viewBinding.imgAdd);
setClick(viewBinding.switchButton);
//头部 周一~周日
mWeekAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
mWeekAdapter.setSelPos(position);
List<WaterPlanWeekEntity.TimeDataBean> timeList = weekList.get(position).getTimeData();
mTimeAdapter.setNewData(timeList);
viewBinding.switchButton.setChecked(weekList.get(position).getStatus().equals("1"));
}
});
//周期对应的 时间配置
mTimeAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
switch (view.getId()){
case R.id.tv_select_time:
selectStartTime(position);
break;
case R.id.tv_plan_duration:
inputDuration(position);
break;
}
}
});
//输入框监听
viewBinding.editPlanName.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
String planName = "";
if(!TextUtils.isEmpty(s.toString())){
planName = s.toString();
}
mLocalEntity.setName(planName);
}
});
}
private void setClick(View view) {
view.setOnClickListener(this::onClick);
}
public void onClick(View v){
int selPos = mWeekAdapter.getmPos();
switch (v.getId()){
case R.id.img_add:
isConfigSubmitted = false;
WaterPlanWeekEntity.TimeDataBean timeDataAdd = new WaterPlanWeekEntity.TimeDataBean();
weekList.get(selPos).getTimeData().add(timeDataAdd);
mTimeAdapter.notifyItemInserted(weekList.get(selPos).getTimeData().size() - 1);
break;
case R.id.switch_button:
if(weekList.get(selPos).getStatus().equals("0")){
weekList.get(selPos).setStatus("1");
viewBinding.switchButton.setChecked(true);
}else{
weekList.get(selPos).setStatus("0");
viewBinding.switchButton.setChecked(false);
}
break;
case R.id.tv_commit:
// 如果已经保存过mRemoteEntity 不为空),则走更新逻辑;否则走新增逻辑
if (mRemoteEntity != null) {
updateConfig();
} else {
validateAndSave();
}
break;
}
}
public boolean isConfigSubmitted() {
return isConfigSubmitted;
}
/**
* 获取当前排程名称
* @return 排程名称
*/
public String getPlanName() {
if (mLocalEntity != null) {
return mLocalEntity.getName();
}
return "";
}
/**
* 检查是否至少配置了一天的时间
* @return true表示有时间配置false表示没有配置任何时间
*/
public boolean hasTimeConfig() {
for (WaterPlanWeekEntity.DetailsBean dayBean : weekList) {
List<WaterPlanWeekEntity.TimeDataBean> timeDataList = dayBean.getTimeData();
if (timeDataList != null && !timeDataList.isEmpty()) {
for (WaterPlanWeekEntity.TimeDataBean timeData : timeDataList) {
if (!TextUtils.isEmpty(timeData.getStartTime()) && timeData.getDurationMin() > 0) {
return true;
}
}
}
}
return false;
}
/**
* 校验并保存配置(供外部调用)
* @return true表示校验通过并已提交保存false表示校验失败
*/
public boolean commitConfig() {
return validateAndSave();
}
/**
* 更新配置(用于数据变更后调用)
* @return true表示校验通过并已提交更新false表示校验失败
*/
public boolean updateConfig() {
if (!validateConfig()) {
return false;
}
// 调用更新接口
if(mLocalEntity != null){
mPresenter.updateConfig(mLocalEntity);
}
return true;
}
/**
* 设置编辑模式的排程数据
* @param entity 从详情页传来的排程数据
*/
public void setEditEntity(WaterPlanWeekEntity entity) {
if (entity == null) {
return;
}
mIsEditMode = true;
// 深拷贝数据到 mConfigEntity用于本地编辑
mLocalEntity = cloneEntity(entity);
// 保存远程原始数据,用于后续变化检测
mRemoteEntity = entity;
isConfigSubmitted = true;
// 初始化 UI
viewBinding.editPlanName.setText(entity.getName());
// 更新周配置列表的显示,使用 mConfigEntity.getDetails() 保证数据一致
if (mLocalEntity.getDetails() != null) {
weekList = mLocalEntity.getDetails();
mWeekAdapter.setNewData(mLocalEntity.getDetails());
mTimeAdapter.setNewData(weekList.get(mWeekAdapter.getmPos()).getTimeData());
}
}
/**
* 深拷贝 WaterPlanWeekEntity
*/
private WaterPlanWeekEntity cloneEntity(WaterPlanWeekEntity source) {
if (source == null) {
return null;
}
WaterPlanWeekEntity target = new WaterPlanWeekEntity();
target.setId(source.getId());
target.setName(source.getName());
target.setStatus(source.getStatus());
if (source.getDetails() != null) {
List<WaterPlanWeekEntity.DetailsBean> detailsList = new ArrayList<>();
for (WaterPlanWeekEntity.DetailsBean bean : source.getDetails()) {
WaterPlanWeekEntity.DetailsBean newBean = new WaterPlanWeekEntity.DetailsBean();
List<WaterPlanWeekEntity.TimeDataBean> timeDataList = new ArrayList<>();
for(WaterPlanWeekEntity.TimeDataBean timeDataBean : bean.getTimeData()){
WaterPlanWeekEntity.TimeDataBean newTimeDataBean = new WaterPlanWeekEntity.TimeDataBean();
newTimeDataBean.setStartTime(ZYTimeUtils.formatHHmm(timeDataBean.getStartTime()));
newTimeDataBean.setDurationMin(timeDataBean.getDurationMin());
timeDataList.add(newTimeDataBean);
}
newBean.setTimeData(timeDataList);
newBean.setId(bean.getId());
newBean.setWeekday(bean.getWeekday());
newBean.setWeekName(ZYTimeUtils.getWeekName(bean.getWeekday() - 1));
newBean.setStatus(bean.getStatus());
detailsList.add(newBean);
}
target.setDetails(detailsList);
}
return target;
}
/**
* 校验配置
* @return true表示校验通过false表示校验失败
*/
private boolean validateConfig() {
if(TextUtils.isEmpty(viewBinding.editPlanName.getText().toString())){
ToastUtil.showShort(mContext,getString(R.string.plan_name_text_empty_hint));
return false;
}
// 检查七天的所有时间配置是否全部为空
boolean allTimeEmpty = true;
for (WaterPlanWeekEntity.DetailsBean dayBean : weekList) {
List<WaterPlanWeekEntity.TimeDataBean> timeDataList = dayBean.getTimeData();
if (timeDataList != null && !timeDataList.isEmpty()) {
for (WaterPlanWeekEntity.TimeDataBean timeData : timeDataList) {
if (!TextUtils.isEmpty(timeData.getStartTime()) && timeData.getDurationMin() > 0) {
allTimeEmpty = false;
break;
}
}
}
if (!allTimeEmpty) break;
}
if (allTimeEmpty) {
ToastUtil.showShort(mContext, "请至少配置一天的时间");
return false;
}
// 校验每一天内的时间是否有冲突
String conflictMsg = checkTimeConflict();
if (conflictMsg != null) {
ToastUtil.showShort(mContext, conflictMsg);
return false;
}
return true;
}
/**
* 校验配置并保存(新增)
* @return true表示校验通过并已提交保存false表示校验失败
*/
private boolean validateAndSave() {
if (!validateConfig()) {
return false;
}
if(mLocalEntity != null){
mPresenter.saveConfig(mLocalEntity);
return true;
}
return false;
}
/**
* 获取远程实体用于AddWaterPlanActivity比对
* @return mRemoteEntity
*/
public WaterPlanWeekEntity getRemoteEntity() {
return mRemoteEntity;
}
/**
* 获取本地实体用于AddWaterPlanActivity比对
* @return mLocalEntity
*/
public WaterPlanWeekEntity getLocalEntity() {
return mLocalEntity;
}
/**
* 检查本地数据是否与远程数据有变更
* @return true表示有变更false表示无变更
*/
public boolean hasDataChanged() {
if (mRemoteEntity == null || mLocalEntity == null) {
return false;
}
// 比对排程名称
String localName = mLocalEntity.getName();
String remoteName = mRemoteEntity.getName();
if (!TextUtils.isEmpty(localName) && !localName.equals(remoteName)) {
return true;
}
// 比对排程状态
String localStatus = mLocalEntity.getStatus();
String remoteStatus = mRemoteEntity.getStatus();
if (!TextUtils.isEmpty(localStatus) && !localStatus.equals(remoteStatus)) {
return true;
}
// 比对 details 列表
List<WaterPlanWeekEntity.DetailsBean> localDetails = mLocalEntity.getDetails();
List<WaterPlanWeekEntity.DetailsBean> remoteDetails = mRemoteEntity.getDetails();
if (localDetails == null && remoteDetails == null) {
return false;
}
if (localDetails == null || remoteDetails == null) {
return true;
}
if (localDetails.size() != remoteDetails.size()) {
return true;
}
// 逐个比对每个 DetailsBean
for (int i = 0; i < localDetails.size(); i++) {
WaterPlanWeekEntity.DetailsBean localDetail = localDetails.get(i);
WaterPlanWeekEntity.DetailsBean remoteDetail = remoteDetails.get(i);
// 比对 status
String localDetailStatus = localDetail.getStatus();
String remoteDetailStatus = remoteDetail.getStatus();
if (!TextUtils.isEmpty(localDetailStatus) && !localDetailStatus.equals(remoteDetailStatus)) {
return true;
}
// 比对 triggerType
String localTriggerType = localDetail.getTriggerType();
String remoteTriggerType = remoteDetail.getTriggerType();
if (!TextUtils.isEmpty(localTriggerType) && !localTriggerType.equals(remoteTriggerType)) {
return true;
}
// 比对 timeData 列表
List<WaterPlanWeekEntity.TimeDataBean> localTimeData = localDetail.getTimeData();
List<WaterPlanWeekEntity.TimeDataBean> remoteTimeData = remoteDetail.getTimeData();
if (localTimeData == null && remoteTimeData == null) {
continue;
}
if (localTimeData == null || remoteTimeData == null) {
return true;
}
if (localTimeData.size() != remoteTimeData.size()) {
return true;
}
// 逐个比对 TimeDataBean
for (int j = 0; j < localTimeData.size(); j++) {
WaterPlanWeekEntity.TimeDataBean localTime = localTimeData.get(j);
WaterPlanWeekEntity.TimeDataBean remoteTime = remoteTimeData.get(j);
// 比对 startTime
String localStartTime = localTime.getStartTime();
String remoteStartTime = remoteTime.getStartTime();
if (!TextUtils.isEmpty(localStartTime) && !localStartTime.equals(remoteStartTime)) {
return true;
}
// 比对 durationMin
if (localTime.getDurationMin() != remoteTime.getDurationMin()) {
return true;
}
}
}
return false;
}
/**
* 校验每一天内的时间配置是否有冲突
* @return null表示无冲突返回具体提示信息表示有冲突
*/
private String checkTimeConflict() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm", Locale.getDefault());
for (int dayIndex = 0; dayIndex < weekList.size(); dayIndex++) {
WaterPlanWeekEntity.DetailsBean dayBean = weekList.get(dayIndex);
List<WaterPlanWeekEntity.TimeDataBean> timeDataList = dayBean.getTimeData();
if (timeDataList == null || timeDataList.isEmpty()) {
continue;
}
// 收集该天所有有效的时间段(开始时间 + 结束时间)
List<long[]> periods = new ArrayList<>();
for (WaterPlanWeekEntity.TimeDataBean timeData : timeDataList) {
if (TextUtils.isEmpty(timeData.getStartTime()) || timeData.getDurationMin() <= 0) {
continue;
}
try {
Date startDate = sdf.parse(timeData.getStartTime());
long startMinutes = startDate.getHours() * 60 + startDate.getMinutes();
long endMinutes = startMinutes + timeData.getDurationMin();
periods.add(new long[]{startMinutes, endMinutes});
} catch (Exception e) {
e.printStackTrace();
}
}
// 检查是否有冲突
for (int i = 0; i < periods.size(); i++) {
for (int j = i + 1; j < periods.size(); j++) {
long[] p1 = periods.get(i);
long[] p2 = periods.get(j);
// 冲突条件:一个段的开始时间在另一个段的结束时间之前(即有重叠)
// 不冲突p1.end <= p2.start 或 p2.end <= p1.start
if (!(p1[1] <= p2[0] || p2[1] <= p1[0])) {
String dayName = dayBean.getWeekName();
return dayName + "的时间配置存在冲突,请调整";
}
}
}
}
return null;
}
/**
* 选择开始时间
* @param position
*/
private void selectStartTime(int position) {
boolean times[] = {false, false, false, true, true, false};
//时间选择器
TimePickerView pvTime = new TimePickerBuilder(mContext, new OnTimeSelectListener() {
@Override
public void onTimeSelect(Date date, View v) {
//用于提交接口
weekList.get(mWeekAdapter.getmPos()).getTimeData().get(position).
setStartTime(ZYTimeUtils.getStrTimeData_H_M(date));
mTimeAdapter.notifyItemChanged(position);
}
}).setType(times)
.setCancelColor(mContext.getColor(R.color.color_999999))
.setSubmitColor(mContext.getColor(R.color.color_zhu))
.setTextColorCenter(mContext.getColor(R.color.color_zhu))
.build();
pvTime.show();
}
/**
* 输入浇水时间
* @param position
*/
private void inputDuration(int position) {
WaterPlanWeekEntity.TimeDataBean timeData = weekList.get(mWeekAdapter.getmPos()).getTimeData().get(position);
showEditDialog(getString(R.string.device_work_times_title),
getString(R.string.input_water_plan_time),
timeData.getDurationMin() == 0 ? "" : timeData.getDurationMin() + "",
true,
getString(R.string.cancel_text),
getString(R.string.confirm_text),
BaseFragment.INPUT_TYPE_NUMBER,
new BaseActivity.OnDialogClick() {
@Override
public void onCancelClick() {}
@Override
public void onConfirmClisk() {}
@Override
public void onConfirmClisk(String content) {
if (Integer.parseInt(content) <= 0) {
ToastUtil.showShort(mContext, getString(R.string.input_water_plan_time_error));
return;
}
timeData.setDurationMin(Integer.parseInt(content));
mTimeAdapter.notifyItemChanged(position);
}
@Override
public void onView1Click() {
}
});
}
/**
* 侧滑相关
*/
// 创建菜单:
SwipeMenuCreator mSwipeMenuCreator = new SwipeMenuCreator() {
@Override
public void onCreateMenu(SwipeMenu leftMenu, SwipeMenu rightMenu, int position) {
SwipeMenuItem deleteItem = new SwipeMenuItem(mContext);
deleteItem.setBackground(mContext.getResources().getDrawable(R.drawable.shape_item_delete_bg));
deleteItem.setText("删除");
deleteItem.setTextColor(mContext.getResources().getColor(R.color.white));
deleteItem.setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
deleteItem.setWidth((int) mContext.getResources().getDimension(R.dimen.dp_90));
// 各种文字和图标属性设置。
rightMenu.addMenuItem(deleteItem); // 在Item右侧添加一个菜单。
}
};
// 菜单点击监听。
OnItemMenuClickListener mItemMenuClickListener = new OnItemMenuClickListener() {
@Override
public void onItemClick(SwipeMenuBridge menuBridge, int position) {
// 先关闭菜单
menuBridge.closeMenu();
// 左/右菜单
int direction = menuBridge.getDirection();
// 点击的是第几个菜单
int menuPosition = menuBridge.getPosition();
// 只处理右侧菜单
if (direction == SwipeRecyclerView.RIGHT_DIRECTION) {
if (menuPosition == 0) {
weekList.get(mWeekAdapter.getmPos()).getTimeData().remove(position);
if(mTimeAdapter != null){
mTimeAdapter.notifyItemRemoved(position);
}
}
}
}
};
/**
* 新增
* @param entity
*/
@Override
public void saveConfigSuccess(WaterPlanWeekEntity entity) {
ToastUtil.showShort(mContext, "排程新增成功");
isConfigSubmitted = true;
// 把接口返回的 ID 设置到 mConfigEntity便于后续更新操作
mLocalEntity.setId(entity.getId());
// 把 details 中每个 bean 的 id 也设置到 mConfigEntity便于后续更新操作
if (entity.getDetails() != null && mLocalEntity.getDetails() != null) {
for (int i = 0; i < entity.getDetails().size() && i < mLocalEntity.getDetails().size(); i++) {
mLocalEntity.getDetails().get(i).setId(entity.getDetails().get(i).getId());
mLocalEntity.getDetails().get(i).setStatus(entity.getDetails().get(i).getStatus());
}
}
//接口请求之后返回的数据,方便后面做对比
mRemoteEntity = entity;
if (getActivity() instanceof AddWaterPlanActivity) {
((AddWaterPlanActivity) getActivity()).onConfigSaved(entity);
}
}
/**
* 更新
* @param entity
*/
@Override
public void updateConfigSuccess(WaterPlanWeekEntity entity) {
ToastUtil.showShort(mContext, "排程更新成功");
mRemoteEntity = entity;
}
// private List<WaterPlanWeekEntity.DeviceEntity> getSelectedDevices() {
// if (getActivity() instanceof AddWaterPlanActivity) {
// return ((AddWaterPlanActivity) getActivity()).getSelectedDevices();
// }
// return new ArrayList<>();
// }
@Override
public WaterPlanPresenter createPresenter() {
return new WaterPlanPresenter(new WaterPlanImpl());
}
@Override
public void onNetChange(int netModel) {
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
@Override
public void getWaterConfigListSuccess(List<WaterPlanWeekEntity> list, int total) {
}
@Override
public void updatePlanStatusSuccess(BaseBean bean, String status) {
}
@Override
public void getPlanDetailInfo(WaterPlanWeekEntity entity) {
}
@Override
public void getPlanBindDeviceList(WaterDeviceEntity bean) {
}
@Override
public void planBindDeviceSuccess(BaseBean bean) {
}
@Override
public void deletePlanSuccess(BaseBean bean) {
}
@Override
public void planUnbindDeviceSuccess(BaseBean bean, int position) {
}
}

View File

@@ -8,31 +8,37 @@ import android.view.View;
import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.BaseQuickAdapter;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.base.BaseFragment; import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.custom.view.CustomRefreshHeader;
import com.ckkj.water.databinding.WaterPlanFragmentBinding; import com.ckkj.water.databinding.WaterPlanFragmentBinding;
import com.ckkj.water.main.activity.MainActivity; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean; import com.ckkj.water.network.BaseBean;
//import com.ckkj.water.plan.adapter.WaterPlanListAdapter;
import com.ckkj.water.plan.adapter.WaterPlanListAdapter; import com.ckkj.water.plan.adapter.WaterPlanListAdapter;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity; import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.plan.mvp.WaterPlanContract; import com.ckkj.water.plan.mvp.WaterPlanContract;
import com.ckkj.water.plan.mvp.WaterPlanImpl; import com.ckkj.water.plan.mvp.WaterPlanImpl;
import com.ckkj.water.plan.mvp.WaterPlanPresenter; import com.ckkj.water.plan.mvp.WaterPlanPresenter;
import com.ckkj.water.utils.manager.ThemeManager; import com.ckkj.water.utils.manager.ThemeManager;
import com.ckkj.water.utils.show.ToastUtil;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.gyf.immersionbar.ImmersionBar; import com.gyf.immersionbar.ImmersionBar;
import com.scwang.smart.refresh.footer.ClassicsFooter;
import com.scwang.smart.refresh.layout.api.RefreshHeader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class WaterPlanFragment extends BaseFragment<WaterPlanFragmentBinding, WaterPlanPresenter> public class WaterPlanFragment extends BaseFragment<WaterPlanFragmentBinding, WaterPlanPresenter>
implements WaterPlanContract.WaterPlanView { implements WaterPlanContract.WaterPlanView {
private List<WaterPlanWeekEntity.DeviceEntity> mDevList = new ArrayList<>(); private List<WaterPlanWeekEntity> mPlanList = new ArrayList<>();
private WaterPlanListAdapter mAdapter; private WaterPlanListAdapter mAdapter;
private int mCurrentPage = 1;
@Override @Override
public void initData(Bundle state) { public void initData(Bundle state) {
String jsonContent = getString(R.string.plan_water_entity_json); String jsonContent = getString(R.string.plan_water_entity_json);
WaterPlanWeekEntity entity = new Gson().fromJson(jsonContent, WaterPlanWeekEntity.class); WaterPlanWeekEntity entity = new Gson().fromJson(jsonContent, WaterPlanWeekEntity.class);
mDevList = entity.getDeviceList(); // mDevList = entity.getDeviceList();
ImmersionBar.with(mContext) ImmersionBar.with(mContext)
.statusBarColor(R.color.mainBackgroundColor) .statusBarColor(R.color.mainBackgroundColor)
@@ -42,17 +48,37 @@ public class WaterPlanFragment extends BaseFragment<WaterPlanFragmentBinding, Wa
viewBinding.includedTitle.imgBack.setVisibility(INVISIBLE); viewBinding.includedTitle.imgBack.setVisibility(INVISIBLE);
viewBinding.includedTitle.tvTitle.setText(getString(R.string.plan_title)); viewBinding.includedTitle.tvTitle.setText(getString(R.string.plan_title));
initListener(); initListener();
mAdapter = new WaterPlanListAdapter(mContext,R.layout.water_plan_list_item,mPlanList);
mAdapter = new WaterPlanListAdapter(mContext,R.layout.water_plan_list_item,mDevList);
viewBinding.rvPlans.setAdapter(mAdapter); viewBinding.rvPlans.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() { mAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override @Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) { public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
goTo(mContext, PlanDetailActivity.class,null); Bundle bundle = new Bundle();
bundle.putSerializable("plan_entity",mPlanList.get(position));
goTo(mContext, PlanDetailActivity.class,bundle);
} }
}); });
RefreshHeader header = new CustomRefreshHeader(mContext);
viewBinding.refresh.setRefreshHeader(header);
viewBinding.refresh.setRefreshFooter(new ClassicsFooter(mContext));
viewBinding.refresh.setOnRefreshListener(layout -> {
mCurrentPage = 1;
viewBinding.refresh.setNoMoreData(false);
mPresenter.getWaterPlanList(mCurrentPage);
});
viewBinding.refresh.setOnLoadMoreListener(layout -> {
mCurrentPage++;
mPresenter.getWaterPlanList(mCurrentPage);
});
} }
@Override
protected void onResumeInitData() {
super.onResumeInitData();
showLoadingDialog();
mPresenter.getWaterPlanList(mCurrentPage);
}
private void initListener() { private void initListener() {
setClick(viewBinding.tvAdd); setClick(viewBinding.tvAdd);
@@ -70,6 +96,42 @@ public class WaterPlanFragment extends BaseFragment<WaterPlanFragmentBinding, Wa
} }
} }
@Override
public void getWaterConfigListSuccess(List<WaterPlanWeekEntity> list,int total) {
hideDialogLoading();
List<WaterPlanWeekEntity> pageList = list == null ? new ArrayList<>() : list;
if (mCurrentPage == 1) {
viewBinding.refresh.finishRefresh(300);
mPlanList.clear(); // 只在刷新时清除
mPlanList = pageList;
} else {
viewBinding.refresh.finishLoadMore(300);
mPlanList.addAll(pageList);
}
mAdapter.setNewData(mPlanList);
// 4. 判断是否还有更多数据
if (mAdapter.getItemCount() >= total || pageList.size() == 0) {
// 使用 post 延迟调用,避免内部状态冲突导致的循环调用
viewBinding.refresh.postDelayed(() -> viewBinding.refresh.setNoMoreData(true), 300);
viewBinding.relNoMore.setVisibility(View.VISIBLE); // 自定义底部提示"暂无更多数据"
} else {
viewBinding.refresh.setNoMoreData(false);
viewBinding.relNoMore.setVisibility(View.GONE);
}
// 5. 控制空布局和内容显示
if (mAdapter.getItemCount() != 0) {
viewBinding.refresh.setVisibility(View.VISIBLE);
viewBinding.relNoresult.setVisibility(View.GONE);
} else {
viewBinding.refresh.setVisibility(View.GONE);
viewBinding.relNoresult.setVisibility(View.VISIBLE);
}
}
@Override @Override
public WaterPlanPresenter createPresenter() { public WaterPlanPresenter createPresenter() {
return new WaterPlanPresenter(new WaterPlanImpl()); return new WaterPlanPresenter(new WaterPlanImpl());
@@ -82,11 +144,54 @@ public class WaterPlanFragment extends BaseFragment<WaterPlanFragmentBinding, Wa
@Override @Override
public void showError(String message) { public void showError(String message) {
hideDialogLoading();
ToastUtil.showShort(mContext,message);
} }
@Override @Override
public void logOut(BaseBean bean) { public void logOut(BaseBean bean) {
} }
@Override
public void saveConfigSuccess(WaterPlanWeekEntity entity) {
}
@Override
public void updateConfigSuccess(WaterPlanWeekEntity entity) {
}
@Override
public void updatePlanStatusSuccess(BaseBean bean, String status) {
}
@Override
public void getPlanDetailInfo(WaterPlanWeekEntity entity) {
}
@Override
public void getPlanBindDeviceList(WaterDeviceEntity bean) {
}
@Override
public void planBindDeviceSuccess(BaseBean bean) {
}
@Override
public void deletePlanSuccess(BaseBean bean) {
}
@Override
public void planUnbindDeviceSuccess(BaseBean bean, int position) {
}
} }

View File

@@ -8,26 +8,27 @@ import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder; import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity; import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
public class BindDeviceAdapter extends BaseQuickAdapter<WaterPlanWeekEntity.DeviceEntity, BaseViewHolder> { public class BindDeviceAdapter extends BaseQuickAdapter<WaterDeviceEntity.DeviceListBean, BaseViewHolder> {
private Context mContext; private Context mContext;
private Set<Integer> mSelectedPositions = new HashSet<>(); private Set<Integer> mSelectedPositions = new HashSet<>();
public BindDeviceAdapter(Context context, int layoutResId, @Nullable List<WaterPlanWeekEntity.DeviceEntity> data) { public BindDeviceAdapter(Context context, int layoutResId, @Nullable List<WaterDeviceEntity.DeviceListBean> data) {
super(layoutResId, data); super(layoutResId, data);
this.mContext = context; this.mContext = context;
} }
@Override @Override
protected void convert(BaseViewHolder helper, WaterPlanWeekEntity.DeviceEntity item) { protected void convert(BaseViewHolder helper, WaterDeviceEntity.DeviceListBean item) {
CheckBox checkBox = helper.getView(R.id.radio); CheckBox checkBox = helper.getView(R.id.radio);
helper.setText(R.id.tv_device_name, item.getDeviceName()); helper.setText(R.id.tv_device_name, item.getDeviceName());
helper.setText(R.id.tv_device_serial, item.getDeviceCode()); helper.setText(R.id.tv_device_serial, item.getDeviceSn());
checkBox.setChecked(mSelectedPositions.contains(helper.getLayoutPosition())); checkBox.setChecked(mSelectedPositions.contains(helper.getLayoutPosition()));
} }

View File

@@ -0,0 +1,32 @@
package com.ckkj.water.plan.adapter;
import android.content.Context;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2026/5/29
* @description TODO: 描述该类的作用
*/
public class PlanBoundDeviceAdapter extends BaseQuickAdapter<WaterDeviceEntity, BaseViewHolder> {
private Context mContext;
public PlanBoundDeviceAdapter(Context context,int layoutResId, @Nullable List<WaterDeviceEntity> data) {
super(layoutResId, data);
mContext = context;
}
@Override
protected void convert(BaseViewHolder helper, WaterDeviceEntity item) {
helper.setText(R.id.tv_device_name, item.getDeviceName());
helper.setText(R.id.tv_device_serial, item.getDeviceSn());
helper.addOnClickListener(R.id.img_delete);
}
}

View File

@@ -5,19 +5,20 @@ import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder; import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity; import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import java.util.List; import java.util.List;
public class PlanDetailDeviceAdapter extends BaseQuickAdapter<WaterPlanWeekEntity.DeviceEntity, BaseViewHolder> { public class PlanDetailDeviceAdapter extends BaseQuickAdapter<WaterDeviceEntity, BaseViewHolder> {
public PlanDetailDeviceAdapter(int layoutResId, @Nullable List<WaterPlanWeekEntity.DeviceEntity> data) { public PlanDetailDeviceAdapter(int layoutResId, @Nullable List<WaterDeviceEntity> data) {
super(layoutResId, data); super(layoutResId, data);
} }
@Override @Override
protected void convert(BaseViewHolder helper, WaterPlanWeekEntity.DeviceEntity item) { protected void convert(BaseViewHolder helper, WaterDeviceEntity item) {
helper.setText(R.id.tv_device_name,item.getDeviceName()); helper.setText(R.id.tv_device_name,item.getDeviceName());
helper.setText(R.id.tv_device_serial,item.getDeviceCode()); helper.setText(R.id.tv_device_serial,item.getDeviceSn());
} }
} }

View File

@@ -1,24 +1,29 @@
package com.ckkj.water.plan.adapter; package com.ckkj.water.plan.adapter;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import android.widget.TextView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder; import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity; import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.utils.time.ZYTimeUtils;
import java.util.List; import java.util.List;
public class PlanDetailTimeAdapter extends BaseQuickAdapter<WaterPlanWeekEntity.WashCycleEntity, BaseViewHolder> { public class PlanDetailTimeAdapter extends BaseQuickAdapter<WaterPlanWeekEntity.TimeDataBean, BaseViewHolder> {
public PlanDetailTimeAdapter(int layoutResId, @Nullable List<WaterPlanWeekEntity.WashCycleEntity> data) { public PlanDetailTimeAdapter(int layoutResId, @Nullable List<WaterPlanWeekEntity.TimeDataBean> data) {
super(layoutResId, data); super(layoutResId, data);
} }
@Override @Override
protected void convert(BaseViewHolder helper, WaterPlanWeekEntity.WashCycleEntity item) { protected void convert(BaseViewHolder helper, WaterPlanWeekEntity.TimeDataBean item) {
helper.setText(R.id.tv_week,item.getWeek()); helper.setText(R.id.tv_start_time,ZYTimeUtils.formatHHmm(item.getStartTime()));
helper.setText(R.id.tv_start_time,item.getTime()); helper.setText(R.id.tv_duration,item.getDurationMin() + "min");
helper.setText(R.id.tv_duration,item.getDuration());
} }
} }

View File

@@ -0,0 +1,50 @@
package com.ckkj.water.plan.adapter;
import android.graphics.Rect;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import java.util.List;
public class PlanWeekDaysAdapter extends BaseQuickAdapter<WaterPlanWeekEntity.DetailsBean, BaseViewHolder> {
public PlanWeekDaysAdapter(int layoutResId, @Nullable List<WaterPlanWeekEntity.DetailsBean> data) {
super(layoutResId, data);
}
@Override
protected void convert(BaseViewHolder helper, WaterPlanWeekEntity.DetailsBean item) {
helper.setText(R.id.tv_week_name, item.getWeekName());
RecyclerView rvWeekDatas = helper.getView(R.id.rv_plan_detail_times);
PlanDetailTimeAdapter adapter = new PlanDetailTimeAdapter(R.layout.plan_detail_time_item, item.getTimeData());
rvWeekDatas.setAdapter(adapter);
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
// 添加透明色分割线高度10px
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
if (position > 0) {
outRect.top = (int) (10 * view.getContext().getResources().getDisplayMetrics().density);
}
}
@Override
public void onDraw(android.graphics.Canvas c, RecyclerView parent, RecyclerView.State state) {
// 不绘制任何内容,保持透明
}
});
}
}

View File

@@ -14,18 +14,18 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
public class WaterPlanListAdapter extends BaseQuickAdapter<WaterPlanWeekEntity.DeviceEntity, BaseViewHolder> { public class WaterPlanListAdapter extends BaseQuickAdapter<WaterPlanWeekEntity, BaseViewHolder> {
private Context mContext; private Context mContext;
public WaterPlanListAdapter(Context context, int layoutResId, @Nullable List<WaterPlanWeekEntity.DeviceEntity> data) { public WaterPlanListAdapter(Context context, int layoutResId, @Nullable List<WaterPlanWeekEntity> data) {
super(layoutResId, data); super(layoutResId, data);
this.mContext = context; this.mContext = context;
} }
@Override @Override
protected void convert(BaseViewHolder helper, WaterPlanWeekEntity.DeviceEntity item) { protected void convert(BaseViewHolder helper, WaterPlanWeekEntity item) {
helper.setText(R.id.tv_device_name, item.getDeviceName()); helper.setText(R.id.tv_device_name, item.getName());
helper.setText(R.id.tv_device_serial, item.getDeviceCode()); helper.setText(R.id.tv_device_serial, item.getId());
} }

View File

@@ -0,0 +1,49 @@
package com.ckkj.water.plan.adapter;
import android.content.Context;
import android.text.TextUtils;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2026/5/28
* @description TODO: 描述该类的作用
*/
public class WaterPlanTimeDataAdapter extends BaseQuickAdapter<WaterPlanWeekEntity.TimeDataBean, BaseViewHolder> {
private Context mContext;
public WaterPlanTimeDataAdapter(Context context,int layoutResId, @Nullable List<WaterPlanWeekEntity.TimeDataBean> data) {
super(layoutResId, data);
mContext = context;
}
@Override
protected void convert(BaseViewHolder helper, WaterPlanWeekEntity.TimeDataBean item) {
TextView tvStartTime = helper.getView(R.id.tv_select_time);
TextView tvPlanDuration = helper.getView(R.id.tv_plan_duration);
if(!TextUtils.isEmpty(item.getStartTime())){
helper.setText(R.id.tv_select_time, item.getStartTime());
}else{
helper.setText(R.id.tv_select_time,"");
tvStartTime.setHint(mContext.getString(R.string.select_water_time));
}
if(item.getDurationMin() != 0){
helper.setText(R.id.tv_plan_duration,item.getDurationMin() + "");
}else{
helper.setText(R.id.tv_plan_duration,"");
tvPlanDuration.setHint(mContext.getString(R.string.input_water_plan_time));
}
helper.addOnClickListener(R.id.tv_select_time);
helper.addOnClickListener(R.id.tv_plan_duration);
}
}

View File

@@ -7,7 +7,9 @@ import static android.view.View.VISIBLE;
import android.content.Context; import android.content.Context;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.CheckBox;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@@ -15,40 +17,71 @@ import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder; import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R; import com.ckkj.water.R;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity; import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.utils.time.ZYTimeUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class WaterPlanWeekAdapter extends BaseQuickAdapter<WaterPlanWeekEntity.WashCycleEntity, BaseViewHolder> { public class WaterPlanWeekAdapter extends BaseQuickAdapter<WaterPlanWeekEntity.DetailsBean, BaseViewHolder> {
private List<WaterPlanWeekEntity.WashCycleEntity> mList = new ArrayList<>(); private List<WaterPlanWeekEntity.DetailsBean> mList = new ArrayList<>();
private Context mContext; private Context mContext;
private int mPos = 0; private int mPos = 0;
public WaterPlanWeekAdapter(Context context,int layoutResId, @Nullable List<WaterPlanWeekEntity.WashCycleEntity> data) { public WaterPlanWeekAdapter(Context context,int layoutResId, @Nullable List<WaterPlanWeekEntity.DetailsBean> data) {
super(layoutResId, data); super(layoutResId, data);
this.mContext = context; this.mContext = context;
this.mList = data; this.mList = data;
} }
@Override @Override
protected void convert(BaseViewHolder helper, WaterPlanWeekEntity.WashCycleEntity item) { protected void convert(BaseViewHolder helper, WaterPlanWeekEntity.DetailsBean item) {
helper.setText(R.id.tv_week,item.getWeek()); TextView tvStartTime = helper.getView(R.id.tv_select_time);
LinearLayout linearItem = helper.getView(R.id.linear_item); CheckBox checkBox = helper.getView(R.id.checkbox);
View viewStatus = helper.getView(R.id.view_status); TextView tvPlanDuration = helper.getView(R.id.tv_plan_duration);
if(helper.getLayoutPosition() == mPos){
linearItem.setBackground(mContext.getResources().getDrawable(R.drawable.shape_water_period_sel_bg));
viewStatus.setVisibility(VISIBLE); helper.setText(R.id.tv_week_name,item.getWeekName());
viewStatus.setBackground(mContext.getResources().getDrawable(R.drawable.shape_green_circle));
if(!TextUtils.isEmpty(item.getStartTime())){
helper.setText(R.id.tv_select_time, item.getStartTime());
}else{ }else{
linearItem.setBackground(null); helper.setText(R.id.tv_select_time,"");
if(!TextUtils.isEmpty(item.getTime()) && !TextUtils.isEmpty(item.getDuration())){ tvStartTime.setHint(mContext.getString(R.string.select_water_time));
viewStatus.setVisibility(VISIBLE); }
viewStatus.setBackground(mContext.getResources().getDrawable(R.drawable.shape_yellow_circle)); if(item.getDurationMin() != 0){
helper.setText(R.id.tv_plan_duration,item.getDurationMin() + "");
}else{ }else{
viewStatus.setVisibility(INVISIBLE); helper.setText(R.id.tv_plan_duration,"");
viewStatus.setBackground(null); tvPlanDuration.setHint(mContext.getString(R.string.input_water_plan_time));
} }
if(item.getStatus().equals("1")){
checkBox.setChecked(true);
}else{
checkBox.setChecked(false);
} }
helper.addOnClickListener(R.id.linear_week);
helper.addOnClickListener(R.id.checkbox);
helper.addOnClickListener(R.id.tv_select_time);
helper.addOnClickListener(R.id.tv_plan_duration);
// LinearLayout linearItem = helper.getView(R.id.linear_item);
// View viewStatus = helper.getView(R.id.view_status);
// if(helper.getLayoutPosition() == mPos){
// linearItem.setBackground(mContext.getResources().getDrawable(R.drawable.shape_water_period_sel_bg));
// viewStatus.setVisibility(VISIBLE);
// viewStatus.setBackground(mContext.getResources().getDrawable(R.drawable.shape_green_circle));
// }else{
// linearItem.setBackground(null);
// if(!TextUtils.isEmpty(item.getTime()) && !TextUtils.isEmpty(item.getDuration())){
// viewStatus.setVisibility(VISIBLE);
// viewStatus.setBackground(mContext.getResources().getDrawable(R.drawable.shape_yellow_circle));
// }else{
// viewStatus.setVisibility(INVISIBLE);
// viewStatus.setBackground(null);
// }
// }
} }
public void setSelPos(int position) { public void setSelPos(int position) {

View File

@@ -0,0 +1,97 @@
package com.ckkj.water.plan.adapter;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import android.content.Context;
import android.text.TextUtils;
import android.view.View;
import android.widget.CheckBox;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import java.util.ArrayList;
import java.util.List;
public class WaterPlanWeekAdapter_copy extends BaseQuickAdapter<WaterPlanWeekEntity.DetailsBean, BaseViewHolder> {
private List<WaterPlanWeekEntity.DetailsBean> mList = new ArrayList<>();
private Context mContext;
private int mPos = 0;
public WaterPlanWeekAdapter_copy(Context context, int layoutResId, @Nullable List<WaterPlanWeekEntity.DetailsBean> data) {
super(layoutResId, data);
this.mContext = context;
this.mList = data;
}
@Override
protected void convert(BaseViewHolder helper, WaterPlanWeekEntity.DetailsBean item) {
TextView tvStartTime = helper.getView(R.id.tv_select_time);
CheckBox checkBox = helper.getView(R.id.checkbox);
TextView tvPlanDuration = helper.getView(R.id.tv_plan_duration);
helper.setText(R.id.tv_week_name,item.getWeekName());
LinearLayout linearItem = helper.getView(R.id.linear_item);
View viewStatus = helper.getView(R.id.view_status);
if(helper.getLayoutPosition() == mPos){
linearItem.setBackground(mContext.getResources().getDrawable(R.drawable.shape_water_period_sel_bg));
viewStatus.setVisibility(VISIBLE);
viewStatus.setBackground(mContext.getResources().getDrawable(R.drawable.shape_green_circle));
}else{
linearItem.setBackground(null);
viewStatus.setVisibility(INVISIBLE);
}
// if(!TextUtils.isEmpty(item.getStartTime())){
// helper.setText(R.id.tv_select_time, item.getStartTime());
// }else{
// helper.setText(R.id.tv_select_time,"");
// tvStartTime.setHint(mContext.getString(R.string.select_water_time));
// }
// if(item.getDurationMin() != 0){
// helper.setText(R.id.tv_plan_duration,item.getDurationMin() + "");
// }else{
// helper.setText(R.id.tv_plan_duration,"");
// tvPlanDuration.setHint(mContext.getString(R.string.input_water_plan_time));
// }
//
// if(item.getStatus().equals("1")){
// checkBox.setChecked(true);
// }else{
// checkBox.setChecked(false);
// }
//
// helper.addOnClickListener(R.id.linear_week);
// helper.addOnClickListener(R.id.checkbox);
// helper.addOnClickListener(R.id.tv_select_time);
// helper.addOnClickListener(R.id.tv_plan_duration);
// if(!TextUtils.isEmpty(item.getTime()) && !TextUtils.isEmpty(item.getDuration())){
// viewStatus.setVisibility(VISIBLE);
// viewStatus.setBackground(mContext.getResources().getDrawable(R.drawable.shape_yellow_circle));
// }else{
// viewStatus.setVisibility(INVISIBLE);
// viewStatus.setBackground(null);
// }
}
public void setSelPos(int position) {
this.mPos = position;
notifyDataSetChanged();
}
public int getmPos() {
return mPos;
}
}

View File

@@ -1,152 +1,77 @@
package com.ckkj.water.plan.entity; package com.ckkj.water.plan.entity;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
public class WaterPlanWeekEntity implements Serializable { public class WaterPlanWeekEntity implements Serializable {
/**
* 排程名称
*/
private String scheduleName;
/** /**
* 状态 * id : 2057637613963182082
* userId : 2056543507514097665
* name : 排程四
* deviceIds : null
* status : 1
* details : [{"createDept":null,"createBy":"2056543507514097665","createTime":"2026-05-22 09:40:10","updateBy":"2056543507514097665","updateTime":"2026-05-22 09:40:10","id":"2057637613963182083","scheduleId":"2057637613963182082","weekday":1,"startTime":"2026-04-11 10:12:12","durationMin":20,"zones":null,"triggerType":"0","status":"1"},{"createDept":null,"createBy":"2056543507514097665","createTime":"2026-05-22 09:40:10","updateBy":"2056543507514097665","updateTime":"2026-05-22 09:40:10","id":"2057637613963182084","scheduleId":"2057637613963182082","weekday":2,"startTime":"2026-04-11 10:12:12","durationMin":20,"zones":null,"triggerType":"0","status":"1"},{"createDept":null,"createBy":"2056543507514097665","createTime":"2026-05-22 09:40:10","updateBy":"2056543507514097665","updateTime":"2026-05-22 09:40:10","id":"2057637613963182085","scheduleId":"2057637613963182082","weekday":3,"startTime":"2026-04-11 10:12:12","durationMin":20,"zones":null,"triggerType":"0","status":"1"}]
*/ */
private boolean enable;
private String id;
private String userId;
private String name;
private List<WaterDeviceEntity> deviceIds;
private String status = "1";
private List<DetailsBean> details;
@NoArgsConstructor
@Data
public static class DetailsBean implements Serializable{
/** /**
* 洗水周期列表 * createDept : null
* createBy : 2056543507514097665
* createTime : 2026-05-22 09:40:10
* updateBy : 2056543507514097665
* updateTime : 2026-05-22 09:40:10
* id : 2057637613963182083
* scheduleId : 2057637613963182082
* weekday : 1
* startTime : 2026-04-11 10:12:12
* durationMin : 20
* zones : null
* triggerType : 0
* status : 1
*/ */
private List<WashCycleEntity> washCycleList;
/** private Object createDept;
* 关联设备列表 private String createBy;
*/ private String createTime;
private List<DeviceEntity> deviceList; private String updateBy;
private String updateTime;
public String getScheduleName() { private String id;
return scheduleName; private String scheduleId;
private int weekday = 1;
private String weekName;
private String startTime = "";
private int durationMin = 0;
private Object zones;
private String triggerType = "0";
private String status = "1";
private List<TimeDataBean> timeData;
} }
public void setScheduleName(String scheduleName) { @NoArgsConstructor
this.scheduleName = scheduleName; @Data
} public static class TimeDataBean implements Serializable{
private String startTime = "";
public boolean isEnable() { private int durationMin = 0;
return enable; private String weekName;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public List<WashCycleEntity> getWashCycleList() {
return washCycleList;
}
public void setWashCycleList(List<WashCycleEntity> washCycleList) {
this.washCycleList = washCycleList;
}
public List<DeviceEntity> getDeviceList() {
return deviceList;
}
public void setDeviceList(List<DeviceEntity> deviceList) {
this.deviceList = deviceList;
}
/**
* 洗水周期
*/
public static class WashCycleEntity {
/**
* 星期
* 如:周一
*/
private String week;
/**
* 时间
* 如10:30
*/
private String time;
/**
* 时长
* 如10min
*/
private String duration;
public String getWeek() {
return week;
}
public void setWeek(String week) {
this.week = week;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getDuration() {
return duration;
}
public void setDuration(String duration) {
this.duration = duration;
}
}
/**
* 设备实体
*/
public static class DeviceEntity {
/**
* 设备名称
*/
private String deviceName;
/**
* 设备编号
*/
private String deviceCode;
/**
* 是否已关联
*/
private boolean bind;
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public String getDeviceCode() {
return deviceCode;
}
public void setDeviceCode(String deviceCode) {
this.deviceCode = deviceCode;
}
public boolean isBind() {
return bind;
}
public void setBind(boolean bind) {
this.bind = bind;
}
} }
} }

View File

@@ -1,15 +1,59 @@
package com.ckkj.water.plan.mvp; package com.ckkj.water.plan.mvp;
import com.ckkj.water.base.IView; import com.ckkj.water.base.IView;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import org.json.JSONObject;
import java.util.List;
import java.util.Map;
public class WaterPlanContract { public class WaterPlanContract {
public interface CallBack<T> { public interface CallBack<T> {
void success(T msg); void success(T msg,int total);
void fail(String msg); void fail(String msg);
} }
public interface DataModel{ public interface DataModel{
//查询排程列表
void getWaterConfigList(Map<String, String> map,CallBack callBack);
//新增排程
void saveConfig(JSONObject json,CallBack callBack);
//更新排程
void updateConfig(JSONObject json,CallBack callBack);
//更新排程状态
void updatePlanStatus(JSONObject json, CallBack callBack);
//查询排程可绑定的设备列表
void getPlanBindDeviceList(Map<String, String> map,CallBack callBack);
//查询排程详情
void getPlanDetailInfo(Map<String, String> map,CallBack callBack);
//排程绑定设备
void planBindDevice(JSONObject json,CallBack callBack);
//删除排程
void deletePlan(String id,CallBack callBack);
//排程解绑设备
void planUnbindDevice(Map<String, String> map,CallBack callBack);
} }
public interface WaterPlanView extends IView { public interface WaterPlanView extends IView {
//查询排程列表成功
void getWaterConfigListSuccess(List<WaterPlanWeekEntity> list,int total);
//排程保存成功g
void saveConfigSuccess(WaterPlanWeekEntity entity);
//排程更新成功
void updateConfigSuccess(WaterPlanWeekEntity entity);
//更新排程状态成功
void updatePlanStatusSuccess(BaseBean bean, String status);
//获取排程详情
void getPlanDetailInfo(WaterPlanWeekEntity entity);
//查询到可绑定设备列表
void getPlanBindDeviceList(WaterDeviceEntity bean);
//排程绑定设备成功
void planBindDeviceSuccess(BaseBean bean);
//删除排程成功
void deletePlanSuccess(BaseBean bean);
//排程解绑设备成功
void planUnbindDeviceSuccess(BaseBean bean,int position);
} }
} }

View File

@@ -1,7 +1,340 @@
package com.ckkj.water.plan.mvp; package com.ckkj.water.plan.mvp;
import com.ckkj.water.device.mvp.DeviceContract; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.network.NetWorkManager;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import org.json.JSONObject;
import java.util.List;
import java.util.Map;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
public class WaterPlanImpl implements WaterPlanContract.DataModel{ public class WaterPlanImpl implements WaterPlanContract.DataModel{
/**
* 查询排程列表
* @param map
* @param callBack
*/
@Override
public void getWaterConfigList(Map<String, String> map, WaterPlanContract.CallBack callBack) {
NetWorkManager.getRequest().scheduleList(NetWorkManager.getToken(),map)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<List<WaterPlanWeekEntity>>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<List<WaterPlanWeekEntity>> bean) {
if (bean.getCode() == 200) {
callBack.success(bean.getRows(),bean.getTotal());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
}
/**
* 新增排程
* @param json
* @param callBack
*/
@Override
public void saveConfig(JSONObject json, WaterPlanContract.CallBack callBack) {
try {
NetWorkManager.getRequest().addSchedule(NetWorkManager.getToken(),NetWorkManager.toRequestBody(json))
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<WaterPlanWeekEntity>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<WaterPlanWeekEntity> bean) {
if (bean.getCode() == 200) {
callBack.success(bean.getData(),0);
} else {
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 更新排程信息
* @param json
* @param callBack
*/
@Override
public void updateConfig(JSONObject json, WaterPlanContract.CallBack callBack) {
try {
NetWorkManager.getRequest().updateSchedule(NetWorkManager.getToken(),NetWorkManager.toRequestBody(json))
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<WaterPlanWeekEntity>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<WaterPlanWeekEntity> bean) {
if (bean.getCode() == 200) {
callBack.success(bean.getData(),0);
} else {
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 更新排程状态
* @param callBack
*/
@Override
public void updatePlanStatus(JSONObject json, WaterPlanContract.CallBack callBack) {
NetWorkManager.getRequest().updateScheduleStatus(NetWorkManager.getToken(),NetWorkManager.toRequestBody(json))
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<WaterPlanWeekEntity>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<WaterPlanWeekEntity> bean) {
if (bean.getCode() == 200) {
callBack.success(bean.getData(), 0);
} else {
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
}
/**
* 查询可绑定排程的设备列表
* @param map
* @param callBack
*/
@Override
public void getPlanBindDeviceList(Map<String, String> map, WaterPlanContract.CallBack callBack) {
String deviceID = map.get("id");
NetWorkManager.getRequest().getPlanBindDeviceList(NetWorkManager.getToken(), deviceID)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<WaterDeviceEntity>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<WaterDeviceEntity> bean) {
if (bean.getCode() == 200) {
callBack.success(bean.getData(),0);
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
}
@Override
public void getPlanDetailInfo(Map<String, String> map, WaterPlanContract.CallBack callBack) {
String deviceID = map.get("id");
NetWorkManager.getRequest().getPlanDetailInfo(NetWorkManager.getToken(), deviceID)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<WaterPlanWeekEntity>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<WaterPlanWeekEntity> bean) {
if (bean.getCode() == 200) {
callBack.success(bean.getData(),0);
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
}
@Override
public void planBindDevice(JSONObject json, WaterPlanContract.CallBack callBack) {
try {
NetWorkManager.getRequest().planBindDevice(NetWorkManager.getToken(),NetWorkManager.toRequestBody(json))
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean bean) {
if (bean.getCode() == 200) {
callBack.success(bean.getData(),0);
} else {
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除排程
* @param id
* @param callBack
*/
@Override
public void deletePlan(String id, WaterPlanContract.CallBack callBack) {
try {
NetWorkManager.getRequest().deletePlanById(NetWorkManager.getToken(), id)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean bean) {
if (bean.getCode() == 200) {
callBack.success(bean,0);
} else {
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void planUnbindDevice(Map<String, String> map, WaterPlanContract.CallBack callBack) {
NetWorkManager.getRequest().planUnBindDevice(NetWorkManager.getToken(), map)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean bean) {
if (bean.getCode() == 200) {
callBack.success(bean,0);
} else {
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
}
} }

View File

@@ -1,8 +1,17 @@
package com.ckkj.water.plan.mvp; package com.ckkj.water.plan.mvp;
import com.ckkj.water.base.BasePresenter; import com.ckkj.water.base.BasePresenter;
import com.ckkj.water.device.mvp.DeviceContract; import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.device.mvp.DeviceImpl; import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class WaterPlanPresenter extends BasePresenter<WaterPlanContract.WaterPlanView> { public class WaterPlanPresenter extends BasePresenter<WaterPlanContract.WaterPlanView> {
private WaterPlanImpl impl; private WaterPlanImpl impl;
@@ -10,4 +19,290 @@ public class WaterPlanPresenter extends BasePresenter<WaterPlanContract.WaterPla
public WaterPlanPresenter(WaterPlanImpl impl) { public WaterPlanPresenter(WaterPlanImpl impl) {
this.impl = impl; this.impl = impl;
} }
/**
* 获取排程信息
*/
public void getWaterPlanList(int mCurrentPage) {
Map<String,String> map = new HashMap<>();
map.put("pageNum", mCurrentPage + "");
map.put("pageSize", "10");
impl.getWaterConfigList(map, new WaterPlanContract.CallBack<List<WaterPlanWeekEntity>>() {
@Override
public void success(List<WaterPlanWeekEntity> List, int total) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().getWaterConfigListSuccess(List, total);
}
}
@Override
public void fail(String msg) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().showError(msg);
}
}
});
}
/**
* 保存排程信息
* @param entity
*/
public void saveConfig(WaterPlanWeekEntity entity) {
try {
JSONObject json = new JSONObject();
json.put("name", entity.getName());
json.put("status", entity.getStatus());
JSONArray array = new JSONArray();
for(WaterPlanWeekEntity.DetailsBean detailsBean : entity.getDetails()){
JSONObject jsonDetails = new JSONObject();
jsonDetails.put("weekday", detailsBean.getWeekday());
jsonDetails.put("triggerType", detailsBean.getTriggerType());
jsonDetails.put("status", detailsBean.getStatus());
JSONArray timeArray = new JSONArray();
for(WaterPlanWeekEntity.TimeDataBean timeDataBean : detailsBean.getTimeData()){
JSONObject jsonTime = new JSONObject();
jsonTime.put("startTime", timeDataBean.getStartTime());
jsonTime.put("durationMin", timeDataBean.getDurationMin());
timeArray.put(jsonTime);
}
jsonDetails.put("timeData", timeArray);
array.put(jsonDetails);
}
json.put("details", array);
impl.saveConfig(json, new WaterPlanContract.CallBack<WaterPlanWeekEntity>() {
@Override
public void success(WaterPlanWeekEntity bean, int total) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().saveConfigSuccess(bean);
}
}
@Override
public void fail(String msg) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().showError(msg);
}
}
});
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
/**
* 更新排程信息
* @param entity
*/
public void updateConfig(WaterPlanWeekEntity entity) {
try {
JSONObject json = new JSONObject();
json.put("id", entity.getId());
json.put("name", entity.getName());
json.put("status", entity.getStatus());
JSONArray array = new JSONArray();
for(WaterPlanWeekEntity.DetailsBean detailsBean : entity.getDetails()){
JSONObject jsonDetails = new JSONObject();
jsonDetails.put("weekday", detailsBean.getWeekday());
jsonDetails.put("triggerType", detailsBean.getTriggerType());
jsonDetails.put("status", detailsBean.getStatus());
jsonDetails.put("id", detailsBean.getId());
JSONArray timeArray = new JSONArray();
for(WaterPlanWeekEntity.TimeDataBean timeDataBean : detailsBean.getTimeData()){
JSONObject jsonTime = new JSONObject();
jsonTime.put("startTime", timeDataBean.getStartTime());
jsonTime.put("durationMin", timeDataBean.getDurationMin());
timeArray.put(jsonTime);
}
jsonDetails.put("timeData", timeArray);
array.put(jsonDetails);
}
json.put("details", array);
impl.updateConfig(json, new WaterPlanContract.CallBack<WaterPlanWeekEntity>() {
@Override
public void success(WaterPlanWeekEntity bean, int total) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().updateConfigSuccess(bean);
}
}
@Override
public void fail(String msg) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().showError(msg);
}
}
});
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
/**
* 查询排程可绑定的设备列表
* @param entity
*/
public void getPlanBindDevices(WaterPlanWeekEntity entity) {
Map<String,String> map = new HashMap<>();
map.put("id",entity.getId());
impl.getPlanBindDeviceList(map, new WaterPlanContract.CallBack<WaterDeviceEntity>() {
@Override
public void success(WaterDeviceEntity bean, int total) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().getPlanBindDeviceList(bean);
}
}
@Override
public void fail(String msg) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().showError( msg);
}
}
});
}
/**
* 查询排程详情
* @param mPlanEntity
*/
public void getPlanDetailInfo(WaterPlanWeekEntity mPlanEntity) {
Map<String,String> map = new HashMap<>();
map.put("id",mPlanEntity.getId());
impl.getPlanDetailInfo(map, new WaterPlanContract.CallBack<WaterPlanWeekEntity>() {
@Override
public void success(WaterPlanWeekEntity bean, int total) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().getPlanDetailInfo(bean);
}
}
@Override
public void fail(String msg) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().showError( msg);
}
}
});
}
/**
* 排程绑定设备
* @param entity
* @param deviceIds
*/
public void planBindWithDevices(WaterPlanWeekEntity entity, String deviceIds) {
try {
JSONObject json = new JSONObject();
json.put("scheduleId", entity.getId());
// 将逗号分隔的字符串转换为 JSONArray (数字类型)
JSONArray deviceIdArray = new JSONArray();
String[] idArray = deviceIds.split(",");
for (String id : idArray) {
deviceIdArray.put(id);
}
json.put("deviceIds", deviceIdArray);
impl.planBindDevice(json, new WaterPlanContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean, int total) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().planBindDeviceSuccess(bean);
}
}
@Override
public void fail(String msg) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().showError( msg);
}
}
});
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
/**
* 更新排程状态
* @param entity 排程实体
* @param status 状态 0-关闭 1-开启
*/
public void updatePlanStatus(WaterPlanWeekEntity entity, String status) {
try {
JSONObject json = new JSONObject();
json.put("id", entity.getId());
json.put("status", status);
impl.updatePlanStatus(json, new WaterPlanContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean, int total) {
if (WaterPlanPresenter.this.getView() != null) {
WaterPlanPresenter.this.getView().updatePlanStatusSuccess(bean,status);
}
}
@Override
public void fail(String msg) {
if (WaterPlanPresenter.this.getView() != null) {
WaterPlanPresenter.this.getView().showError(msg);
}
}
});
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
/**
* 删除排程
* @param mDetailEntity
*/
public void deletePlan(WaterPlanWeekEntity mDetailEntity) {
impl.deletePlan(mDetailEntity.getId(), new WaterPlanContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean, int total) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().deletePlanSuccess(bean);
}
}
@Override
public void fail(String msg) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().showError( msg);
}
}
});
}
/**
* 排程解绑设备
* @param planID
* @param deviceID
*/
public void planUnbindDevice(String planID, String deviceID,int position) {
Map<String,String> map = new HashMap<>();
map.put("scheduleId",planID);
map.put("deviceId",deviceID);
impl.planUnbindDevice(map, new WaterPlanContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean, int total) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().planUnbindDeviceSuccess(bean,position);
}
}
@Override
public void fail(String msg) {
if(WaterPlanPresenter.this.getView() != null){
WaterPlanPresenter.this.getView().showError( msg);
}
}
});
}
} }

View File

@@ -0,0 +1,66 @@
package com.ckkj.water.utils.manager;
import android.content.Context;
import com.ckkj.water.R;
/**
* @author fengxiaoyang
* @date 2026/6/2
* @description 电池图标管理,根据电量值返回对应的图标资源
*/
public class PowerIconManage {
private static PowerIconManage instance;
private int[] horIconRes = {R.mipmap.hor_0, R.mipmap.hor_10, R.mipmap.hor_20, R.mipmap.hor_30,
R.mipmap.hor_40, R.mipmap.hor_50, R.mipmap.hor_60, R.mipmap.hor_70,
R.mipmap.hor_80, R.mipmap.hor_90, R.mipmap.hor_100};
private int [] verIconRes = {R.mipmap.ver_0, R.mipmap.ver_10, R.mipmap.ver_20, R.mipmap.ver_30,
R.mipmap.ver_40, R.mipmap.ver_50, R.mipmap.ver_60, R.mipmap.ver_70,
R.mipmap.ver_80, R.mipmap.ver_90, R.mipmap.ver_100};
public static PowerIconManage getInstance() {
if (instance == null) {
synchronized (PowerIconManage.class) {
if (instance == null) {
instance = new PowerIconManage();
}
}
}
return instance;
}
/**
* 根据电量值获取对应的电池图标
* @param power 电量值 (0-100)
* @return 电池图标资源ID
*/
public int getPowerIcon(int power) {
if (power <= 0) {
return horIconRes[0];
}
if (power >= 100) {
return horIconRes[10];
}
// 计算对应的数组索引电量1~10对应索引111~20对应索引2...
int index = (power + 9) / 10;
return horIconRes[index];
}
/**
* 根据电量值获取对应的电池图标
* @param power 电量值 (0-100)
* @return 电池图标资源ID
*/
public int getPowerVerIcon(int power) {
if (power <= 0) {
return verIconRes[0];
}
if (power >= 100) {
return verIconRes[10];
}
// 计算对应的数组索引电量1~10对应索引111~20对应索引2...
int index = (power + 9) / 10;
return verIconRes[index];
}
}

View File

@@ -0,0 +1,168 @@
package com.ckkj.water.utils.manager;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import com.ckkj.water.AppConfig;
import java.util.Arrays;
import java.util.UUID;
import no.nordicsemi.android.ble.BleManager;
/**
* @author fengxiaoyang
* @date 2026/6/3
* @description 蓝牙设备管理
*/
public class WaterDeviceManager extends BleManager {
private BluetoothGattCharacteristic writeCharacteristic;
private BluetoothGattCharacteristic notifyCharacteristic;
private OnDataReceivedListener dataListener;
public interface OnDataReceivedListener {
void onDataReceived(byte[] data);
}
public WaterDeviceManager(@NonNull Context context) {
super(context);
}
public void setOnDataReceivedListener(OnDataReceivedListener listener) {
this.dataListener = listener;
}
@NonNull
@Override
protected BleManagerGattCallback getGattCallback() {
return new DeviceGattCallback();
}
private class DeviceGattCallback extends BleManagerGattCallback {
@Override
protected void initialize() {
setNotificationCallback(notifyCharacteristic)
.with((device, data) -> {
byte[] bytes = data.getValue();
Log.e("TEST", "收到数据: " + Arrays.toString(bytes));
if (dataListener != null) {
dataListener.onDataReceived(bytes);
}
});
enableNotifications(notifyCharacteristic)
.enqueue();
}
// @Override
// public boolean isRequiredServiceSupported(@NonNull BluetoothGatt gatt) {
//
// BluetoothGattService service =
// gatt.getService(UUID.fromString(
// AppConfig.BLUETOOTH_DEVICE_UUID));
//
// if (service == null) {
// return false;
// }
//
// writeCharacteristic =
// service.getCharacteristic(UUID.fromString(
// AppConfig.BLUETOOTH_DEVICE_UUID));
//
// notifyCharacteristic =
// service.getCharacteristic(UUID.fromString(
// AppConfig.BLUETOOTH_DEVICE_UUID));
//
// return writeCharacteristic != null
// && notifyCharacteristic != null;
// }
@Override
public boolean isRequiredServiceSupported(
@NonNull BluetoothGatt gatt) {
for (BluetoothGattService service :
gatt.getServices()) {
Log.e("TEST",
"Service=" + service.getUuid());
for (BluetoothGattCharacteristic c :
service.getCharacteristics()) {
int properties = c.getProperties();
Log.e("TEST",
"Characteristic="
+ c.getUuid()
+ " props="
+ properties);
if ((properties &
BluetoothGattCharacteristic.PROPERTY_WRITE)
!= 0) {
writeCharacteristic = c;
}
if ((properties &
BluetoothGattCharacteristic.PROPERTY_NOTIFY)
!= 0) {
notifyCharacteristic = c;
}
}
}
Log.e("TEST",
"write="
+ (writeCharacteristic != null
? writeCharacteristic.getUuid()
: "null"));
Log.e("TEST",
"notify="
+ (notifyCharacteristic != null
? notifyCharacteristic.getUuid()
: "null"));
return writeCharacteristic != null;
}
@Override
protected void onServicesInvalidated() {
writeCharacteristic = null;
notifyCharacteristic = null;
}
}
public void send(byte[] data) {
if (writeCharacteristic == null) {
Log.e("TEST", "send: Write characteristic is null");
return;
}
writeCharacteristic(writeCharacteristic, data)
.enqueue();
}
public boolean isBlConnected() {
// 通过反射或状态检查来判断是否已连接
// BleManager 没有直接的 isConnected 方法,需要检查内部状态
try {
// 检查 writeCharacteristic 是否可用(连接后会初始化)
return writeCharacteristic != null;
} catch (Exception e) {
return false;
}
}
}

View File

@@ -229,10 +229,98 @@ public class ZYTimeUtils {
public static String getStrTimeData(Date date) { public static String getStrTimeData(Date date) {
String timeString = null; String timeString = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
timeString = sdf.format(new Date());//单位秒 timeString = sdf.format(date);//单位秒
return timeString; return timeString;
} }
/**
* yyyy-MM-dd HH:mm 转换为 HH:mm显示
* @param date
* @return
*/
public static String yyyyMMdd2HH_mm(String date) {
if (TextUtils.isEmpty(date)) {
return "";
}
try {
SimpleDateFormat sourceFormat =
new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
SimpleDateFormat targetFormat =
new SimpleDateFormat("HH:mm", Locale.getDefault());
Date parseDate = sourceFormat.parse(date);
return parseDate == null ? "" : targetFormat.format(parseDate);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* yyyy-MM-dd HH:mm:ss 转换成 yyyy-MM-dd HH:mm
* @param time
* @return
*/
public static String timeWithoutMillis(String time) {
if (TextUtils.isEmpty(time)) {
return null;
}
try {
SimpleDateFormat sourceFormat =
new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss",
Locale.getDefault());
SimpleDateFormat targetFormat =
new SimpleDateFormat(
"yyyy-MM-dd HH:mm",
Locale.getDefault());
Date date = sourceFormat.parse(time);
return date == null ? "" : targetFormat.format(date);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* HH:mm:ss 转 HH:mm
* 例如:
* 08:00:00 -> 08:00
* 18:35:29 -> 18:35
*/
public static String formatHHmm(String time) {
if (TextUtils.isEmpty(time)) {
return "";
}
try {
SimpleDateFormat sourceFormat =
new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
SimpleDateFormat targetFormat =
new SimpleDateFormat("HH:mm", Locale.getDefault());
Date date = sourceFormat.parse(time);
return targetFormat.format(date);
} catch (Exception e) {
e.printStackTrace();
return time;
}
}
public static String getStrTimeData_H_M(Date date) { public static String getStrTimeData_H_M(Date date) {
String timeString = null; String timeString = null;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm"); SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
@@ -974,4 +1062,18 @@ public class ZYTimeUtils {
} }
} }
private static final String[] WEEK_NAMES = {"周一", "周二", "周三", "周四", "周五", "周六", "周日"};
/**
* 根据星期索引获取星期名称
* @param weekday 星期索引0=周一1=周二,...6=周日
* @return 对应的星期名称
*/
public static String getWeekName(int weekday) {
if (weekday >= 0 && weekday < 7) {
return WEEK_NAMES[weekday];
}
return "";
}
} }

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white"/>
<stroke android:color="@color/color_zhu" android:width="@dimen/dp_1"/>
<corners android:radius="@dimen/dp_4"/>
</shape>

View File

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

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetRight="12dp">
<shape android:shape="rectangle">
<solid android:color="@color/color_e34d59"/>
<corners
android:radius="8dp"/>
</shape>
</inset>

View File

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

View File

@@ -6,11 +6,5 @@
<corners android:topLeftRadius="@dimen/dp_4" android:bottomLeftRadius="@dimen/dp_4" /> <corners android:topLeftRadius="@dimen/dp_4" android:bottomLeftRadius="@dimen/dp_4" />
</shape> </shape>
</item> </item>
<item>
<shape android:shape="rectangle">
<solid android:color="@color/white" />
<stroke android:color="@color/color_zhu" android:width="@dimen/dp_1"/>
<corners android:topLeftRadius="@dimen/dp_4" android:bottomLeftRadius="@dimen/dp_4" />
</shape>
</item>
</selector> </selector>

View File

@@ -6,11 +6,4 @@
<corners android:topRightRadius="@dimen/dp_4" android:bottomRightRadius="@dimen/dp_4" /> <corners android:topRightRadius="@dimen/dp_4" android:bottomRightRadius="@dimen/dp_4" />
</shape> </shape>
</item> </item>
<item>
<shape android:shape="rectangle">
<solid android:color="@color/white" />
<stroke android:color="@color/color_zhu" android:width="@dimen/dp_1"/>
<corners android:bottomRightRadius="@dimen/dp_4" android:topRightRadius="@dimen/dp_4" />
</shape>
</item>
</selector> </selector>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="@color/color_zhu" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@color/white" />
<stroke android:color="@color/color_zhu" android:width="@dimen/dp_1"/>
</shape>
</item>
</selector>

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -43,14 +45,19 @@
android:layout_width="@dimen/dp_200" android:layout_width="@dimen/dp_200"
android:layout_height="@dimen/dp_200" android:layout_height="@dimen/dp_200"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:src="@drawable/anim_add_device_scan"/> android:src="@drawable/anim_add_device_scan"
android:visibility="visible"/>
<ImageView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/img_device_item" android:id="@+id/rv_devices"
android:layout_width="@dimen/dp_150" android:layout_width="match_parent"
android:layout_height="@dimen/dp_150" android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:src="@mipmap/ic_launcher" android:paddingHorizontal="@dimen/dp_5"
android:layout_marginTop="@dimen/dp_5"
tools:listitem="@layout/scan_ble_device_item"
app:spanCount="4"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
android:visibility="gone"/> android:visibility="gone"/>
<TextView <TextView
@@ -76,4 +83,17 @@
android:layout_marginHorizontal="@dimen/dp_20" android:layout_marginHorizontal="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_40" android:layout_marginTop="@dimen/dp_40"
android:gravity="center"/> android:gravity="center"/>
<TextView
android:id="@+id/btn_ble_scan"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="@color/white"
android:text="蓝牙扫描"
android:background="@drawable/shape_green_button_bg"
android:paddingVertical="@dimen/dp_10"
android:layout_marginHorizontal="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_40"
android:gravity="center"/>
</LinearLayout> </LinearLayout>

View File

@@ -16,7 +16,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/dp_40" android:layout_height="@dimen/dp_40"
android:orientation="horizontal" android:orientation="horizontal"
android:layout_marginHorizontal="@dimen/dp_20"> android:layout_marginHorizontal="@dimen/dp_20"
android:background="@drawable/shape_add_water_tab_bg">
<TextView <TextView
android:id="@+id/tv_config" android:id="@+id/tv_config"
android:layout_width="0dp" android:layout_width="0dp"
@@ -27,6 +28,16 @@
android:textSize="14sp" android:textSize="14sp"
android:textColor="@drawable/tab_selector_text" android:textColor="@drawable/tab_selector_text"
android:text="@string/water_device_config"/> android:text="@string/water_device_config"/>
<TextView
android:id="@+id/tv_bound"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:background="@drawable/tab_selector_bg_center"
android:textSize="14sp"
android:textColor="@drawable/tab_selector_text"
android:text="@string/water_bound_device"/>
<TextView <TextView
android:id="@+id/tv_bind" android:id="@+id/tv_bind"
android:layout_width="0dp" android:layout_width="0dp"

View File

@@ -187,8 +187,8 @@
android:orientation="horizontal" android:orientation="horizontal"
android:background="@drawable/shape_f9f9f9_corner_5" android:background="@drawable/shape_f9f9f9_corner_5"
android:layout_marginHorizontal="@dimen/dp_20"> android:layout_marginHorizontal="@dimen/dp_20">
<EditText <TextView
android:id="@+id/et_wort_time" android:id="@+id/tv_work_duartion"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingLeft="@dimen/dp_5" android:paddingLeft="@dimen/dp_5"

View File

@@ -0,0 +1,100 @@
<?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="wrap_content">
<LinearLayout
android:id="@+id/linear_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_20"
android:paddingHorizontal="@dimen/dp_20"
android:orientation="vertical"
android:background="@drawable/shape_water_plan_time_bg">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="@color/red"
android:text="*"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_4"
android:textSize="14sp"
android:textColor="@color/color_222222"
android:text="@string/plan_start_time"
android:layout_marginVertical="@dimen/dp_13"/>
<TextView
android:id="@+id/tv_select_time"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="9"
android:gravity="center_vertical"
android:textSize="14sp"
android:textColor="@color/color_222222"
android:layout_marginLeft="@dimen/dp_10"
android:hint="@string/select_water_time"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="@dimen/dp_24"
android:layout_weight="0.5"
android:src="@mipmap/icon_point_right_wt"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/color_d9d9d9"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="@color/red"
android:text="*"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_4"
android:textSize="14sp"
android:textColor="@color/color_222222"
android:text="@string/plan_time"
android:layout_marginVertical="@dimen/dp_13"/>
<TextView
android:id="@+id/tv_plan_duration"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="9"
android:gravity="center_vertical"
android:textSize="14sp"
android:textColor="@color/color_222222"
android:layout_marginLeft="@dimen/dp_10"
android:hint="@string/input_water_plan_time"/>
<TextView
android:id="@+id/tv_time_unit"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center_vertical|right"
android:textSize="14sp"
android:textColor="@color/color_222222"
android:layout_marginLeft="@dimen/dp_10"
android:hint="min"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -93,11 +93,9 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_devices" android:id="@+id/rv_devices"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="wrap_content"
android:layout_weight="1"
android:clipToPadding="false" android:clipToPadding="false"
android:paddingHorizontal="@dimen/dp_15" android:paddingHorizontal="@dimen/dp_15"
android:paddingBottom="@dimen/dp_20"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/index_device_list_item" /> tools:listitem="@layout/index_device_list_item" />

View File

@@ -14,6 +14,7 @@
layout="@layout/include_activity_back_whitebg_layout" /> layout="@layout/include_activity_back_whitebg_layout" />
</RelativeLayout> </RelativeLayout>
<LinearLayout <LinearLayout
android:id="@+id/linear_info"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"

View File

@@ -6,14 +6,20 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:paddingBottom="@dimen/dp_20"> android:paddingBottom="@dimen/dp_20">
<LinearLayout
android:id="@+id/linear_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_devices" android:id="@+id/rv_devices"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:listitem="@layout/plan_bind_device_item" tools:listitem="@layout/plan_bind_device_item"
tools:itemCount="3"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/> app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
<TextView <TextView
@@ -29,4 +35,16 @@
android:layout_marginTop="@dimen/dp_40" android:layout_marginTop="@dimen/dp_40"
android:gravity="center"/> android:gravity="center"/>
</LinearLayout> </LinearLayout>
<RelativeLayout
android:id="@+id/rel_noresult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/dp_100"
android:visibility="gone">
<include
android:id="@+id/included_noresult"
layout="@layout/include_no_result_layout"/>
</RelativeLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/dp_10"
android:layout_marginVertical="@dimen/dp_5"
app:cardCornerRadius="10dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingVertical="@dimen/dp_12">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingLeft="@dimen/dp_10">
<!-- 设备名称 -->
<TextView
android:id="@+id/tv_device_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="智能浇水设备A1"
android:textColor="@color/color_333333"
android:textSize="17sp"
android:textStyle="bold" />
<!-- 设备序列号 -->
<TextView
android:id="@+id/tv_device_serial"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_4"
android:text="YA226641000107"
android:textColor="@color/color_666666"
android:textSize="12sp" />
<!-- 电量信息 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_8"
android:gravity="center_vertical"
android:orientation="horizontal">
<View
android:layout_width="@dimen/dp_4"
android:layout_height="@dimen/dp_4"
android:background="@drawable/shape_green_circle"/>
<TextView
android:id="@+id/tv_battery_level"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_4"
android:text="已绑定"
android:textColor="@color/color_666666"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
<ImageView
android:id="@+id/img_delete"
android:layout_width="@dimen/dp_24"
android:layout_height="@dimen/dp_24"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_marginRight="@dimen/dp_20"
android:src="@mipmap/icon_delete"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>

Some files were not shown because too many files have changed in this diff Show More