This commit is contained in:
fengjignqi
2026-05-16 16:19:39 +08:00
commit 1b1575eb8a
1632 changed files with 242221 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
package com.ckkj.water;
public class AppConfig {
/**************************生产*******************************/
// public static String BASE_URL = "https://www.mingdengbazi.site/";//测试【http://114.55.12.112/】【https://www.mingdengbazi.site/】
// public static String BASE_URL_TWO = BASE_URL;//测试
// public static String BASE_URL_THREE = BASE_URL;//测试
// public static boolean IS_TEST_REQUEST = false;
/**************************测试*******************************/
// public static String BASE_URL = "http://47.106.83.229:8081/";//测试http://47.106.83.166:8001/
// public static String BASE_URL_TWO = BASE_URL;//测试
// public static String BASE_URL_THREE = BASE_URL;//测试
// public static boolean IS_TEST_REQUEST = true;
/**************************本地*******************************/
public static String BASE_URL = "http://192.168.1.67:8081/";//测试
public static String BASE_URL_TWO = BASE_URL;//测试
public static String BASE_URL_THREE = BASE_URL;//测试
public static boolean IS_TEST_REQUEST = true;
/**************************生产*******************************/
//
// public static String BASE_URL = "https://gw.dingdingche.net/";//测试
// public static String BASE_URL_TWO = "https://gw.dingdingche.net/";//测试
// public static String BASE_URL_THREE = "https://gw.dingdingche.net/";//测试
// public static String BASE_URL_LOCAL = "http://192.168.100.234:48080";//大宗测试
// public static String RONGCLOUD_APPKEY = "n19jmcy5nh7s9";//融云通信AppKey
// public static String KKFILE_PREVIEW_URL = "";//文件kkFile拼接预览
// public static String SERVICE_WEB_URL = "https://mro.jkmass.com/testService?token=";//测试
// public static boolean IS_TEST_REQUEST = false;
public static boolean USER_CONFIRM_UPDATE_APP = false;
//生成订单相关
/**************************生产******************************/
// public static String BASE_URL = "http://192.168.10.28:8083";//测试
////用于登录页面便捷切换账号
public final static boolean APP_TEST_FLAG = true;
//App权限验证码
public static String APP_ENTER_CODE = "";
public static String USER_TOKEN = "";
public static int MEMBER_ID = 0;
//是否登录
public static boolean USER_LOGIN = false;
//用户是否设置了生辰八字
public static boolean USER_SET_BIRTH_INFO = false;
//用户头像
public static String USER_INFO_AVATAR = "";
//手机号验证码登录
public static final int MEMBER_LOGIN = 2;
//缘份居 API 调用的 key
public static String YUANFENJU_API_KEY = "utEK5Kbx2JSkZqnlKypyuz1DK";//公司
// public static String YUANFENJU_API_KEY = "jLCpL92dL8pPh2C9F4rfBattZ";//个人
//密码校验正则/
public static final String PSD_REGEX = "^(?=.*[a-zA-Z])(?=.*\\d)[a-zA-Z\\d]{8,20}$";
//高德地图 AppKey
public static String GAODE_MAP_APP_KEY = "a91364c6bbc2f5c773a949926fae7fb6";//个人
//友盟相关
public static String UMENG_APP_KEY = "6709d097667bfe33f3be702e";
/**************************支付宝相关******************************/
//支付宝Appid
public static final String ALIPAY_APPID = "9021000137698324";
//用于支付宝账户登录授权业务的入参 pid。
public static final String PID = "2088721037230300";
/**************************字典相关******************************/
//缓存商品单位的json
public static String PRODUCT_UNIT_JSON = "";
//缓存商品品牌的json
public static String PRODUCT_BRAND_JSON = "";
public static String WX_APPID = "wx66c35bc33549040a";
//融云回话token
public static String RONG_CLOUD_TALK_TOKEN = "";
//用户userID,,不可见
public static String USER_ID = "";
//用户融云ID
public static String USER_RONGCLOUD_ID = "";
//阿里云配置相关
public static String ALIYUN_ENDPOINT = "https://oss-cn-nanjing.aliyuncs.com";
public static String ALIYUN_BUCKETNAME = "mdbz";
//上传type
public static final int UPLOAD_TYPE_100 = 100;//暂用于头像
public static final int UPLOAD_TYPE_200 = 200;//暂用于车圈
public static final int UPLOAD_TYPE_300 = 300;//暂用于车圈
public static final int UPLOAD_TYPE_400 = 400;//暂用于反馈客服
//汽车品牌在阿里云的地址
public static String ALI_OSS_CAR_BRAND_LOGO = "https://oss.mingdengbazi.site/";
//验证码使用场景值
//登录
public static String SMS_CODE_TYPE_LOGIN = "login";
//注册
public static String SMS_CODE_TYPE_REGISTER = "1";
//修改手机号
public static String SMS_CODE_TYPE_CHANGE_PHONE = "modify";
//注销账号
public static String SMS_CODE_TYPE_LOG_OFF = "cancel";
//绑定支付宝
public static String SMS_CODE_TYPE_BIND_ALIPAY = "4";
//当前车圈筛选的值 0 全部 1 求购2 出售
public static String CURRENT_CAR_CIRCLE_OPTION_CODE = "0";
//邀请页面注册页面的 url
public static String INVITE_REGIST_URL = "https://esca.dingdingche.net/H5/index.html?";
//测试使用 token
public static String TEST_USER_ID = "1897194667309666304";
//用户协议
public static String USER_AGREEMENT = "https://sta.mingdengbazi.site/yhxy.html";
//隐私政策
public static String USER_PRIVACY = "https://sta.mingdengbazi.site/ysxy.html";
//用户分享链接
public static String USER_SHARE_URL = "https://sta.mingdengbazi.site/on/index.html?code=";
}

View File

@@ -0,0 +1,118 @@
package com.ckkj.water;
/**
* @author messi.mo
* date2019/7/30.
* describe常量池
*/
public class ConstantUtil {
//页面跳转来源
public static final String ACTIVITY_NAVIGATE_FLAG = "activity_navigate_flag";
public static final String SHARE_PRE_NAME = "mingdengbazi_pre";
public static final String FIRST_ENTER_APP_AGREEMENT_TIPS = "first_enter_app_agreement_tips";
public static final String FIRST_ENTER_APP_FLAG = "first_enter_app_flag";
public static final String USER_LOGIN = "user_login";
public static final String USER_TOKEN = "user_token";
public static final String USER_HAS_SET_BIRTH = "user_has_set_birth";
public static final String USER_RONGCLOUD_TOKEN = "user_rongcloud_token";
public static final String USER_ID = "user_id";
public static final String USER_RONGCLOUD_ID = "user_rongcloud_id";
public static final String USER_INFO_JSON_CONTENT = "user_info_json_content";
public static final String SEARCH_HISTORY = "search_history";
public static final String USER_CONFIRM_UPLOAD_INFO = "user_confirm_upload_info";
public static final String GROUP_LAST_TIME = "group_last_time";
//用户是否同意隐私政策
public static final String PRIVACY_POLICY_AGREED = "privacy_policy_agreed";
//App访问验证code
public static final String APP_ENTER_CODE_VALUE = "app_enter_code_value";
//用户是否允许定位授权
public static final String USER_AUTH_LOCATION = "user_auth_location";
//用户是否请求过定位权限
public static final String USER_REQUEST_LOCATION_PERMISSION = "user_request_location_permission";
//用户是否请求过文件访问权限
public static final String USER_REQUEST_READ_WRITE_PERMISSION = "user_request_read_write_permission";
//用户是否请求过麦克风权限
public static final String USER_REQUEST_RECORD_AUDIO_PERMISSION = "user_request_record_audio_permission";
//用户是否请求过相机权限
public static final String USER_REQUEST_CAMERA_PERMISSION = "user_request_camera_permission";
//用户当前定位省份
public static final String USER_LOCATION_PROVICE_NAME = "user_location_provice_name";
//用户当前定位城市
public static final String USER_LOCATION_CITY_NAME = "user_location_city_name";
//用户当前定位县区
public static final String USER_LOCATION_COUNTY_NAME = "user_location_county_name";
public static final String USER_SELECT_PROVICE_NAME = "user_select_provice_name";
//用户当前定位城市
public static final String USER_SELECT_CITY_NAME = "user_select_city_name";
//用户当前定位县区
public static final String USER_SELECT_COUNTY_NAME = "user_select_county_name";
//首页用户定位code
public static final String INDEX_LOCATION_PROVINCE_CODE = "index_location_province_code";
//用户当前定位县区
public static final String INDEX_LOCATION_CITY_CODE = "index_location_city_code";
//首页用户定位code
public static final String INDEX_SELECT_PROVINCE_CODE = "index_select_province_code";
//用户当前定位县区
public static final String INDEX_SELECT_CITY_CODE = "index_select_city_code";
//用户提交的企业会员认证结果
public static final String USER_REVIEW_STATUS_CODE = "user_review_status_code";
//用户是否为企业会员
public static final String USER_IS_VIP_FLAG = "user_is_vip_flag";
//用户资料中的个人手机号码
public static final String USER_INFO_PHONE_NUMBER = "user_info_phone_number";
//用户资料中头像
public static final String USER_INFO_AVATAR = "user_info_avatar";
//用户资料昵称
public static final String USER_NICKNAME = "user_nickname";
//企业名称
public static final String USER_UPLOAD_COMPANY_NAME = "user_upload_company_name";
//单位名称
public static final String GOODS_UNIT_JSON = "goods_unit_json";
//运费json
public static final String TRANS_COST_JSON = "trans_cost_json";
//品牌名称json
public static final String GOODS_BRAND_JSON = "goods_brand_json";
//所有字典
public static final String MRO_BRAND_DICT_JSON = "mro_dict_json";
/********************大宗相关*********************/
public static final String DICT_DATAS_JSON = "dict_datas_json";
//生成订单来自何处 100商品详情 200购物车
public static final int CREAT_ORDER_FROM_PRODUCT_CODE = 100;
public static final int CREAT_ORDER_FROM_SHOPCAR_CODE = 200;
/********************订单相关*********************/
public static final int ORDER_ALLCODE = -1;//全部
public static final int ORDER_DAIZHIFU = 0;//待支付
public static final int ORDER_WEIFAHUO = 1;//未发货
public static final int ORDER_DAISHOUHUO = 2;//待收货
public static final int ORDER_YIWANCHENG = 3;//已完成
public static final int ORDER_CANCELED = 4;
public static final int ORDER_SHOUHOU = 5;//待收货
public static final int ORDER_BUFENFAHUO = 7;//待收货
public static final int ORDER_DAIQUEREN = 8;//待确认
public static final int ORDER_JIESUANZHONG = 9;//结算中
public static final int ORDER_CHULIZHONG = 0;//处理中
/*******询价单********/
public static final int XJ_BAOJIAZHONG_CODE = 0;//报价中
public static final int XJ_YIBAOJIA_CODE = 1;//已报价
public static final int XJ_YICHEXIAO_CODE = 2;//已撤销
//权限申请请求
public static final int PERMISSION_QUEST = 500;
/***************权限相关*******************/
//地址
public static final int ACCESS_FINE_LOCATION = 1;
//授权读取文件
public static final int WRITE_FILE_PERMISSON_CPDE = 1001;
//读取文件
public static final int READ_EXTERNAL_STORAGE = 2;
//相机权限
public static final int CAMERA_AUTH_CODE = 1003;
//快速下单,下载模板到手机
public static final int DOWN_TEMPLATE_CODE = 1004;
}

View File

@@ -0,0 +1,62 @@
package com.ckkj.water;
/**
* eventbus回调
*/
public class EventMessage {
public static final String DATA_REFRESH_EVENT = "data_refresh_event";
public static final String USER_LOGIN_LOST = "user_login_lost";
public static final String CODE_LOGIN_LOST = "code_login_lost";
public static final String WX_PAY_SUCCESS = "wx_pay_success";
public static final String USER_LOGIN_SUCCESS = "user_login_success";
public static final String HISTORY_SESSIONID_DELETE_SUCCESS = "history_sessionid_delete_success";
public static final String SWITCH_TO_FATE_FRAGMENT = "switch_to_fate_fragment";
public int result_code;
public String eventStrKey;
public String msg;
public String getEventStrKey() {
return eventStrKey;
}
public void setEventStrKey(String eventStrKey) {
this.eventStrKey = eventStrKey;
}
public EventMessage(String msg) {
this.msg = msg;
}
public EventMessage(String eventStr, String msg) {
this.eventStrKey = eventStr;
this.msg = msg;
}
public EventMessage(int result_code, String msg) {
this.result_code = result_code;
this.msg = msg;
}
public int getResult_code() {
return result_code;
}
public void setResult_code(int result_code) {
this.result_code = result_code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}

View File

@@ -0,0 +1,187 @@
package com.ckkj.water;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.gson.Gson;
import com.ckkj.water.fate.util.LunarDateLoader;
import com.ckkj.water.login.entity.LoginEntity;
import com.ckkj.water.network.NetWorkManager;
import com.ckkj.water.utils.dataUtil.SharePreUtil;
import com.ckkj.water.utils.manager.MingDengUserInfoManager;
import java.util.List;
import me.jessyan.autosize.AutoSizeConfig;
public class MyApplication extends Application {
private static Context context;
private static Activity mLaunchActivity;
private static Activity currentActivity;
private static MyApplication instance;
private String TAG = "DINGDINGCAR-----";
//口令跳转
public static boolean hasJumped = false;
public static void setCurrentActivity(Activity activity) {
mLaunchActivity = activity;
}
public static Activity getLaunchActivity() {
return mLaunchActivity;
}
public static synchronized boolean canJump() {
if (!hasJumped) {
hasJumped = true;
return true;
}
return false;
}
public void initializeUmengSDK(){
//预初始化
// UMConfigure.preInit(context, AppConfig.UMENG_APP_KEY, "Android");
// UMConfigure.init(this,"5a12384aa40fa3551f0001d1"
// ,"umeng",UMConfigure.DEVICE_TYPE_PHONE,"");
// //日志开关
// UMConfigure.setLogEnabled(true);
// //科大讯飞 该段初始化代码必须要放在用户还同意隐私协议政策之后
// // 将“12345678”替换成您申请的APPID申请地址http://www.xfyun.cn
// // 请勿在“=”与appid之间添加任何空字符或者转义符
// SpeechUtility.createUtility(context, SpeechConstant.APPID +"=322c51d1");
//初始化厂商推送
}
@Override
public void onCreate() {
super.onCreate();
instance = this;
context = getApplicationContext();
// 异步预加载农历数据缓存
LunarDateLoader.preloadLunarJson(this);
boolean isUserAgreed = SharePreUtil.getBoolean(ConstantUtil.SHARE_PRE_NAME,context,ConstantUtil.PRIVACY_POLICY_AGREED);
if(isUserAgreed){
initializeUmengSDK();
}
NetWorkManager.getInstance().init(this);
AppConfig.USER_LOGIN = SharePreUtil.getBoolean(ConstantUtil.SHARE_PRE_NAME,context,ConstantUtil.USER_LOGIN);
AppConfig.USER_TOKEN = SharePreUtil.getString(ConstantUtil.SHARE_PRE_NAME,context,ConstantUtil.USER_TOKEN);
AppConfig.USER_SET_BIRTH_INFO = SharePreUtil.getBoolean(ConstantUtil.SHARE_PRE_NAME,context,ConstantUtil.USER_HAS_SET_BIRTH);
//单位JSON
AppConfig.PRODUCT_UNIT_JSON = SharePreUtil.getString(ConstantUtil.SHARE_PRE_NAME,context,ConstantUtil.GOODS_UNIT_JSON);
AppConfig.PRODUCT_BRAND_JSON = SharePreUtil.getString(ConstantUtil.SHARE_PRE_NAME,context,ConstantUtil.GOODS_BRAND_JSON);
AppConfig.USER_ID = SharePreUtil.getString(ConstantUtil.SHARE_PRE_NAME,context, ConstantUtil.USER_ID);
String userInfoJson = SharePreUtil.getString(ConstantUtil.SHARE_PRE_NAME,context, ConstantUtil.USER_INFO_JSON_CONTENT);
if(!TextUtils.isEmpty(userInfoJson)){
LoginEntity entity = new Gson().fromJson(userInfoJson, LoginEntity.class);
MingDengUserInfoManager.getInstance().setEntity(entity);
MingDengUserInfoManager.getInstance().setUserInfo(entity.getUser_info());
}
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) {
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
if(activity != null){
Log.i("currentAct", "当前所在页面===============" + activity.getLocalClassName()+ "=======================");
}
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) {
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
}
});
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityResumed(Activity activity) {
currentActivity = activity;
}
@Override
public void onActivityPaused(Activity activity) {
if (currentActivity == activity) {
currentActivity = null;
}
}
// 其他回调方法可以留空
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
currentActivity = activity;
}
@Override
public void onActivityStarted(Activity activity) {
currentActivity = activity;
}
@Override
public void onActivityStopped(Activity activity) {}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
@Override
public void onActivityDestroyed(Activity activity) {}
});
AutoSizeConfig.getInstance()
// 是否使用设备真实尺寸
.setUseDeviceSize(true)
// 是否支持 fragment
.setCustomFragment(true);
}
private boolean shouldInit() {
ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE));
List<ActivityManager.RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
String mainProcessName = getApplicationInfo().processName;
int myPid = android.os.Process.myPid();
for (ActivityManager.RunningAppProcessInfo info : processInfos) {
if (info.pid == myPid && mainProcessName.equals(info.processName)) {
return true;
}
}
return false;
}
public static Activity getCurrentActivity() {
return instance.currentActivity;
}
public static Context getContext() {
return context;
}
}

View File

@@ -0,0 +1,33 @@
package com.ckkj.water.adapter;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.List;
/**
* 作者 fjw
* 日期 2025/3/7
*/
public class ViewPageAdapter extends FragmentStateAdapter {
private List<Fragment> list;
public ViewPageAdapter(@NonNull FragmentActivity fragmentActivity,
List<Fragment> fragmentList) {
super(fragmentActivity);
list = fragmentList;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return list.get(position);
}
@Override
public int getItemCount() {
return list.size();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,440 @@
package com.ckkj.water.base;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.viewbinding.ViewBinding;
import com.ckkj.water.ConstantUtil;
import com.ckkj.water.R;
import com.ckkj.water.dialog.LoadingDialog;
import com.ckkj.water.receiver.NetworkChangeReceiver;
import com.ckkj.water.utils.manager.ActivityManager;
import com.ckkj.water.utils.permissions.PermissionUtils;
import com.ckkj.water.utils.show.ToastUtil;
import com.ckkj.water.utils.text.TextUtil;
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
/**
* 所有activity基类
*/
@SuppressWarnings({ "unchecked" }) public abstract class BaseActivityNoP<T extends ViewBinding>
extends RxAppCompatActivity implements IView {
//P层主导
protected Dialog loadingDialog;
private NetworkChangeReceiver receiver;
public static IView iView;
public TextView tipTextView;
protected T viewBinding;
protected BaseActivityNoP mContext;
@Override protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
mContext = this;
ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();
Class cls = (Class) type.getActualTypeArguments()[0];
Method inflate = cls.getDeclaredMethod("inflate", LayoutInflater.class);
viewBinding = (T) inflate.invoke(null, getLayoutInflater());
setContentView(viewBinding.getRoot());
//在界面初始化之前初始化窗口
initWindows();
int layoutResID = getLayoutResId(savedInstanceState);
if (layoutResID != 0) {
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
// setContentView(layoutResID);
}
} catch (Exception e) {
e.printStackTrace();
}
initWidget();
initData(savedInstanceState);
}
/**
* 初始化窗口
*/
protected void initWindows() {
//StatusBarUtils.setWindowStatusBarColor(this, R.color.color_blue01);
// StatusBarUtil.setAndroidNativeLightStatusBar(this, true);
}
protected void initWidget() {
ActivityManager.addActivity(this, this.getClass().getName());
iView = this;
if (receiver == null) {
receiver = new NetworkChangeReceiver();
}
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(receiver, filter);
}
@Override protected void onDestroy() {
unregisterReceiver(receiver);
hideDialogLoading();
super.onDestroy();
}
/***
* 关闭等待页面
*/
public void hideDialogLoading() {
LoadingDialog dialog = mLoadingDialog;
try {
if (dialog != null && mContext != null) {
mLoadingDialog = null;
dialog.dismiss();
}
} catch (Exception e) {
e.printStackTrace();
}
}
//每个activity都需要创建setLayoutId
public abstract int getLayoutResId(Bundle savedInstanceState);
public void initData(Bundle savedInstanceState) {
createLoadingDialog(this, "加载中...");
}
/**
* 模拟显示加载对话框
*/
@Override public void showLoading() {
loadingDialog.show();
}
//模拟处理统一的数据
@Override public void handleError(Exception e) {
e.printStackTrace();
hideLoading();
showMessage(e.getMessage());
}
@Override public void hideLoading() {
loadingDialog.dismiss();
}
@Override public void showMessage(String message) {
ToastUtil.showShort(this, message);
}
//加载进度
protected void createLoadingDialog(Context context, String msg) {
LayoutInflater inflater = LayoutInflater.from(context);
@SuppressLint("InflateParams") View v = inflater.inflate(R.layout.dialog_loading, null);
LinearLayout layout = (LinearLayout) v.findViewById(R.id.dialog_loading_view);
tipTextView = (TextView) v.findViewById(R.id.tipTextView);
tipTextView.setText(msg);
ImageView imgLoading = v.findViewById(R.id.img_loading);
loadingDialog = new Dialog(context, R.style.MyDialogStyle);
loadingDialog.setCanceledOnTouchOutside(false);
loadingDialog.setContentView(layout,
new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
Window window = loadingDialog.getWindow();
if (window != null) {
WindowManager.LayoutParams lp = window.getAttributes();
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setGravity(Gravity.CENTER);
window.setAttributes(lp);
window.setWindowAnimations(R.style.PopWindowAnimStyle);
}
loadingDialog.setCanceledOnTouchOutside(false);
}
protected LoadingDialog mLoadingDialog;
public void showLoadingDialog() {
LoadingDialog dialog = mLoadingDialog;
if (dialog == null&& mContext != null) {
dialog = new LoadingDialog(mContext);
// 不可触摸取消
dialog.setCanceledOnTouchOutside(false);
// 强制取消关闭界面
dialog.setCancelable(true);
dialog.setOnCancelListener(dialog1 -> finish());
mLoadingDialog = dialog;
} else {
dialog.dismiss();
}
if (dialog != null && mContext != null) {
try {
dialog.show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override public void onNetChange(int netModel) {
}
@Override public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
View view = getCurrentFocus();
TextUtil.hideKeyboard(ev, view, this);//调用方法判断是否需要隐藏键盘
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}
/**
* activity跳转
*/
protected void goTo(Context from, Class<? extends BaseActivityNoP> to, Bundle data) {
Intent i = new Intent();
i.setClass(from, to);
if (data != null) i.putExtras(data);
from.startActivity(i);
}
/**
* activity跳转
*/
protected void goToWihoutNoBase(Context from, Class<? extends Activity> to, Bundle data) {
Intent i = new Intent();
i.setClass(from, to);
if (data != null) i.putExtras(data);
from.startActivity(i);
}
/**
* 跳转返回值
*/
protected void goToForResult(Context from, Class<? extends BaseActivityNoP> to, int questCode,
Bundle bundle) {
Intent i = new Intent();
i.setClass(from, to);
if (bundle != null) i.putExtras(bundle);
startActivityForResult(i, questCode);
}
protected void requestPermission(String... permissions) {
if (PermissionUtils.isPermissionsGranted(this, ConstantUtil.PERMISSION_QUEST, permissions)) {
Log.d("permission", "all");
nextStep();
}
}
public void noAllowPermission() {
}
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case ConstantUtil.PERMISSION_QUEST:
if (PermissionUtils.verifyPermissions(grantResults)) {
nextStep();
}else {
noAllowPermission();
}
break;
default:
break;
}
}
public interface OnDialogClick {
void onCancelClick();
void onConfirmClisk();
void onView1Click();
}
/**+
*
* @param title 标题
* @param content 提示内容
* @param hint 提示内容2
* @param type 弹窗类型
* @param cancelText 取消 文案
* @param confirmText 确定 文案
* @param click
*/
public void showDialog(String title, String content, String hint, String type,String cancelText,String confirmText, final OnDialogClick click) {
}
public Dialog dialog = null;
// 弹出一个确认对话框 并可以设置取消按钮事件
public void showDialogtext(String title, String content, String okText, String cancelText, final OnDialogClick click) {
View view = getLayoutInflater().inflate(R.layout.public_dialog_confirm, null);
setTextView(R.id.tv_title, title, view);
setTextView(R.id.tv_content, content, view);
// ((EditText) view.findViewById(R.id.txtContent)).setText(cancelText);
if(!TextUtils.isEmpty(okText) && !TextUtils.isEmpty(cancelText)){
((TextView) view.findViewById(R.id.btnLeft)).setText(cancelText);
((TextView) view.findViewById(R.id.btnRight)).setText(okText);
}
view.findViewById(R.id.btnLeft).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (dialog != null && dialog.isShowing())
dialog.dismiss();
if (click != null)
click.onCancelClick();
}
});
view.findViewById(R.id.btnRight).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (dialog != null && dialog.isShowing())
dialog.dismiss();
if (click != null)
click.onConfirmClisk();
}
});
view.findViewById(R.id.tv_click).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (dialog != null && dialog.isShowing())
if (click != null)
click.onView1Click();
}
});
AlertDialog.Builder builder = null;//new AlertDialog.Builder(this, android.R.style.Theme_Holo_Dialog);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
builder = new AlertDialog.Builder(this, AlertDialog.THEME_HOLO_LIGHT);
} else {
builder = new AlertDialog.Builder(this);
}
builder.setInverseBackgroundForced(true);
builder.setView(view);
dialog = builder.show();
try {
((View) dialog.getWindow().getDecorView().findViewById(R.id.contentDialog).getParent().getParent()).setBackgroundColor(getResources().getColor(R.color.transparent));
} catch (Exception e) {
}
}
// 弹出一个确认对话框 并可以设置取消按钮事件
public void showDialogtext(Drawable imgRes, boolean isIconShow, boolean isTextShow, String title, String content, String okText, String cancelText,
final BaseFragment.OnDialogClick click) {
View view = getLayoutInflater().inflate(R.layout.public_dialog_index_permis, null);
ImageView imgIcon = view.findViewById(R.id.img_dialog_icon);
TextView tvOther = view.findViewById(R.id.tv_click);
if(isIconShow){
imgIcon.setVisibility(View.VISIBLE);
if(imgRes != null ){
imgIcon.setImageDrawable(imgRes);
}
}else{
imgIcon.setVisibility(View.GONE);
}
if(isTextShow){
tvOther.setVisibility(View.VISIBLE);
}else{
tvOther.setVisibility(View.GONE);
}
setTextView(R.id.tv_title, title, view);
setTextView(R.id.tv_content, content, view);
// ((EditText) view.findViewById(R.id.txtContent)).setText(cancelText);
if (!TextUtils.isEmpty(okText) && !TextUtils.isEmpty(cancelText)) {
((TextView) view.findViewById(R.id.btnLeft)).setText(okText);
((TextView) view.findViewById(R.id.btnRight)).setText(cancelText);
}
view.findViewById(R.id.btnLeft).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (dialog != null && dialog.isShowing())
dialog.dismiss();
if (click != null)
click.onCancelClick();
}
});
view.findViewById(R.id.btnRight).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (dialog != null && dialog.isShowing())
dialog.dismiss();
if (click != null)
click.onConfirmClick();
}
});
AlertDialog.Builder builder = null;//new AlertDialog.Builder(this, android.R.style.Theme_Holo_Dialog);
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();
try {
((View) dialog.getWindow().getDecorView().findViewById(R.id.contentDialog).getParent().getParent()).setBackgroundColor(getResources().getColor(R.color.transparent));
} catch (Exception e) {
}
}
/**
* 设置指定TextView的文本
*
* @param id
* @param value textView的值
*/
public void setTextView(int id, String value, View view) {
try {
if (!TextUtils.isEmpty(value)) {
value = value.replaceAll("null", "");
((TextView) view.findViewById(id)).setText(value);
} else {
((TextView) view.findViewById(id)).setText("");
((TextView) view.findViewById(id)).setVisibility(View.GONE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void nextStep() {
}
}

View File

@@ -0,0 +1,890 @@
package com.ckkj.water.base;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.viewbinding.ViewBinding;
import com.esafirm.imagepicker.features.ImagePicker;
import com.ckkj.water.AppConfig;
import com.ckkj.water.ConstantUtil;
import com.ckkj.water.EventMessage;
import com.ckkj.water.R;
import com.ckkj.water.dialog.LoadingDialog;
import com.ckkj.water.login.LoginActivity;
import com.ckkj.water.utils.dataUtil.SharePreUtil;
import com.ckkj.water.utils.manager.ActivityManager;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import de.greenrobot.event.EventBus;
import de.greenrobot.event.Subscribe;
import de.greenrobot.event.ThreadMode;
import pub.devrel.easypermissions.EasyPermissions;
/**
* 所有Fragment基类
* @param <P>
*/
@SuppressWarnings({ "unchecked" })
public abstract class BaseFragment<T extends ViewBinding,P extends IPresenter> extends Fragment implements IView, EasyPermissions.PermissionCallbacks {
protected String TAG = "MING_DENG";
protected Activity activity;
protected P mPresenter;
protected Dialog loadingDialog;
protected T viewBinding;
protected Activity mContext;
protected final int REQUEST_CODE_100 = 100;
protected final int REQUEST_CODE_200 = 200;
protected static final int REQUEST_EVENT_CODE_10001 = 10001;
protected static final int REQUEST_EVENT_CODE_10002 = 10002;
protected static final int REQUEST_EVENT_CODE_10003 = 10003;
private static final AtomicBoolean isDialogShown = new AtomicBoolean(false); // 使用 AtomicBoolean 保证线程安全
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
initArgs(getArguments());
}
@Override
public void onResume() {
super.onResume();
onResumeInitData();
}
public boolean hasRecordPermission(String permission) {
return EasyPermissions.hasPermissions(mContext, permission);
}
/**
* 获取权限
*
* @param permis
* @param title
* @param content
* @param requestCode String... permis
*/
public void getPermissionRequst(String permis, String title, String content, int requestCode) {
if (EasyPermissions.hasPermissions(mContext, permis)) {
// 已有权限,不需要处理
return;
}
// 还没权限,弹自定义确认弹窗
showDialogtext(mContext.getResources().getDrawable(R.mipmap.img_location),
false, false,
title,
content,
"不允许", "允许",
new BaseFragment.OnDialogClick() {
@Override
public void onCancelClick() {
// 用户点了"不允许",什么都不用做
}
@Override
public void onConfirmClick() {
showPermissionDialog(mContext.getResources().getDrawable(R.mipmap.img_permission_file),
true, title, content);
// 用户点了"允许",继续判断
if (ActivityCompat.shouldShowRequestPermissionRationale(mContext, permis)) {
// 用户之前拒绝过,但没勾"不再询问" ➔ 直接请求权限
// 修复第一个参数应该是Fragment本身而不是Activity的context
EasyPermissions.requestPermissions(BaseFragment.this, content, requestCode, permis);
} else {
// 可能是第一次申请,也可能是勾了"不再询问"
// 用EasyPermissions继续请求系统自己决定弹不弹
// 修复第一个参数应该是Fragment本身而不是Activity的context
EasyPermissions.requestPermissions(BaseFragment.this, content, requestCode, permis);
}
}
});
}
/**
* 判断Fragment是否真正对用户可见
*/
protected boolean isFragmentVisible() {
return isVisible() && isResumed();
}
/**
* 可见时初始化数据
*/
protected void onResumeInitData() {
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
createLoadingDialog(getActivity());
mPresenter = createPresenter();//创建presenter
}
@Nullable
@Override
public View onCreateView(@Nullable LayoutInflater inflater,@Nullable ViewGroup container,@Nullable Bundle state) {
mContext = getActivity();
activity = getActivity();
EventBus.getDefault().register(this);
ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();
Class cls = (Class) type.getActualTypeArguments()[0];
try {
Method inflate = cls.getDeclaredMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class);
viewBinding = (T) inflate.invoke(null, inflater, container, false);
} catch (NoSuchMethodException | IllegalAccessException| InvocationTargetException e) {
e.printStackTrace();
}
initView();
return viewBinding.getRoot();
}
@Subscribe(threadMode = ThreadMode.MainThread)
public void onGetMessage(EventMessage message) {
Log.d("DINGDING", "BaseFragment收到EventBus消息: " + message.msg);
if (message.msg.equals(EventMessage.USER_LOGIN_LOST)) {
Log.d("DINGDING","Fragment接收一次");
Log.d("DINGDING", "当前Fragment状态: isDetached=" + isDetached() + ", isRemoving=" + isRemoving());
// 检查Fragment状态如果正在销毁则不处理
if (isDetached() || isRemoving()) {
Log.d("DINGDING", "Fragment正在销毁跳过处理");
return;
}
// 检查Activity状态如果Activity正在销毁则不处理
if (mContext == null || mContext.isFinishing() || mContext.isDestroyed()) {
Log.d("DINGDING", "Fragment所属Activity正在销毁跳过处理");
return;
}
if (isDialogShown.compareAndSet(false, true)) {
Log.d("DINGDING","Fragment触发弹窗");
AppConfig.USER_LOGIN = false;
AppConfig.MEMBER_ID = 0;
AppConfig.USER_TOKEN = "";
AppConfig.USER_ID = "";
SharePreUtil.putBoolean(ConstantUtil.SHARE_PRE_NAME, mContext, ConstantUtil.USER_LOGIN, AppConfig.USER_LOGIN);
// 确保在主线程中执行
mContext.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
// 再次检查Fragment和Activity状态
if (isDetached() || isRemoving() || mContext == null || mContext.isFinishing() || mContext.isDestroyed()) {
Log.d("DINGDING", "Fragment或Activity已销毁取消弹窗");
isDialogShown.set(false);
return;
}
showDialogtextInterBackKey(null, false, false,
"提示",
"检测到您的账号在异地登录。若非本人操作,请立即修改密码并检查账号安全!",
"我知道了", "", // 交换参数位置
new OnDialogClick() {
@Override
public void onCancelClick() {
Log.d("DINGDING", "用户点击取消");
}
@Override
public void onConfirmClick() {
Log.d("DINGDING", "用户点击确定");
ActivityManager.removeAllActivityExceptMain();
goTo(mContext, LoginActivity.class, null);
isDialogShown.set(false);
}
}, true);
Log.d("DINGDING", "Fragment弹窗显示成功");
} catch (Exception e) {
Log.e("DINGDING", "Fragment弹窗显示失败", e);
isDialogShown.set(false);
}
}
});
} else {
Log.d("DINGDING", "Fragment弹窗已显示跳过");
}
} else if (message.msg.equals(EventMessage.CODE_LOGIN_LOST)) {
// 检查是否满足跳转条件
// if (MyApplication.canJump()) { // MyApplication is not defined in this file
// }
}
}
/**
* 初始化控件
*/
protected void initView() {
}
/**
* activity跳转
*/
protected void goToWihoutNoPresent(Context from, Class<? extends BaseActivityNoP> to, Bundle data) {
Intent i = new Intent();
i.setClass(from, to);
if (data != null) i.putExtras(data);
from.startActivity(i);
}
protected LoadingDialog mLoadingDialog;
public void showLoadingDialog() {
LoadingDialog dialog = mLoadingDialog;
if (dialog == null&& mContext != null) {
dialog = new LoadingDialog(mContext);
// 不可触摸取消
dialog.setCanceledOnTouchOutside(false);
// 强制取消关闭界面
dialog.setCancelable(true);
// dialog.setOnCancelListener(dialog1 -> finish());
mLoadingDialog = dialog;
} else {
dialog.dismiss();
}
if (dialog != null && mContext != null) {
try {
dialog.show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
protected void createLoadingDialog(Context context){
LayoutInflater inflater = LayoutInflater.from(context);
@SuppressLint("InflateParams") View v = inflater.inflate(R.layout.dialog_loading, null);
LinearLayout layout = (LinearLayout) v.findViewById(R.id.dialog_loading_view);
ImageView imgLoading = v.findViewById(R.id.img_loading);
loadingDialog = new Dialog(context, R.style.MyDialogStyle);
loadingDialog.setCanceledOnTouchOutside(false);
loadingDialog.setContentView(layout,
new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
Window window = loadingDialog.getWindow();
if (window != null) {
WindowManager.LayoutParams lp = window.getAttributes();
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setGravity(Gravity.CENTER);
window.setAttributes(lp);
window.setWindowAnimations(R.style.PopWindowAnimStyle);
}
loadingDialog.setCanceledOnTouchOutside(false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (mPresenter != null) {
mPresenter.attachView(this);
}
initData(savedInstanceState);
}
public void imagePicker(int limitCount,int requestCode,Fragment fragment){
//获取相册
ImagePicker.create(fragment)
.folderMode(false)
.showCamera(false).limit(limitCount)
.start(requestCode);
String[] permis = {Manifest.permission.READ_EXTERNAL_STORAGE};
// if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
// //获取到了权限,可以请求地址显示
// if (EasyPermissions.hasPermissions(mContext, permis)) {
//
// }else{
// showDialogtext(mContext.getResources().getDrawable(R.mipmap.img_location), false, false,
// "相册访问权限", "超越仓需要您的授权,访问相册来上传资料",
// "不允许", "允许", new BaseFragment.OnDialogClick() {
// @Override
// public void onCancelClick() {
//
// }
//
// @Override
// public void onConfirmClick() {
// if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
//// Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
//// mContext.startActivity(intent);
// EasyPermissions.requestPermissions(mContext, "应用需要获相册授权",
// ConstantUtil.READ_EXTERNAL_STORAGE
// , Manifest.permission.READ_EXTERNAL_STORAGE);
// } else {
// EasyPermissions.requestPermissions(mContext, "应用需要获相册授权",
// ConstantUtil.READ_EXTERNAL_STORAGE
// , Manifest.permission.READ_EXTERNAL_STORAGE);
// }
// }
// });
// }
//// XXPermissions.with(mContext)
//// // 申请单个权限
//// .permission(Permission.READ_EXTERNAL_STORAGE)
//// .interceptor(new PermissionInterceptor())
//// .request(new OnPermissionCallback() {
//// @Override
//// public void onGranted(List<String> permissions, boolean all) {
////
//// }
////
//// @Override
//// public void onDenied(List<String> permissions, boolean never) {
//// if (never) {
//// Toast.makeText(mContext, "被永久拒绝授权,请手动授予权限", Toast.LENGTH_SHORT).show();
//// // 如果是被永久拒绝就跳转到应用权限系统设置页面
//// XXPermissions.startPermissionActivity(mContext, permissions);
//// } else {
//// Toast.makeText(mContext, "获取权限失败", Toast.LENGTH_SHORT).show();
//// }
//// return;
//// }
//// });
//
// } else {
// //获取到了权限,可以请求地址显示
// if (EasyPermissions.hasPermissions(mContext, permis)) {
// //获取相册
// ImagePicker.create(fragment)
// .folderMode(false)
// .showCamera(false).limit(limitCount)
// .start(requestCode);
// } else {
// showDialogtext(mContext.getResources().getDrawable(R.mipmap.img_location), false, false,
// "相册访问权限", "超越仓需要您的授权,访问相册来上传资料",
// "不允许", "允许", new BaseFragment.OnDialogClick() {
// @Override
// public void onCancelClick() {
//
// }
//
// @Override
// public void onConfirmClick() {
// if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
// Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
// mContext.startActivity(intent);
// } else {
// EasyPermissions.requestPermissions(mContext, "应用需要获相册授权",
// ConstantUtil.READ_EXTERNAL_STORAGE
// , Manifest.permission.READ_EXTERNAL_STORAGE);
// }
// }
// });
// }
// }
}
public Dialog dialog = null;
// 弹出一个确认对话框 并可以设置取消按钮事件
public void showDialogtext(Drawable imgRes,boolean isIconShow, boolean isTextShow, String title,
String content, String okText, String cancelText,
final OnDialogClick click) {
View view = getLayoutInflater().inflate(R.layout.public_dialog_index_permis, null);
ImageView imgIcon = view.findViewById(R.id.img_dialog_icon);
TextView tvOther = view.findViewById(R.id.tv_click);
TextView tvLeft = view.findViewById(R.id.btnLeft);
if(isIconShow){
imgIcon.setVisibility(View.VISIBLE);
if(imgRes != null ){
imgIcon.setImageDrawable(imgRes);
}
}else{
imgIcon.setVisibility(View.GONE);
}
if(isTextShow){
tvOther.setVisibility(View.VISIBLE);
}else{
tvOther.setVisibility(View.GONE);
}
setTextView(R.id.tv_title, title, view);
setTextView(R.id.tv_content, content, view);
// ((EditText) view.findViewById(R.id.txtContent)).setText(cancelText);
if (!TextUtils.isEmpty(okText) && !TextUtils.isEmpty(cancelText)) {
((TextView) view.findViewById(R.id.btnLeft)).setText(okText);
((TextView) view.findViewById(R.id.btnRight)).setText(cancelText);
}
view.findViewById(R.id.btnLeft).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (dialog != null && dialog.isShowing())
dialog.dismiss();
if (click != null)
click.onCancelClick();
}
});
view.findViewById(R.id.btnRight).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (dialog != null && dialog.isShowing())
dialog.dismiss();
if (click != null)
click.onConfirmClick();
}
});
if(!TextUtils.isEmpty(cancelText)){
tvLeft.setVisibility(View.VISIBLE);
}else{
tvLeft.setVisibility(View.GONE);
}
AlertDialog.Builder builder = null;//new AlertDialog.Builder(this, android.R.style.Theme_Holo_Dialog);
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(false);
try {
((View) dialog.getWindow().getDecorView().findViewById(R.id.contentDialog).getParent().getParent()).setBackgroundColor(getResources().getColor(R.color.transparent));
} catch (Exception e) {
}
}
/**
* 强制登出,并且拦截返回键
* @param imgRes
* @param isIconShow
* @param isTextShow
* @param title
* @param content
* @param okText
* @param cancelText
* @param click
* @param interceptBackKey
*/
public void showDialogtextInterBackKey(Drawable imgRes, boolean isIconShow, boolean isTextShow, String title,
String content, String okText, String cancelText,
final OnDialogClick click, boolean interceptBackKey) {
View view = getLayoutInflater().inflate(R.layout.public_dialog_index_permis, null);
ImageView imgIcon = view.findViewById(R.id.img_dialog_icon);
TextView tvOther = view.findViewById(R.id.tv_click);
TextView tvLeft = view.findViewById(R.id.btnLeft);
if (isIconShow) {
imgIcon.setVisibility(View.VISIBLE);
if (imgRes != null) {
imgIcon.setImageDrawable(imgRes);
}
} else {
imgIcon.setVisibility(View.GONE);
}
tvOther.setVisibility(isTextShow ? View.VISIBLE : View.GONE);
setTextView(R.id.tv_title, title, view);
setTextView(R.id.tv_content, content, view);
if (!TextUtils.isEmpty(okText) && !TextUtils.isEmpty(cancelText)) {
((TextView) view.findViewById(R.id.btnLeft)).setText(okText);
((TextView) view.findViewById(R.id.btnRight)).setText(cancelText);
}
view.findViewById(R.id.btnLeft).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (dialog != null && dialog.isShowing())
dialog.dismiss();
if (click != null)
click.onCancelClick();
}
});
view.findViewById(R.id.btnRight).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (dialog != null && dialog.isShowing())
dialog.dismiss();
if (click != null)
click.onConfirmClick();
}
});
tvLeft.setVisibility(TextUtils.isEmpty(cancelText) ? View.GONE : View.VISIBLE);
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(false);
// 🔒 返回键拦截逻辑
if (interceptBackKey) {
dialog.setCancelable(false);
dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialogInterface, int keyCode, KeyEvent event) {
return keyCode == KeyEvent.KEYCODE_BACK;
}
});
}
try {
((View) dialog.getWindow().getDecorView()
.findViewById(R.id.contentDialog)
.getParent().getParent())
.setBackgroundColor(getResources().getColor(R.color.transparent));
} catch (Exception e) {
// 安全兜底
}
}
public void showPermissionDialog(Drawable imgRes,boolean isIconShow, String title,
String content) {
View view = getLayoutInflater().inflate(R.layout.permisson_top_dialog, null);
ImageView imgIcon = view.findViewById(R.id.img_permission_icon);
TextView tvTitle = view.findViewById(R.id.tv_permission_title);
TextView tvContent = view.findViewById(R.id.tv_permission_content);
tvTitle.setText(title);
tvContent.setText(content);
if(isIconShow){
imgIcon.setVisibility(View.VISIBLE);
if(imgRes != null ){
imgIcon.setImageDrawable(imgRes);
}
}else{
imgIcon.setVisibility(View.GONE);
}
AlertDialog.Builder builder = null;//new AlertDialog.Builder(this, android.R.style.Theme_Holo_Dialog);
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.create();
// 获取 dialog 的 Window 对象
Window window = dialog.getWindow();
if (window != null) {
// 设置 dialog 在屏幕顶部显示
WindowManager.LayoutParams params = window.getAttributes();
params.gravity = Gravity.TOP; // 设置对话框顶部显示
window.setAttributes(params);
}
// 显示 AlertDialog
dialog.show();
// dialog = builder.show();
try {
((View) dialog.getWindow().getDecorView().findViewById(R.id.contentDialog).getParent().getParent()).setBackgroundColor(getResources().getColor(R.color.transparent));
} catch (Exception e) {
}
}
/**
* 设置指定TextView的文本
*
* @param id
* @param value textView的值
*/
public void setTextView(int id, String value, View view) {
try {
if (!TextUtils.isEmpty(value)) {
value = value.replaceAll("null", "");
((TextView) view.findViewById(id)).setText(value);
((TextView) view.findViewById(id)).setVisibility(View.VISIBLE);
} else {
((TextView) view.findViewById(id)).setText("");
((TextView) view.findViewById(id)).setVisibility(View.GONE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public interface OnDialogClick {
public void onCancelClick();
public void onConfirmClick();
}
/**
* 初始化参数
* @param bundle 需要初始化的参数
*/
protected void initArgs(Bundle bundle) {
}
/**
* 初始化控件
*/
protected void initWidget(View root) {
}
/**
* 初始化views
*
* @param state
*/
public abstract void initData(Bundle state);
public abstract P createPresenter();
@Override
public void onDestroy() {
EventBus.getDefault().unregister(this);
if (mPresenter != null) {
mPresenter.onDestroy();//释放资源
}
this.mPresenter = null;
hideDialogLoading();
// 重置弹窗状态让其他Fragment可以显示弹窗
isDialogShown.set(false);
super.onDestroy();
}
@Override public void onDestroyView() {
super.onDestroyView();
//此处try catch 是因为unbinder.unbind() 在清空状态下,会造成崩溃
//其他处不影响使用
try {
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDetach() {
super.onDetach();
this.activity = null;
}
@Override
public void showLoading() {
loadingDialog.show();
}
@Override
public void hideLoading() {
loadingDialog.dismiss();
}
@Override
public void showMessage(String message) {
}
@Override
public void handleError(Exception e) {
hideLoading();
showMessage(e.getMessage());
e.printStackTrace();
}
/**
* 跳转
*
* @param data 携带数据
*/
protected void goTo(Context from, Class<? extends BaseActivity> to, Bundle data) {
Intent i = new Intent();
i.setClass(from, to);
if(data!=null) i.putExtras(data);
from.startActivity(i);
}
/**
* 跳转返回
*
*
*/
protected void goToForResult(Context from, Class<? extends BaseActivity> to, int questCode, Bundle data) {
Intent i = new Intent();
i.setClass(from, to);
if(data!=null) i.putExtras(data);
startActivityForResult(i,questCode);
}
/***
* 关闭等待页面
*/
public void hideDialogLoading() {
LoadingDialog dialog = mLoadingDialog;
try {
if (dialog != null && mContext != null) {
mLoadingDialog = null;
dialog.dismiss();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void hidePermissionDialog(){
if(dialog != null && dialog.isShowing()){
dialog.dismiss();
}
}
public void clearLoginInfo(){
AppConfig.USER_LOGIN = false;
SharePreUtil.putString(ConstantUtil.SHARE_PRE_NAME,mContext,ConstantUtil.USER_INFO_PHONE_NUMBER,"");
SharePreUtil.putString(ConstantUtil.SHARE_PRE_NAME,mContext,ConstantUtil.USER_UPLOAD_COMPANY_NAME,"未登录");
}
/**
* 处理登录丢失的统一方法
* 子类可以直接调用此方法来处理401错误
*/
protected void handleLoginLost() {
Log.d("DINGDING", "BaseFragment.handleLoginLost() 被调用");
// 检查Fragment状态
if (isDetached() || isRemoving()) {
Log.d("DINGDING", "Fragment正在销毁跳过处理");
return;
}
// 检查Activity状态
if (mContext == null || mContext.isFinishing() || mContext.isDestroyed()) {
Log.d("DINGDING", "Fragment所属Activity正在销毁跳过处理");
return;
}
// 重置登录信息
resetLoginInfo();
// 显示401弹窗
show401Dialog();
}
/**
* 重置登录信息
*/
private void resetLoginInfo() {
AppConfig.USER_LOGIN = false;
AppConfig.MEMBER_ID = 0;
AppConfig.USER_TOKEN = "";
AppConfig.USER_ID = "";
SharePreUtil.putBoolean(ConstantUtil.SHARE_PRE_NAME, mContext, ConstantUtil.USER_LOGIN, AppConfig.USER_LOGIN);
Log.d("DINGDING", "登录信息已重置");
}
/**
* 显示401弹窗
*/
private void show401Dialog() {
if (mContext == null || mContext.isFinishing() || mContext.isDestroyed()) {
Log.d("DINGDING", "Activity状态异常无法显示弹窗");
return;
}
mContext.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
// 再次检查状态
if (isDetached() || isRemoving() || mContext == null || mContext.isFinishing() || mContext.isDestroyed()) {
Log.d("DINGDING", "Fragment或Activity已销毁取消弹窗");
return;
}
showDialogtextInterBackKey(null, false, false,
"提示",
"检测到您的账号在异地登录。若非本人操作,请立即修改密码并检查账号安全!",
"我知道了", "",
new OnDialogClick() {
@Override
public void onCancelClick() {
Log.d("DINGDING", "用户点击取消");
}
@Override
public void onConfirmClick() {
Log.d("DINGDING", "用户点击确定");
ActivityManager.removeAllActivityExceptMain();
goTo(mContext, LoginActivity.class, null);
}
}, true);
Log.d("DINGDING", "BaseFragment 401弹窗显示成功");
} catch (Exception e) {
Log.e("DINGDING", "BaseFragment 401弹窗显示失败", e);
}
}
});
}
/**
* 权限请求结果回调
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// 将权限结果传递给EasyPermissions处理
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
/**
* 权限被授予时的回调
*/
@Override
public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
// 这个方法会在子Fragment中重写这里可以留空或者提供默认实现
}
/**
* 权限被拒绝时的回调
*/
@Override
public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
// 这个方法会在子Fragment中重写这里可以留空或者提供默认实现
}
}

View File

@@ -0,0 +1,31 @@
package com.ckkj.water.base;
public abstract class BasePresenter<V extends IView> implements IPresenter<V> {
//View 显示回显的接口
protected V mRootView;
public BasePresenter() {
onStart();
}
@Override
public void onStart() {
}
@Override
public void onDestroy() {
this.mRootView = null;
}
@Override
public void attachView(V view) {
this.mRootView = view;
}
@Override
public V getView() {
return mRootView;
}
}

View File

@@ -0,0 +1,21 @@
package com.ckkj.water.base;
public interface IPresenter<T extends IView> {
/**
* 做一些初始化操作
*/
void onStart();
/**
* 销毁
*/
void onDestroy();
/**
* 绑定View
*/
void attachView(T view);
T getView();
}

View File

@@ -0,0 +1,47 @@
package com.ckkj.water.base;
import com.ckkj.water.network.BaseBean;
public interface IView {
/**
* 网络状态改变时的回调
* @param netModel
*/
void onNetChange(int netModel);
/**
* 显示加载
*/
void showLoading();
/**
* 隐藏加载
*/
void hideLoading();
/**
* 显示信息
* @param message
*/
void showMessage(String message);
/**
* 显示错误信息
* @param message
*/
void showError(String message);
/**
* 统一消息处理
* @param e
*/
void handleError(Exception e);
/**
* 登录失效
* @param
*/
void logOut(BaseBean bean);
}

View File

@@ -0,0 +1,51 @@
package com.ckkj.water.base.entity;
import java.io.Serializable;
/**
* @author fengxiaoyang
* @date 2025/7/28
* @description TODO: 描述该类的作用
*/
public class MineUserInfoBean implements Serializable {
private UserInfoEntity userInfo;
private boolean hasEightCharacters;
private String constellation;
private String birthTime;
public String getConstellation() {
return constellation;
}
public void setConstellation(String constellation) {
this.constellation = constellation;
}
public String getBirthTime() {
return birthTime;
}
public void setBirthTime(String birthTime) {
this.birthTime = birthTime;
}
public UserInfoEntity getUserInfo() {
return userInfo;
}
public void setUserInfo(UserInfoEntity userInfo) {
this.userInfo = userInfo;
}
public boolean isHasEightCharacters() {
return hasEightCharacters;
}
public void setHasEightCharacters(boolean hasEightCharacters) {
this.hasEightCharacters = hasEightCharacters;
}
}

View File

@@ -0,0 +1,279 @@
package com.ckkj.water.base.entity;
import java.io.Serializable;
/**
* @author fengxiaoyang
* @date 2025/7/21
* @description TODO: 描述该类的作用
*/
public class UserInfoEntity implements Serializable {
private String name;
private String gender;
private String genderText;
private String birthType;
private String birthTypeText;
private String birthTime;
private String birthPlace;
private String currentPlace;
private String trueSolarTime;
private String longitude;
private String latitude;
private String constellation;
private BaziSizhu baziSizhu;
private long userId;
private String mobile;
private String username;
private String nickname;
private String email;
private int status;
private String registerTime;
private String updateTime;
private int membershipStatus;
private String membershipExpireTime;
private String inviteCode;
private String userRole;
private String avatar;
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getRegisterTime() {
return registerTime;
}
public void setRegisterTime(String registerTime) {
this.registerTime = registerTime;
}
public String getUpdateTime() {
return updateTime;
}
public void setUpdateTime(String updateTime) {
this.updateTime = updateTime;
}
public int getMembershipStatus() {
return membershipStatus;
}
public void setMembershipStatus(int membershipStatus) {
this.membershipStatus = membershipStatus;
}
public String getMembershipExpireTime() {
return membershipExpireTime;
}
public void setMembershipExpireTime(String membershipExpireTime) {
this.membershipExpireTime = membershipExpireTime;
}
public String getInviteCode() {
return inviteCode;
}
public void setInviteCode(String inviteCode) {
this.inviteCode = inviteCode;
}
public String getUserRole() {
return userRole;
}
public void setUserRole(String userRole) {
this.userRole = userRole;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getGender() {
return gender;
}
public void setGenderText(String genderText) {
this.genderText = genderText;
}
public String getGenderText() {
return genderText;
}
public void setBirthType(String birthType) {
this.birthType = birthType;
}
public String getBirthType() {
return birthType;
}
public void setBirthTypeText(String birthTypeText) {
this.birthTypeText = birthTypeText;
}
public String getBirthTypeText() {
return birthTypeText;
}
public void setBirthTime(String birthTime) {
this.birthTime = birthTime;
}
public String getBirthTime() {
return birthTime;
}
public void setBirthPlace(String birthPlace) {
this.birthPlace = birthPlace;
}
public String getBirthPlace() {
return birthPlace;
}
public void setCurrentPlace(String currentPlace) {
this.currentPlace = currentPlace;
}
public String getCurrentPlace() {
return currentPlace;
}
public void setTrueSolarTime(String trueSolarTime) {
this.trueSolarTime = trueSolarTime;
}
public String getTrueSolarTime() {
return trueSolarTime;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
public String getLongitude() {
return longitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getLatitude() {
return latitude;
}
public void setConstellation(String constellation) {
this.constellation = constellation;
}
public String getConstellation() {
return constellation;
}
public void setBaziSizhu(BaziSizhu baziSizhu) {
this.baziSizhu = baziSizhu;
}
public BaziSizhu getBaziSizhu() {
return baziSizhu;
}
/**
* Copyright 2025 bejson.com
*/
/**
* Auto-generated: 2025-07-21 17:23:17
*
* @author bejson.com (i@bejson.com)
* @website http://www.bejson.com/java2pojo/
*/
public static class BaziSizhu implements Serializable{
private String nianzhu;
private String yuezhu;
private String rizhu;
private String shizhu;
public void setNianzhu(String nianzhu) {
this.nianzhu = nianzhu;
}
public String getNianzhu() {
return nianzhu;
}
public void setYuezhu(String yuezhu) {
this.yuezhu = yuezhu;
}
public String getYuezhu() {
return yuezhu;
}
public void setRizhu(String rizhu) {
this.rizhu = rizhu;
}
public String getRizhu() {
return rizhu;
}
public void setShizhu(String shizhu) {
this.shizhu = shizhu;
}
public String getShizhu() {
return shizhu;
}
}
}

View File

@@ -0,0 +1,11 @@
package com.ckkj.water.base.inter;
import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.ServiceException;
import java.util.List;
public interface UploadCallback {
void onSuccess(List<String> urls);
void onFailure(ClientException clientException, ServiceException serviceException);
}

View File

@@ -0,0 +1,900 @@
package com.ckkj.water.chat;
import static android.app.Activity.RESULT_OK;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.widget.NestedScrollView;
import androidx.recyclerview.widget.GridLayoutManager;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.ckkj.water.AppConfig;
import com.ckkj.water.EventMessage;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.chat.adapter.ChatQuestionDetailAdapter;
import com.ckkj.water.chat.adapter.ChatZixunAdapter;
import com.ckkj.water.chat.entity.ChatQuestionEntity;
import com.ckkj.water.custom.GridSpacingItemDecoration;
import com.ckkj.water.databinding.IndexLayoutBinding;
import com.ckkj.water.chat.adapter.IndexChatAdapter;
import com.ckkj.water.chat.adapter.IndexOptionAdapter;
import com.ckkj.water.chat.adapter.IndexEnterHintAdapter;
import com.ckkj.water.chat.adapter.IndexQuickAskAdapter;
import com.ckkj.water.chat.entity.CharHistoryEntity;
import com.ckkj.water.chat.entity.ChatAiMsgEntity;
import com.ckkj.water.chat.entity.ChatMultiItem;
import com.ckkj.water.chat.entity.IndexTemplateEntity;
import com.ckkj.water.chat.mvp.IndexContract;
import com.ckkj.water.chat.mvp.IndexImpl;
import com.ckkj.water.chat.mvp.IndexPresenter;
import com.ckkj.water.dialog.ContentReportDialog;
import com.ckkj.water.login.LoginActivity;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plate.entity.BaziResultBean;
import com.ckkj.water.plate.entity.PaipanCache;
import com.ckkj.water.utils.click.ClickUtil;
import com.ckkj.water.utils.manager.ColorManage;
import com.ckkj.water.utils.show.ToastUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import de.greenrobot.event.Subscribe;
import de.greenrobot.event.ThreadMode;
import android.content.ClipData;
import android.content.ClipboardManager;
/**
* @author fengxiaoyang
* @date 2025/7/7
* @description TODO: 描述该类的作用
*/
public class ChatFragment extends BaseFragment<IndexLayoutBinding, IndexPresenter> implements IndexContract.IndexView {
//顶部 adapter
private IndexOptionAdapter mOptionAdapter;
private ChatZixunAdapter mZixunQuestAdapter;
private ChatQuestionDetailAdapter mQuesDetailAdapter;
//快速提问 adapter
private IndexQuickAskAdapter mQuickAskAdapter;
private List<IndexTemplateEntity> mQuickAskList = new ArrayList<>();
private List<ChatMultiItem> mChatMsgList = new ArrayList<>();
//聊天 adapter
private IndexChatAdapter mChatAdapter;
//欢迎语 adapter
private IndexEnterHintAdapter mHintAdapter;
//输入的内容
private String mCurrentInputContent = "";
//当前options 的 pos
private int mCurrentStreamPos = 0;
//模板数据 list
private List<IndexTemplateEntity> mIndexTemList = new ArrayList<>();
//输出是否完成
private boolean mIsStreamStop = true;
//当前选中 option 的 typeID
private String mSelectTypeID = "1";
//会话 ID
private String mSessionId = "";
// 添加流式数据累积变量
private StringBuilder mStreamContentBuilder = new StringBuilder();
private ChatAiMsgEntity mCurrentStreamEntity = null;
// 智能滚动管理
private boolean mIsUserScrolling = false;
// 优化防抖机制
private Handler mUpdateHandler = new Handler();
private Runnable mUpdateRunnable;
private List<ChatQuestionEntity> mQuesTypeList = new ArrayList<>();
private boolean mIsShowQuestions = true;
@Override
public void initData(Bundle state) {
mOptionAdapter = new IndexOptionAdapter(mContext, R.layout.index_device_list_item, mIndexTemList);
viewBinding.rvOptions.setAdapter(mOptionAdapter);
mQuickAskAdapter = new IndexQuickAskAdapter(mContext, R.layout.index_home_quick_ask_item, mQuickAskList);
viewBinding.rvQuickAsk.setAdapter(mQuickAskAdapter);
mChatAdapter = new IndexChatAdapter(mContext, mChatMsgList, viewBinding.rvChat);
viewBinding.rvChat.setAdapter(mChatAdapter);
//提问类型
GridLayoutManager manager = new GridLayoutManager(mContext, 2);
viewBinding.rvChatQuick.setLayoutManager(manager);
List<ChatQuestionEntity.SubheadingsDTO> subList = new ArrayList<>();
mQuesDetailAdapter = new ChatQuestionDetailAdapter(R.layout.chat_quest_detail_item, subList);
viewBinding.rvChatQuick.setAdapter(mQuesDetailAdapter);
viewBinding.rvChatQuick.addItemDecoration(new GridSpacingItemDecoration(2, 10, true));
mZixunQuestAdapter = new ChatZixunAdapter(mContext, R.layout.chat_zixun_type_item, mQuesTypeList);
viewBinding.rvChatType.setAdapter(mZixunQuestAdapter);
// 设置聊天RecyclerView的LayoutManager禁用滚动
androidx.recyclerview.widget.LinearLayoutManager chatLayoutManager =
new androidx.recyclerview.widget.LinearLayoutManager(mContext);
chatLayoutManager.setStackFromEnd(false);
viewBinding.rvChat.setLayoutManager(chatLayoutManager);
// 禁用RecyclerView的滚动让NestedScrollView处理滚动
viewBinding.rvChat.setNestedScrollingEnabled(false);
mHintAdapter = new IndexEnterHintAdapter(mContext, R.layout.index_enter_hint_item, new ArrayList<>());
viewBinding.rvEnterHint.setAdapter(mHintAdapter);
setAdapterClick();
// 添加EditText的焦点监听器
viewBinding.editInput.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
// EditText获取焦点时延迟滚动到底部确保键盘弹出后再滚动
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
scrollNestedScrollViewToBottom();
}
}, 300); // 延迟300ms等待键盘弹出
}
}
});
viewBinding.editInput.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) {
if (s != null) {
mCurrentInputContent = s.toString().trim();
if (TextUtils.isEmpty(s.toString().trim())) {
viewBinding.imgSend.setImageDrawable(ContextCompat.getDrawable(mContext, R.mipmap.icon_index_send));
viewBinding.editInput.setHint("请输入您的问题");
} else {
viewBinding.imgSend.setImageDrawable(ContextCompat.getDrawable(mContext, R.mipmap.icon_index_send_b));
}
}
}
});
//请求页面模板数据
mPresenter.getIndexTemplateDatas();
mPresenter.getChatTemplateDatas();
//组件增加点击区域
ClickUtil.addClickPart(viewBinding.imgCloseQuick, 30);
ClickUtil.addClickPart(viewBinding.imgRefresh, 30);
ClickUtil.addClickPart(viewBinding.imgHistory, 30);
// 设置智能滚动监听
setupSmartScrollListener();
// 设置页面点击监听,用于隐藏键盘
setupPageClickListener();
// 检查是否有传递过来的参数
checkAndHandleBundle();
}
/**
* 检查并处理传递过来的Bundle参数
*/
private void checkAndHandleBundle() {
Bundle args = getArguments();
if (args != null) {
handleBirthInfoBundle(args);
}
}
/**
* 处理出生信息Bundle参数
*
* @param bundle 包含出生信息的Bundle
*/
public void handleBirthInfoBundle(Bundle bundle) {
if (bundle != null) {
BaziResultBean baseEntity = PaipanCache.get();
// 获取出生信息
BaziResultBean.BaseInfoDTO birthInfo = baseEntity.getBaseInfo();
BaziResultBean.DetailInfoDTO.SizhuInfoDTO sizhuInfoDTO = baseEntity.getDetailInfo().getSizhuInfo();
BaziResultBean.DetailInfoDTO.DayunInfoDTO defaulLiunian = (BaziResultBean.DetailInfoDTO.DayunInfoDTO) bundle.getSerializable("defaul_liunian");
if (birthInfo != null) {
viewBinding.editInput.setText("我叫" + birthInfo.getName() + "," +
((birthInfo.getSex().equals("乾造") ? "" : "") + "," +
"生于公历" + birthInfo.getGongli() + "," + "当前大运为" + defaulLiunian.getDayunStartYear() + "--" +
defaulLiunian.getDayunEndYear() + "" + defaulLiunian.getDayunStartGanzhi() + "大运,四柱为"
+ sizhuInfoDTO.getYear().getTg() + sizhuInfoDTO.getYear().getDz() + "" +
sizhuInfoDTO.getMonth().getTg() + sizhuInfoDTO.getMonth().getDz() + "" +
sizhuInfoDTO.getDay().getTg() + sizhuInfoDTO.getDay().getDz() + "" +
sizhuInfoDTO.getHour().getTg() + sizhuInfoDTO.getHour().getDz() + "," +
"现在需要你根据我的八字,给我具体分析一下我的事业、感情、健康、财富、格局、喜用神"));
}
}
}
/**
* 当Fragment参数更新时调用用于处理onNewIntent的情况
*/
@Override
public void onResume() {
super.onResume();
// 检查是否有新的参数需要处理
Bundle args = getArguments();
if (args != null && args.getBoolean("goto_index_fragment", false)) {
// 处理参数
handleBirthInfoBundle(args);
// 清除标记,避免重复处理
args.remove("goto_index_fragment");
}
}
@Subscribe(threadMode = ThreadMode.MainThread)
public void onGetMessage(EventMessage message) {
//用户添加地址成功
if (message.getEventStrKey().equals(EventMessage.HISTORY_SESSIONID_DELETE_SUCCESS)) {
if (message.getMsg().equals(mSessionId)) {
// viewBinding.linearOptionHint.setVisibility(View.VISIBLE);
mChatMsgList.clear();
mChatAdapter.setNewData(mChatMsgList);
mSessionId = "";
}
}
}
/**
* 设置页面点击监听器
*/
private void setupPageClickListener() {
viewBinding.rvChat.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// 当用户触摸NestedScrollView时隐藏键盘并清除焦点
if (event.getAction() == MotionEvent.ACTION_DOWN) {
hideKeyboardAndClearFocus();
}
return false;
}
});
}
/**
* 隐藏键盘并清除EditText焦点
*/
private void hideKeyboardAndClearFocus() {
// 清除EditText焦点
viewBinding.editInput.clearFocus();
// 隐藏键盘
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(viewBinding.editInput.getWindowToken(), 0);
}
}
/**
* 滚动NestedScrollView到底部
*/
private void scrollNestedScrollViewToBottom() {
if (viewBinding.nestedScrollChat != null) {
// 获取NestedScrollView的子视图RecyclerView
View childView = viewBinding.nestedScrollChat.getChildAt(0);
if (childView != null) {
// 滚动到底部
viewBinding.nestedScrollChat.smoothScrollTo(0, childView.getHeight());
}
}
}
/**
* 设置智能滚动监听器修改为监听NestedScrollView
*/
private void setupSmartScrollListener() {
// 监听NestedScrollView的滚动
viewBinding.nestedScrollChat.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
@Override
public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
// 检测用户是否向上滑动
if (scrollY < oldScrollY) {
// 用户向上滑动
mIsUserScrolling = true;
} else if (scrollY > oldScrollY) {
// 用户向下滑动
mIsUserScrolling = true;
}
// 检查是否滚动到底部
if (scrollY >= (v.getChildAt(0).getHeight() - v.getHeight())) {
// 滚动到底部,恢复自动滚动
mIsUserScrolling = false;
}
}
});
}
private void setAdapterClick() {
//顶部的选项 adapter 点击事件
mOptionAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
if (mCurrentStreamPos != position) {
if (mIsStreamStop) {
viewBinding.rlQuickAsk.setVisibility(View.GONE);
mOptionAdapter.setSelectPos(position);
setOptionSelStyle(position);
mCurrentStreamPos = position;
mSessionId = "";
mSelectTypeID = mIndexTemList.get(position).getId();
} else {
ToastUtil.showShort(mContext, "Ai解答中请稍后操作");
}
}
}
});
//咨询类型 adapter
mZixunQuestAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
if (mIsStreamStop) {
mZixunQuestAdapter.setSelectPos(position);
mQuesDetailAdapter.setNewData(mQuesTypeList.get(position).getSubheadings());
} else {
ToastUtil.showShort(mContext, "Ai解答中请稍后操作");
}
}
});
//快速提问
mQuesDetailAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
if (!AppConfig.USER_LOGIN) {
goTo(mContext, LoginActivity.class, null);
return;
}
if (!mIsStreamStop) {
ToastUtil.showShort(mContext, "Ai解答中请稍后操作");
return;
}
String quickAskContent = mQuesTypeList.get(mZixunQuestAdapter.getmSelPos()).
getSubheadings().get(position).getContent();
sendMsgToAi(quickAskContent);
}
});
//流式输出,是否完成
mChatAdapter.setOnStreamCompleteListener(new IndexChatAdapter.OnStreamCompleteListener() {
@Override
//此时已经流式输出完成
public void onStreamComplete(int position) {
mCurrentStreamPos = position;
viewBinding.imgSend.setVisibility(View.VISIBLE);
viewBinding.imgStop.setVisibility(View.GONE);
mIsStreamStop = true;
}
@Override
public void onStreamStop() {
viewBinding.imgSend.setVisibility(View.VISIBLE);
viewBinding.imgStop.setVisibility(View.GONE);
mIsStreamStop = true;
}
});
mChatAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
switch (view.getId()) {
case R.id.img_jb:
ContentReportDialog cancelDialog = new ContentReportDialog(mContext, R.layout.dialog_report_reason, "");
cancelDialog.show();
cancelDialog.setOnDialogListener(new ContentReportDialog.DialogListener() {
@Override
public void callBackDatas(String reason) {
showLoadingDialog();
//举报
mPresenter.commitReport(reason);
}
});
break;
}
}
});
// 设置长按菜单监听器
mChatAdapter.setOnItemLongClickMenuListener(new IndexChatAdapter.OnItemLongClickMenuListener() {
@Override
public void onCopyClick(ChatMultiItem item, int position) {
// 处理复制操作
String content = item.getMessage().getContent();
if (!TextUtils.isEmpty(content)) {
ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("chat_content", content);
clipboard.setPrimaryClip(clip);
ToastUtil.showShort(mContext, "内容已复制");
}
}
@Override
public void onReportClick(ChatMultiItem item, int position) {
// 处理举报操作
ContentReportDialog cancelDialog = new ContentReportDialog(mContext, R.layout.dialog_report_reason, "");
cancelDialog.show();
cancelDialog.setOnDialogListener(new ContentReportDialog.DialogListener() {
@Override
public void callBackDatas(String reason) {
showLoadingDialog();
//举报
mPresenter.commitReport(reason);
}
});
}
});
// 添加长按监听器
// mChatAdapter.setOnItemChildLongClickListener(new BaseQuickAdapter.OnItemChildLongClickListener() {
// @Override
// public boolean onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) {
// switch (view.getId()) {
// case R.id.tv_text: // 文本内容的view id
// XPopup.fixLongClick(view); // 能保证弹窗弹出后下层的View无法滑动
//
// // 获取当前消息内容
// ChatMultiItem item = mChatMsgList.get(position);
// String content = item.getMessage().getContent();
//
// // 使用链式调用确保atView在asAttachList之前
// new XPopup.Builder(getContext())
// .hasShadowBg(false)
// .atView(view) // 使用atView而不是watchView
// .asAttachList(new String[]{"复制", "举报"},
// null,
// new OnSelectListener() {
// @Override
// public void onSelect(int selectPosition, String text) {
// switch (selectPosition) {
// case 0: // 复制
// if (!TextUtils.isEmpty(content)) {
// ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
// ClipData clip = ClipData.newPlainText("chat_content", content);
// clipboard.setPrimaryClip(clip);
// ToastUtil.showShort(mContext, "内容已复制");
// }
// break;
// case 1: // 举报
// ContentReportDialog cancelDialog = new ContentReportDialog(mContext, R.layout.dialog_report_reason, "");
// cancelDialog.show();
// cancelDialog.setOnDialogListener(new ContentReportDialog.DialogListener() {
// @Override
// public void callBackDatas(String reason) {
// showLoadingDialog();
// //举报
// mPresenter.commitReport(reason);
// }
// });
// break;
// }
// }
// })
// .show();
// return true;
// }
// return false;
// }
// });
}
/**
* 停止输出
*/
private void stopSteamOutput() {
// 停止当前网络请求
mPresenter.stopCurrentRequest();
// 获取当前正在流式输出的位置
int currentPosition = mChatMsgList.size() - 1;
// 标记当前消息为被停止状态
mChatAdapter.markAsStopped(currentPosition);
// 停止适配器中的流式输出
mChatAdapter.setStreamerStop(currentPosition);
// 清除当前流式输出位置
mChatAdapter.setCurrentStreamingPosition(-1);
// 强制更新当前item以显示停止标识
mChatAdapter.notifyItemChanged(currentPosition);
// 恢复UI状态
viewBinding.imgSend.setVisibility(View.VISIBLE);
viewBinding.imgStop.setVisibility(View.GONE);
mIsStreamStop = true;
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data != null) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case REQUEST_EVENT_CODE_10001:
String sessionId = data.getStringExtra("session_id");
String numerologyType = data.getStringExtra("numerology_type");
int showSelPos = -1;
for (int i = 0; i < mIndexTemList.size(); i++) {
if (numerologyType.equals(mIndexTemList.get(i).getId())) {
showSelPos = i;
}
}
if (mCurrentStreamPos != showSelPos) {
}
if (mIsStreamStop) {
viewBinding.rlQuickAsk.setVisibility(View.GONE);
mOptionAdapter.setSelectPos(showSelPos);
setOptionSelStyle(showSelPos);
mCurrentStreamPos = showSelPos;
mSelectTypeID = mIndexTemList.get(showSelPos).getId();
if (!TextUtils.isEmpty(sessionId)) {
mPresenter.getChatDetailByID(sessionId);
}
} else {
ToastUtil.showShort(mContext, "Ai解答中请稍后操作");
}
break;
}
}
}
}
/**
* 发送消息给 AI
*/
private void sendMsgToAi(String senMsg) {
if (!AppConfig.USER_LOGIN) {
goTo(mContext, LoginActivity.class, null);
return;
}
viewBinding.cardQuestion.setVisibility(View.GONE);
viewBinding.imgClose.setImageDrawable(ContextCompat.getDrawable(mContext, R.mipmap.icon_chat_down));
mIsShowQuestions = false;
viewBinding.linearOptionHint.setVisibility(View.GONE);
// 重置滚动状态
mIsUserScrolling = false;
// 清理适配器缓存
mChatAdapter.clearCache();
// 创建用户消息
ChatAiMsgEntity chatMsgEntity = new ChatAiMsgEntity();
chatMsgEntity.setSessionId(mSessionId);
chatMsgEntity.setType(mSelectTypeID);
chatMsgEntity.setContent(senMsg);
ChatMultiItem userEntity = new ChatMultiItem(ChatMultiItem.TYPE_TEXT_RIGHT, chatMsgEntity);
mChatMsgList.add(userEntity);
mChatAdapter.notifyItemInserted(mChatMsgList.size() - 1);
// 创建AI回复消息初始为空
mCurrentStreamEntity = new ChatAiMsgEntity();
mCurrentStreamEntity.setSessionId(mSessionId);
mCurrentStreamEntity.setType(mSelectTypeID);
mCurrentStreamEntity.setContent(""); // 初始为空
ChatMultiItem aiEntity = new ChatMultiItem(ChatMultiItem.TYPE_TEXT_LEFT, mCurrentStreamEntity);
mChatMsgList.add(aiEntity);
// 设置当前流式输出位置
int aiMessagePosition = mChatMsgList.size() - 1;
mChatAdapter.setCurrentStreamingPosition(aiMessagePosition);
mChatAdapter.notifyItemInserted(aiMessagePosition);
// 重置流式数据累积器
mStreamContentBuilder.setLength(0);
// 清空输入框
viewBinding.editInput.setText("");
// 设置UI状态
viewBinding.imgSend.setVisibility(View.GONE);
viewBinding.imgStop.setVisibility(View.VISIBLE);
// 发送消息后自动滚动到底部
scrollToBottomAfterSend();
// 发起流式请求
mPresenter.talkToAi(senMsg, mSelectTypeID, mSessionId);
}
@Override
public IndexPresenter createPresenter() {
return new IndexPresenter(new IndexImpl());
}
@Override
public void getTalkResultSuccess(ChatAiMsgEntity bean) {
hideDialogLoading();
}
/**
* 首页数据获取成功
*
* @param list
*/
@Override
public void getIndexTemplateSuccess(List<IndexTemplateEntity> list) {
if (list != null && list.size() != 0) {
mIndexTemList = list;
mOptionAdapter.setNewData(mIndexTemList);
setAdapterClick();
setOptionSelStyle(0);
mSelectTypeID = mIndexTemList.get(0).getId();
}
}
/**
* 切换设置显示内容
*
* @param pos
*/
private void setOptionSelStyle(int pos) {
try {
mChatMsgList.clear();
mChatAdapter.setNewData(mChatMsgList);
// 清理缓存
mChatAdapter.clearCache();
// viewBinding.linearOptionHint.setVisibility(View.VISIBLE);
IndexTemplateEntity defaulEntity = mIndexTemList.get(pos);
viewBinding.tvTitleExpert.setText(defaulEntity.getTitle() + "专家");
viewBinding.tvSelectOptionLable.setText(defaulEntity.getTitle() + "专家");
viewBinding.tvSelectOptionSlogan.setText(defaulEntity.getSubheading());
if (ColorManage.getInstance().isParsableColor(defaulEntity.getColor())) {
viewBinding.tvSelectOptionSlogan.setTextColor(Color.parseColor(defaulEntity.getColor()));
} else {
viewBinding.tvSelectOptionSlogan.setTextColor(ContextCompat.getColor(mContext, R.color.color_zhu));
}
//提示语
List<String> hintMsgList = new ArrayList<>();
hintMsgList = Arrays.asList(defaulEntity.getIntermediateContent().split("#"));
mHintAdapter.setNewData(hintMsgList);
//快速提问
mQuickAskList.clear();
List<String> quickAskList = new ArrayList<>();
quickAskList = Arrays.asList(defaulEntity.getQuickQuestions().split("#"));
for (String content : quickAskList) {
IndexTemplateEntity entity = new IndexTemplateEntity();
entity.setColor(defaulEntity.getColor());
entity.setBlackcolor(defaulEntity.getBlackcolor());
entity.setSpliteItemContent(content);
mQuickAskList.add(entity);
}
mQuickAskAdapter.setNewData(mQuickAskList);
} catch (Exception e) {
}
}
@Override
public void onNetChange(int netModel) {
}
@Override
public void showError(String message) {
hideDialogLoading();
ToastUtil.showShort(mContext, message);
// 流式传输完成恢复UI状态
viewBinding.imgSend.setVisibility(View.VISIBLE);
viewBinding.imgStop.setVisibility(View.GONE);
mIsStreamStop = true;
// 可以在这里处理会话ID等
if (mCurrentStreamEntity != null && !TextUtils.isEmpty(mCurrentStreamEntity.getSessionId())) {
mSessionId = mCurrentStreamEntity.getSessionId();
}
// 清理当前流式实体
mCurrentStreamEntity = null;
mStreamContentBuilder.setLength(0);
}
@Override
public void logOut(BaseBean bean) {
}
// 实现流式消息接收回调
@Override
public void onStreamMessageReceived(String messageChunk) {
mIsStreamStop = false;
if (mCurrentStreamEntity != null) {
// 更新当前AI消息的内容
mCurrentStreamEntity.setContent(messageChunk);
// 取消之前的更新任务
if (mUpdateRunnable != null) {
mUpdateHandler.removeCallbacks(mUpdateRunnable);
}
mUpdateRunnable = () -> {
// 只更新最后一个item
int lastPosition = mChatMsgList.size() - 1;
if (lastPosition >= 0) {
// 使用更轻量的更新方式,避免重新布局
mChatAdapter.notifyItemChanged(lastPosition, "content_only");
// 流式输出时如果用户没有手动滑动则自动滚动NestedScrollView
if (!mIsUserScrolling) {
smoothScrollNestedScrollView();
}
}
};
// 增加延迟时间,减少更新频率
mUpdateHandler.postDelayed(mUpdateRunnable, 100);
}
}
// 实现流式完成回调
@Override
public void onStreamComplete(String complateMsg) {
// 流式传输完成恢复UI状态
viewBinding.imgSend.setVisibility(View.VISIBLE);
viewBinding.imgStop.setVisibility(View.GONE);
mIsStreamStop = true;
// 清除当前流式输出位置
mChatAdapter.setCurrentStreamingPosition(-1);
// 注意:这里不标记为停止状态,因为这是正常完成
// 可以在这里处理会话ID等
if (mCurrentStreamEntity != null && !TextUtils.isEmpty(mCurrentStreamEntity.getSessionId())) {
mSessionId = mCurrentStreamEntity.getSessionId();
}
// 清理当前流式实体
mCurrentStreamEntity = null;
mStreamContentBuilder.setLength(0);
// 假设你最后一个消息是流式的 placeholder现在替换它
ChatMultiItem lastMessage = mChatMsgList.get(mChatMsgList.size() - 1);
lastMessage.getMessage().setContent(complateMsg); // 你可以解析 Markdown 变 PlainText或保留 Markdown 渲染
// mChatAdapter.notifyItemChanged(mChatMsgList.size() - 1); // 更新 UI
int lastPos = mChatAdapter.getItemCount() - 1;
mChatAdapter.updateTipsVisibility(lastPos);
}
/**
* 根据会话 id 查询对话详情
*
* @param list
*/
@Override
public void getChatDetailSuccess(List<ChatAiMsgEntity> list) {
mChatMsgList.clear();
if (list != null && list.size() != 0) {
mSessionId = list.get(0).getSessionId();
}
for (ChatAiMsgEntity entity : list) {
ChatMultiItem item;
if (entity.getRole().equals("user")) {
item = new ChatMultiItem(ChatMultiItem.TYPE_TEXT_RIGHT, entity);
} else {
item = new ChatMultiItem(ChatMultiItem.TYPE_TEXT_LEFT, entity);
}
mChatMsgList.add(item);
}
mChatAdapter.setNewData(mChatMsgList);
viewBinding.linearOptionHint.setVisibility(View.GONE);
}
@Override
public void loginLost() {
if (isFragmentVisible()) {
handleLoginLost();
}
stopSteamOutput();
if (mChatAdapter != null) {
mChatAdapter.remove(mChatMsgList.size() - 1);
}
}
/**
* 获取咨询模板成功
*
* @param list
*/
@Override
public void getChatZixunSuccess(List<ChatQuestionEntity> list) {
this.mQuesTypeList = list;
if (list != null) {
mZixunQuestAdapter.setNewData(list);
mQuesDetailAdapter.setNewData(list.get(0).getSubheadings());
setAdapterClick();
}
}
/**
* 举报成功
* @param bean
*/
@Override
public void commitReportSuccess(BaseBean bean) {
ToastUtil.showShort(mContext, "星语明灯感谢您的反馈");
hideDialogLoading();
}
// 实现sessionId接收回调
@Override
public void onSessionReceived(String sessionId) {
// 保存sessionId
mSessionId = sessionId;
}
@Override
public void getHistoryDataSuccess(CharHistoryEntity entity) {
}
@Override
public void deleteHistorySuccess(BaseBean bean, int delPos) {
}
/**
* 平滑滚动NestedScrollView到底部
*/
private void smoothScrollNestedScrollView() {
if (mChatAdapter != null && mChatAdapter.getItemCount() > 0) {
// 直接滚动NestedScrollView到底部
viewBinding.nestedScrollChat.post(() -> {
viewBinding.nestedScrollChat.fullScroll(View.FOCUS_DOWN);
});
}
}
/**
* 发送消息后滚动到底部
*/
private void scrollToBottomAfterSend() {
new Handler().postDelayed(() -> {
if (isFragmentVisible()) {
viewBinding.nestedScrollChat.fullScroll(View.FOCUS_DOWN);
}
}, 100);
}
@Override
public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
}
@Override
public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
}
}

View File

@@ -0,0 +1,225 @@
package com.ckkj.water.chat;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.gyf.immersionbar.ImmersionBar;
import com.ckkj.water.chat.entity.ChatQuestionEntity;
import com.scwang.smart.refresh.footer.ClassicsFooter;
import com.scwang.smart.refresh.layout.api.RefreshHeader;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.custom.view.CustomRefreshHeader;
import com.ckkj.water.databinding.IndexHistoryLayoutBinding;
import com.ckkj.water.chat.adapter.ChatHistoryAdapter;
import com.ckkj.water.chat.entity.CharHistoryEntity;
import com.ckkj.water.chat.entity.ChatAiMsgEntity;
import com.ckkj.water.chat.entity.IndexTemplateEntity;
import com.ckkj.water.chat.mvp.IndexContract;
import com.ckkj.water.chat.mvp.IndexImpl;
import com.ckkj.water.chat.mvp.IndexPresenter;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.utils.show.ToastUtil;
import java.util.ArrayList;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2025/7/11
* @description 历史记录
*/
public class ChatHistoryActivity extends BaseActivity<IndexHistoryLayoutBinding, IndexPresenter>
implements IndexContract.IndexView {
private int mCurrentPage = 1;
private ChatHistoryAdapter mAdapter;
//历史记录
private List<CharHistoryEntity.Sessions> mChatList = new ArrayList<>();
@Override
public IndexPresenter createPresenter() {
return new IndexPresenter(new IndexImpl());
}
@Override
public int getLayoutResId(Bundle savedInstanceState) {
return 0;
}
@Override
public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
ImmersionBar.with(this)
.statusBarColor(R.color.white)
.statusBarDarkFont(true)
.titleBar(viewBinding.rlTitle) // 替换为你的标题栏View
.keyboardEnable(true)
.navigationBarDarkIcon(true)
.init();
viewBinding.includedTitle.tvTitle.setText("历史记录");
viewBinding.includedTitle.imgBack.setOnClickListener(c ->finish());
mAdapter = new ChatHistoryAdapter(mContext, R.layout.history_item_layout, mChatList);
viewBinding.rvData.setAdapter(mAdapter);
setAdapterClick();
// 设置自定义刷新头
RefreshHeader header = new CustomRefreshHeader(mContext);
viewBinding.refresh.setRefreshHeader(header);
viewBinding.refresh.setRefreshFooter(new ClassicsFooter(mContext));
viewBinding.refresh.setOnRefreshListener(layout -> {
mCurrentPage = 1;
getHistoryDatas();
});
viewBinding.refresh.setOnLoadMoreListener(layout -> {
mCurrentPage++;
getHistoryDatas();
});
showLoadingDialog();
getHistoryDatas();
}
private void setAdapterClick() {
mAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
switch (view.getId()){
case R.id.img_delete:
showLoadingDialog();
mPresenter.deleteHistoryBySessionID(mChatList.get(position).getSessionId(),position);
break;
}
}
});
mAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
Intent intent = new Intent();
intent.putExtra("session_id",mChatList.get(position).getSessionId());
intent.putExtra("numerology_type",mChatList.get(position).getNumerologyType());
setResult(RESULT_OK,intent);
finish();
}
});
}
private void getHistoryDatas() {
mPresenter.getHistoryDatas(mCurrentPage);
}
/**
* 查询历史数据成功 g
*
* @param entity
*/
@Override
public void getHistoryDataSuccess(CharHistoryEntity entity) {
hideDialogLoading();
int totalPage = entity.getPages();
viewBinding.refresh.finishRefresh(300);
viewBinding.refresh.finishLoadMore(300);
List<CharHistoryEntity.Sessions> list = entity.getSessions();
if (mCurrentPage == 1) {
mChatList.clear(); // 只在刷新时清除
mChatList = list;
} else {
mChatList.addAll(list);
}
mAdapter.setNewData(mChatList);
// 4. 判断是否还有更多数据
if (totalPage == mCurrentPage || list == null || list.size() == 0) {
// ✅ 告诉 SmartRefreshLayout 没有更多数据了
viewBinding.refresh.setNoMoreData(true);
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
*/
@Override
public void deleteHistorySuccess(BaseBean bean, int delPos) {
hideDialogLoading();
mAdapter.remove(delPos);
if(mAdapter.getItemCount() == 0){
viewBinding.refresh.setVisibility(View.GONE);
viewBinding.relNoresult.setVisibility(View.VISIBLE);
viewBinding.relNoMore.setVisibility(View.GONE);
}
}
@Override
public void getChatDetailSuccess(List<ChatAiMsgEntity> list) {
}
@Override
public void loginLost() {
}
@Override
public void getChatZixunSuccess(List<ChatQuestionEntity> list) {
}
@Override
public void commitReportSuccess(BaseBean bean) {
}
@Override
public void getTalkResultSuccess(ChatAiMsgEntity bean) {
}
@Override
public void getIndexTemplateSuccess(List<IndexTemplateEntity> list) {
}
@Override
public void onStreamMessageReceived(String messageChunk) {
}
@Override
public void onStreamComplete(String complateMsg) {
}
@Override
public void onSessionReceived(String sessionId) {
}
@Override
public void showError(String message) {
viewBinding.refresh.finishRefresh(500);
viewBinding.refresh.finishLoadMore(200);
ToastUtil.showShort(mContext, message);
hideDialogLoading();
}
@Override
public void logOut(BaseBean bean) {
}
}

View File

@@ -0,0 +1,75 @@
package com.ckkj.water.chat.adapter;
import android.content.Context;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R;
import com.ckkj.water.chat.entity.CharHistoryEntity;
import com.ckkj.water.utils.time.ZYTimeUtils;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2025/7/11
* @description TODO: 描述该类的作用
*/
public class ChatHistoryAdapter extends BaseQuickAdapter<CharHistoryEntity.Sessions, BaseViewHolder> {
private Context mContext;
public ChatHistoryAdapter(Context context,int layoutResId, @Nullable List<CharHistoryEntity.Sessions> data) {
super(layoutResId, data);
this.mContext = context;
}
@Override
protected void convert(BaseViewHolder helper, CharHistoryEntity.Sessions item) {
ImageView imgType = helper.getView(R.id.img_logo);
switch (item.getNumerologyType()){
case "1"://八字命理
imgType.setImageDrawable(ContextCompat.getDrawable(mContext,R.mipmap.icon_index_bzml));
helper.setBackgroundRes(R.id.tv_type_name,R.drawable.shape_history_type_bzml_bg);
helper.setTextColor(R.id.tv_type_name,ContextCompat.getColor(mContext,R.color.color_319EF4));
break;
case "2"://紫微斗数
imgType.setImageDrawable(ContextCompat.getDrawable(mContext,R.mipmap. icon_index_zwds));
helper.setBackgroundRes(R.id.tv_type_name,R.drawable.shape_history_type_zwds_bg);
helper.setTextColor(R.id.tv_type_name,ContextCompat.getColor(mContext,R.color.color_B85CE6));
break;
case "3"://风水堪舆
imgType.setImageDrawable(ContextCompat.getDrawable(mContext,R.mipmap.icon_index_fsky));
helper.setBackgroundRes(R.id.tv_type_name,R.drawable.shape_history_type_fsky_bg);
helper.setTextColor(R.id.tv_type_name,ContextCompat.getColor(mContext,R.color.color_24B326));
break;
case "6"://奇门遁甲
imgType.setImageDrawable(ContextCompat.getDrawable(mContext,R.mipmap.icon_index_qmdj));
helper.setBackgroundRes(R.id.tv_type_name,R.drawable.shape_history_type_qmdj_bg);
helper.setTextColor(R.id.tv_type_name,ContextCompat.getColor(mContext,R.color.color_2A5CAA));
break;
case "10"://五行起名
imgType.setImageDrawable(ContextCompat.getDrawable(mContext,R.mipmap. icon_index_wxqm));
helper.setBackgroundRes(R.id.tv_type_name,R.drawable.shape_history_type_wxqm_bg);
helper.setTextColor(R.id.tv_type_name,ContextCompat.getColor(mContext,R.color.color_E69900));
break;
default:
imgType.setImageDrawable(ContextCompat.getDrawable(mContext,R.mipmap.icon_index_bzml));
helper.setBackgroundRes(R.id.tv_type_name,R.drawable.shape_history_type_bzml_bg);
helper.setTextColor(R.id.tv_type_name,ContextCompat.getColor(mContext,R.color.color_319EF4));
break;
}
helper.setText(R.id.tv_type_content,item.getFirstUserMessage());
helper.setText(R.id.tv_type_name,item.getSessionName());
String chatTime = ZYTimeUtils.formatDateOrOneYearAgo(item.getCreateTime());
helper.setText(R.id.tv_time,chatTime);
helper.addOnClickListener(R.id.img_delete);
// helper.addOnClickListener(R.id.rl_title);
// helper.addOnClickListener(R.id.tv_type_content);
// helper.addOnClickListener(R.id.img_logo);
}
}

View File

@@ -0,0 +1,29 @@
package com.ckkj.water.chat.adapter;
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.chat.entity.ChatQuestionEntity;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2025/8/19
* @description TODO: 描述该类的作用
*/
public class ChatQuestionDetailAdapter extends BaseQuickAdapter<ChatQuestionEntity.SubheadingsDTO, BaseViewHolder> {
public ChatQuestionDetailAdapter(int layoutResId, @Nullable List<ChatQuestionEntity.SubheadingsDTO> data) {
super(layoutResId, data);
}
@Override
protected void convert(BaseViewHolder helper, ChatQuestionEntity.SubheadingsDTO item) {
helper.setText(R.id.tv_title,item.getTitle());
helper.setText(R.id.tv_content,item.getContent());
}
}

View File

@@ -0,0 +1,49 @@
package com.ckkj.water.chat.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.chat.entity.ChatQuestionEntity;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2025/7/7
* @description TODO: 描述该类的作用
*/
public class ChatZixunAdapter extends BaseQuickAdapter<ChatQuestionEntity, BaseViewHolder> {
private Context mContext;
private int mSelPos = 0;
public ChatZixunAdapter(Context context, int layoutResId, @Nullable List<ChatQuestionEntity> data) {
super(layoutResId, data);
this.mContext = context;
}
@Override
protected void convert(BaseViewHolder helper, ChatQuestionEntity item) {
helper.setText(R.id.tv_content,item.getTeb());
if(helper.getLayoutPosition() == mSelPos){
helper.setTextColor(R.id.tv_content,mContext.getColor(R.color.color_zhu));
helper.setBackgroundRes(R.id.tv_content, R.drawable.shape_chat_zixun_type);
}else{
helper.setTextColor(R.id.tv_content,mContext.getColor(R.color.color_7A8699));
helper.setBackgroundRes(R.id.tv_content, R.drawable.shape_trans_touming);
}
}
public void setSelectPos(int position) {
this.mSelPos = position;
notifyDataSetChanged();
}
public int getmSelPos() {
return mSelPos;
}
}

View File

@@ -0,0 +1,244 @@
package com.ckkj.water.chat.adapter;
import android.content.Context;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.chad.library.adapter.base.BaseMultiItemQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R;
import com.ckkj.water.chat.entity.ChatAiMsgEntity;
import com.ckkj.water.chat.entity.ChatMultiItem;
import com.ckkj.water.utils.show.ToastUtil;
import com.ckkj.water.utils.stream.MarkdownStreamer;
import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.interfaces.OnSelectListener;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.noties.markwon.Markwon;
/**
* @author fengxiaoyang
* @date 2025/7/7
* @description TODO: 描述该类的作用
*/
public class IndexChatAdapter extends BaseMultiItemQuickAdapter<ChatMultiItem, BaseViewHolder> {
private Context mContext;
private RecyclerView recyclerView;
private OnStreamCompleteListener streamCompleteListener;
//convert() 中每次绑定 item 时缓存 MarkdownStreamer 实例
private final Map<Integer, MarkdownStreamer> streamerMap = new HashMap<>();
// 新增Markdown 解析器
private Markwon markwon;
// 新增:当前正在流式输出的位置
private int mCurrentStreamingPosition = -1;
// 用于标记哪个 position 需要显示 llTips
// 在 IndexChatAdapter 类中新增字段
private Integer pendingTipsCheckPos = null;
// 新增:记录被停止的位置
private final Map<Integer, Boolean> stoppedPositions = new HashMap<>();
public IndexChatAdapter(Context context, List<ChatMultiItem> data, RecyclerView recyclerView) {
super(data);
this.mContext = context;
this.recyclerView = recyclerView;
this.markwon = Markwon.create(context);
addItemType(ChatMultiItem.TYPE_TEXT_LEFT, R.layout.item_text_left);
addItemType(ChatMultiItem.TYPE_TEXT_RIGHT, R.layout.item_text_right);
}
public void setStreamerStop(int position) {
MarkdownStreamer streamer = streamerMap.get(position);
if (streamer != null) {
streamer.stopStreaming();
streamerMap.remove(position);
}
if (mCurrentStreamingPosition == position) {
mCurrentStreamingPosition = -1;
}
}
/**
* 标记某个位置为被停止的状态
*/
public void markAsStopped(int position) {
stoppedPositions.put(position, true);
// 通知该位置更新显示
notifyItemChanged(position);
}
public interface OnStreamCompleteListener {
void onStreamComplete(int position);
void onStreamStop();
}
public void setOnStreamCompleteListener(OnStreamCompleteListener listener) {
this.streamCompleteListener = listener;
}
// 新增:长按菜单项点击回调接口
public interface OnItemLongClickMenuListener {
void onCopyClick(ChatMultiItem item, int position);
void onReportClick(ChatMultiItem item, int position);
}
private OnItemLongClickMenuListener mLongClickMenuListener;
public void setOnItemLongClickMenuListener(OnItemLongClickMenuListener listener) {
this.mLongClickMenuListener = listener;
}
/**
* 设置当前正在流式输出的位置
*/
public void setCurrentStreamingPosition(int position) {
mCurrentStreamingPosition = position;
}
/**
* 对外暴露的方法:检查某个 position 是否为最后一条,并据此显示/隐藏 llTips。
* 仅记录“待检查的位置”并触发该 position 的刷新;实际显示逻辑在 convert() 末尾统一处理。
*/
public void updateTipsVisibility(int position) {
if (position < 0 || position >= getItemCount()) return;
pendingTipsCheckPos = position;
// notifyItemChanged(position);
notifyDataSetChanged();
}
public void setPendingTipsCheckPos(Integer pendingTipsCheckPos) {
this.pendingTipsCheckPos = pendingTipsCheckPos;
}
@Override
protected void convert(BaseViewHolder helper, ChatMultiItem item) {
ChatAiMsgEntity msgEntity = item.getMessage();
TextView tvContent = helper.getView(R.id.tv_text);
LinearLayout llThinking = helper.getView(R.id.linear_thinking);
LinearLayout llStop = helper.getView(R.id.linear_stop);
LinearLayout llTips = helper.getView(R.id.linear_tips);
int position = helper.getBindingAdapterPosition();
helper.addOnClickListener(R.id.img_jb);
// helper.addOnLongClickListener(R.id.tv_text);
if (item.getItemType() == ChatMultiItem.TYPE_TEXT_LEFT) {
String content = msgEntity.getContent();
if(TextUtils.isEmpty(content)){
llThinking.setVisibility(View.VISIBLE);
tvContent.setText("");
llStop.setVisibility(View.GONE);
} else {
llThinking.setVisibility(View.GONE);
// 优化流式输出更新逻辑
if (position == mCurrentStreamingPosition) {
// 当前正在流式输出的位置
try {
Spanned spanned = markwon.toMarkdown(content);
tvContent.setText(spanned);
} catch (Exception e) {
tvContent.setText(content);
}
// 显示停止标识(如果被停止)
if (stoppedPositions.containsKey(position) && stoppedPositions.get(position)) {
llStop.setVisibility(View.VISIBLE);
llTips.setVisibility(View.VISIBLE);
} else {
llStop.setVisibility(View.GONE);
}
} else {
// 历史消息,直接显示完整内容
try {
Spanned spanned = markwon.toMarkdown(content);
tvContent.setText(spanned);
} catch (Exception e) {
tvContent.setText(content);
}
// 历史消息也检查是否被停止
if (stoppedPositions.containsKey(position) && stoppedPositions.get(position)) {
llStop.setVisibility(View.VISIBLE);
llTips.setVisibility(View.VISIBLE);
} else {
llStop.setVisibility(View.GONE);
}
}
}
Log.i("mingdenglog","XXXXX---position======" + pendingTipsCheckPos);
if (pendingTipsCheckPos != null && position == pendingTipsCheckPos) {
Log.i("mingdenglog","position======" + position);
Log.i("mingdenglog","getItemCount() - 1 ------" + (getItemCount() - 1) );
// 仅当是最后一条才显示 llTips否则隐藏
llTips.setVisibility(position == getItemCount() - 1 ? View.VISIBLE : View.GONE);
// 用一次即清
// pendingTipsCheckPos = null;
}else{
llTips.setVisibility(View.GONE);
}
}
switch (item.getItemType()) {
case ChatMultiItem.TYPE_TEXT_RIGHT:
tvContent.setText(msgEntity.getContent());
break;
}
// //必须要在事件发生之前就watch
final XPopup.Builder builder = new XPopup.Builder(mContext)
.hasShadowBg(false).watchView(tvContent);
tvContent.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
// 如果正在流式输出,则拦截长按事件,不执行任何操作
if (mCurrentStreamingPosition != -1) {
// 可以选择性地提示用户
ToastUtil.showShort(mContext, "Ai解答中请稍后操作");
return true; // 拦截事件
}
builder.asAttachList(new String[]{"复制", "举报"}, null, new OnSelectListener() {
@Override
public void onSelect(int menuPosition, String text) {
// 通过接口回调处理菜单项点击事件
if (mLongClickMenuListener != null) {
switch (menuPosition){
case 0: // 复制
mLongClickMenuListener.onCopyClick(item, position);
break;
case 1: // 举报
mLongClickMenuListener.onReportClick(item, position);
break;
}
}
}
}).show();
return false;
}
});
}
/**
* 清理缓存
*/
public void clearCache() {
streamerMap.clear();
stoppedPositions.clear();
mCurrentStreamingPosition = -1;
}
}

View File

@@ -0,0 +1,38 @@
package com.ckkj.water.chat.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 java.util.List;
/**
* @author fengxiaoyang
* @date 2025/7/7
* @description TODO: 描述该类的作用
*/
public class IndexEnterHintAdapter extends BaseQuickAdapter<String, BaseViewHolder> {
private Context mContext;
private int mSelPos = 0;
private String textColor;
private String bgColor;
public void setColor(String textColor,String bgColor){
this.textColor = textColor;
this.bgColor = bgColor;
}
public IndexEnterHintAdapter(Context context, int layoutResId, @Nullable List<String> data) {
super(layoutResId, data);
this.mContext = context;
}
@Override
protected void convert(BaseViewHolder helper, String item) {
helper.setText(R.id.tv_quick_ask_name,item);
}
}

View File

@@ -0,0 +1,45 @@
package com.ckkj.water.chat.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.chat.entity.IndexTemplateEntity;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2025/7/7
* @description TODO: 描述该类的作用
*/
public class IndexOptionAdapter extends BaseQuickAdapter<IndexTemplateEntity, BaseViewHolder> {
private Context mContext;
private int mSelPos = 0;
public IndexOptionAdapter(Context context,int layoutResId, @Nullable List<IndexTemplateEntity> data) {
super(layoutResId, data);
this.mContext = context;
}
@Override
protected void convert(BaseViewHolder helper, IndexTemplateEntity item) {
// helper.setText(R.id.tv_option_name,item.getTitle());
// if(helper.getLayoutPosition() == mSelPos){
// helper.setTextColor(R.id.tv_option_name,mContext.getColor(R.color.white));
// helper.setBackgroundRes(R.id.tv_option_name, R.drawable.shape_index_option_selected);
// }else{
// helper.setTextColor(R.id.tv_option_name,mContext.getColor(R.color.color_zhu));
// helper.setBackgroundRes(R.id.tv_option_name, R.drawable.shape_index_option_un_selected);
// }
}
public void setSelectPos(int position) {
this.mSelPos = position;
notifyDataSetChanged();
}
}

View File

@@ -0,0 +1,58 @@
package com.ckkj.water.chat.adapter;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.util.TypedValue;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R;
import com.ckkj.water.chat.entity.IndexTemplateEntity;
import com.ckkj.water.utils.manager.ColorManage;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2025/7/8
* @description TODO: 描述该类的作用
*/
public class IndexQuickAskAdapter extends BaseQuickAdapter<IndexTemplateEntity, BaseViewHolder> {
private Context context;
public IndexQuickAskAdapter(Context context,int layoutResId, @Nullable List<IndexTemplateEntity> data) {
super(layoutResId, data);
this.context = context;
}
@Override
protected void convert(BaseViewHolder helper, IndexTemplateEntity item) {
helper.setText(R.id.tv_quick_ask_name,item.getSpliteItemContent());
if(ColorManage.getInstance().isParsableColor(item.getColor())){
helper.setTextColor(R.id.tv_quick_ask_name, Color.parseColor(item.getColor()));
}else{
helper.setTextColor(R.id.tv_quick_ask_name, ContextCompat.getColor(mContext,R.color.color_zhu));
}
if(ColorManage.getInstance().isParsableColor(item.getBlackcolor())){
setRoundedBackground(helper.getView(R.id.tv_quick_ask_name),Color.parseColor(item.getBlackcolor()),30);
}else{
setRoundedBackground(helper.getView(R.id.tv_quick_ask_name),ContextCompat.getColor(mContext,R.color.color_E5F2FB),30);
}
}
private void setRoundedBackground(View view, int fillColor, float cornerRadiusDp) {
GradientDrawable drawable = new GradientDrawable();
drawable.setShape(GradientDrawable.RECTANGLE);
drawable.setColor(fillColor); // 设置填充色
float radiusPx = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, cornerRadiusDp, view.getResources().getDisplayMetrics()
);
drawable.setCornerRadius(radiusPx); // 设置圆角半径单位px
view.setBackground(drawable); // 应用背景
}
}

View File

@@ -0,0 +1,122 @@
package com.ckkj.water.chat.entity;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2025/7/11
* @description TODO: 描述该类的作用
*/
public class CharHistoryEntity implements Serializable {
private int total;
private List<Sessions> sessions;
private int pages;
private int pageSize;
private long userId;
private int pageNum;
public void setTotal(int total) {
this.total = total;
}
public int getTotal() {
return total;
}
public void setSessions(List<Sessions> sessions) {
this.sessions = sessions;
}
public List<Sessions> getSessions() {
return sessions;
}
public void setPages(int pages) {
this.pages = pages;
}
public int getPages() {
return pages;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getPageSize() {
return pageSize;
}
public void setUserId(long userId) {
this.userId = userId;
}
public long getUserId() {
return userId;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public int getPageNum() {
return pageNum;
}
public static class Sessions implements Serializable{
private String sessionId;
private long userId;
private String sessionName;
private String numerologyType;
private String firstUserMessage;
private Date createTime;
private Date updateTime;
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public String getSessionId() {
return sessionId;
}
public void setUserId(long userId) {
this.userId = userId;
}
public long getUserId() {
return userId;
}
public void setSessionName(String sessionName) {
this.sessionName = sessionName;
}
public String getSessionName() {
return sessionName;
}
public void setNumerologyType(String numerologyType) {
this.numerologyType = numerologyType;
}
public String getNumerologyType() {
return numerologyType;
}
public void setFirstUserMessage(String firstUserMessage) {
this.firstUserMessage = firstUserMessage;
}
public String getFirstUserMessage() {
return firstUserMessage;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getCreateTime() {
return createTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public Date getUpdateTime() {
return updateTime;
}
}
}

View File

@@ -0,0 +1,75 @@
package com.ckkj.water.chat.entity;
import java.io.Serializable;
/**
* @author fengxiaoyang
* @date 2025/7/7
* @description TODO: 描述该类的作用
*/
public class ChatAiMsgEntity implements Serializable {
private int id;
private String sessionId;
private String type;
private String content;
private String role;
private String messageOrder;
private String createTime;
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getMessageOrder() {
return messageOrder;
}
public void setMessageOrder(String messageOrder) {
this.messageOrder = messageOrder;
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
}

View File

@@ -0,0 +1,44 @@
package com.ckkj.water.chat.entity;
import com.chad.library.adapter.base.entity.MultiItemEntity;
/**
* @author fengxiaoyang
* @date 2025/7/7
* @description TODO: 描述该类的作用
*/
public class ChatMultiItem implements MultiItemEntity {
public static final int TYPE_TEXT_LEFT = 1;
public static final int TYPE_TEXT_RIGHT = 2;
public static final int TYPE_IMAGE_LEFT = 3;
public static final int TYPE_IMAGE_RIGHT = 4;
public static final int TYPE_VOICE_LEFT = 5;
public static final int TYPE_VOICE_RIGHT = 6;
public static final int TYPE_TIME = 7; // 新增时间类型
private int itemType;
private ChatAiMsgEntity message;
public ChatMultiItem(int itemType, ChatAiMsgEntity message) {
this.itemType = itemType;
this.message = message;
}
@Override
public int getItemType() {
return itemType;
}
public void setItemType(int itemType) {
this.itemType = itemType;
}
public ChatAiMsgEntity getMessage() {
return message;
}
public void setMessage(ChatAiMsgEntity message) {
this.message = message;
}
}

View File

@@ -0,0 +1,36 @@
package com.ckkj.water.chat.entity;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
import java.util.List;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author fengxiaoyang
* @date 2025/8/19
* @description TODO: 描述该类的作用
*/
@NoArgsConstructor
@Data
public class ChatQuestionEntity implements Serializable {
@SerializedName("teb")
private String teb;
@SerializedName("subheadings")
private List<SubheadingsDTO> subheadings;
@SerializedName("id")
private String id;
@NoArgsConstructor
@Data
public static class SubheadingsDTO {
@SerializedName("title")
private String title;
@SerializedName("content")
private String content;
}
}

View File

@@ -0,0 +1,111 @@
package com.ckkj.water.chat.entity;
import java.io.Serializable;
/**
* @author fengxiaoyang
* @date 2025/7/8
* @description TODO: 描述该类的作用
*/
public class IndexTemplateEntity implements Serializable {
private String id;
private String title;
private String titletp;
private String color;
private String blackcolor;
private String subheading;
private String intermediateContent;
private String quickQuestions;
private String hide;
private String type;
private String spliteItemContent;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitletp() {
return titletp;
}
public void setTitletp(String titletp) {
this.titletp = titletp;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getBlackcolor() {
return blackcolor;
}
public void setBlackcolor(String blackcolor) {
this.blackcolor = blackcolor;
}
public String getSubheading() {
return subheading;
}
public void setSubheading(String subheading) {
this.subheading = subheading;
}
public String getIntermediateContent() {
return intermediateContent;
}
public void setIntermediateContent(String intermediateContent) {
this.intermediateContent = intermediateContent;
}
public String getQuickQuestions() {
return quickQuestions;
}
public void setQuickQuestions(String quickQuestions) {
this.quickQuestions = quickQuestions;
}
public String getHide() {
return hide;
}
public void setHide(String hide) {
this.hide = hide;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSpliteItemContent() {
return spliteItemContent;
}
public void setSpliteItemContent(String spliteItemContent) {
this.spliteItemContent = spliteItemContent;
}
}

View File

@@ -0,0 +1,78 @@
package com.ckkj.water.chat.mvp;
import com.ckkj.water.base.IView;
import com.ckkj.water.chat.entity.CharHistoryEntity;
import com.ckkj.water.chat.entity.ChatAiMsgEntity;
import com.ckkj.water.chat.entity.ChatQuestionEntity;
import com.ckkj.water.chat.entity.IndexTemplateEntity;
import com.ckkj.water.network.BaseBean;
import java.util.List;
import java.util.Map;
/**
* @author fengxiaoyang
* @date 2025/7/7
* @description TODO: 描述该类的作用
*/
public class IndexContract {
public interface DataModel{
//发送消息给 AI
void sendMsgToAi(Map<String,Object> map, CallBack callBack);
//发送消息给 AI
void sendMsgToAi(Map<String,Object> map, AiStreamCallback callBack);
//停止当前请求
void stopCurrentRequest();
//获取首页数据
void getIndexTemplateDatas(CallBack callBack);
//获取会话历史
void getHistoryChatDatas(Map<String,Object> map, CallBack callBack);
//删除会话
void deleteHistoryBySessionID(Map<String,Object> map, CallBack callBack);
//根据会话 id查询记录详情
void getChatDetailById(Map<String,Object> map, CallBack callBack);
//首页咨询模板
void getChatemplateDatas(CallBack callBack);
//举报好友
void commitReport(Map<String,Object> map,CallBack callBack);
}
public interface CallBack<T> {
void success(T msg);
void fail(String msg);
}
public interface AiStreamCallback {
void onMessage(String messageChunk); // 每次返回一段内容
void onError(String error);
void onComplete(String complateContent); // 结束
void onSessionReceived(String sessionId); // 新增接收sessionId
void loginLost();
}
public interface IndexView extends IView {
//发送消息给 AI获取结果
void getTalkResultSuccess(ChatAiMsgEntity bean);
//获取首页数据成功
void getIndexTemplateSuccess(List<IndexTemplateEntity> list);
// 新增流式回调方法
void onStreamMessageReceived(String messageChunk);
//完成
void onStreamComplete(String complateMsg);
//接收sessionId
void onSessionReceived(String sessionId);
//查询历史记录成功 g
void getHistoryDataSuccess(CharHistoryEntity entity);
//删除会话成功
void deleteHistorySuccess(BaseBean bean,int delPos);
//根据 id 查询会话详情
void getChatDetailSuccess(List<ChatAiMsgEntity> list);
//登录失效
void loginLost();
//获取首页聊天模板
void getChatZixunSuccess(List<ChatQuestionEntity> list);
//提交举报反馈成功
void commitReportSuccess(BaseBean bean);
}
}

View File

@@ -0,0 +1,575 @@
package com.ckkj.water.chat.mvp;
import static android.content.ContentValues.TAG;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.ckkj.water.AppConfig;
import com.ckkj.water.chat.entity.CharHistoryEntity;
import com.ckkj.water.chat.entity.ChatAiMsgEntity;
import com.ckkj.water.chat.entity.ChatQuestionEntity;
import com.ckkj.water.chat.entity.IndexTemplateEntity;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.network.NetWorkManager;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.net.SocketTimeoutException;
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;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* @author fengxiaoyang
* @date 2025/7/7
* @description TODO: 描述该类的作用
*/
public class IndexImpl implements IndexContract.DataModel{
@Override
public void sendMsgToAi(Map<String, Object> map, IndexContract.CallBack callBack) {
try {
NetWorkManager.getRequest().indexTalkToAi(NetWorkManager.getToken(),map)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<ChatAiMsgEntity>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<ChatAiMsgEntity> 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) {
throw new RuntimeException(e);
}
}
/**
* 发送消息给 AI - 流式版本
* @param map
* @param callBack
*/
private final OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS) // 连接超时60秒
.readTimeout(60, TimeUnit.SECONDS) // 读取超时60秒
.writeTimeout(60, TimeUnit.SECONDS) // 写入超时60秒
.callTimeout(60, TimeUnit.SECONDS) // 整个调用超时60秒
.build();
private Call currentCall = null; // 新增保存当前请求的Call对象
private volatile boolean isRequestStopped = false; // 新增:标记是否已停止请求
@Override
public void sendMsgToAi(Map<String, Object> map, IndexContract.AiStreamCallback callBack) {
try {
String finalUrl = AppConfig.BASE_URL + "mobile/context?" + buildQueryParams(map);
Log.d(TAG, "Request URL: " + finalUrl);
Request request = new Request.Builder()
.addHeader("Authorization", "Bearer " + AppConfig.USER_TOKEN)
.url(finalUrl)
.get()
.build();
currentCall = client.newCall(request);
isRequestStopped = false;
currentCall.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
if (isRequestStopped) return; // 如果已停止,不处理失败回调
// 检查是否是超时异常
String errorMessage = e.getMessage();
if (e instanceof SocketTimeoutException ||
(errorMessage != null && errorMessage.contains("timeout"))) {
errorMessage = "请求超时,请稍后重试";
}
String finalErrorMessage = errorMessage;
new Handler(Looper.getMainLooper()).post(() -> {
if (callBack != null) callBack.onError(finalErrorMessage);
});
}
@Override
public void onResponse(Call call, Response response) {
if (isRequestStopped) return;
if (!response.isSuccessful()) {
new Handler(Looper.getMainLooper()).post(() -> {
if (callBack != null) callBack.onError("请求失败: " + response.code());
});
return;
}
InputStream inputStream = response.body().byteStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
reader.mark(1024); // 标记流的当前位置
String peekLine = reader.readLine();
reader.reset(); // 回到标记位置
// 判断是否是标准 JSON非流式错误返回
if (peekLine != null && peekLine.trim().startsWith("{")) {
StringBuilder jsonBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
jsonBuilder.append(line);
}
String responseJson = jsonBuilder.toString();
JSONObject json = new JSONObject(responseJson);
int code = json.optInt("code", 0);
String msg = json.optString("msg", "");
if (code == 401) {
new Handler(Looper.getMainLooper()).post(() -> {
if (callBack != null) callBack.loginLost();
});
} else {
new Handler(Looper.getMainLooper()).post(() -> {
if (callBack != null) callBack.onError("未知错误: " + msg);
});
}
return;
}
// 否则处理为 SSE 流式数据
handleSSEStream(reader, callBack);
} catch (Exception e) {
new Handler(Looper.getMainLooper()).post(() -> {
// if (callBack != null) callBack.onError("响应异常: " + e.getMessage());
});
} finally {
try {
reader.close();
response.close();
} catch (IOException ignored) {}
}
}
});
} catch (Exception e) {
new Handler(Looper.getMainLooper()).post(() -> {
if (callBack != null) callBack.onError("请求异常: " + e.getMessage());
});
}
}
private void handleSSEStream(BufferedReader reader, IndexContract.AiStreamCallback callBack) throws IOException {
String line;
StringBuilder accumulatedContent = new StringBuilder();
StringBuilder lastLineBuffer = new StringBuilder();
String currentEvent = null;
String currentData = null;
String sessionId = "";
while ((line = reader.readLine()) != null) {
if (isRequestStopped) break;
if (line.startsWith("event:")) {
currentEvent = line.substring(6).trim();
} else if (line.startsWith("data:")) {
currentData = line.substring(5).trim();
if ("session".equals(currentEvent)) {
try {
JsonObject sessionData = JsonParser.parseString(currentData).getAsJsonObject();
sessionId = sessionData.get("sessionId").getAsString();
if (callBack != null && !isRequestStopped) {
callBack.onSessionReceived(sessionId);
}
} catch (Exception e) {
Log.e(TAG, "解析session数据失败", e);
}
} else if ("chunk".equals(currentEvent)) {
try {
JsonObject chunkData = JsonParser.parseString(currentData).getAsJsonObject();
String content = chunkData.get("content").getAsString();
boolean hasNewline = chunkData.get("hasNewline").getAsBoolean();
if (isTableLineFragment(lastLineBuffer.toString(), content)) {
lastLineBuffer.append(content);
if (hasNewline) {
accumulatedContent.append(lastLineBuffer).append("\n");
lastLineBuffer.setLength(0);
}
} else {
if (lastLineBuffer.length() > 0) {
accumulatedContent.append(lastLineBuffer);
lastLineBuffer.setLength(0);
}
lastLineBuffer.append(content);
if (hasNewline) {
accumulatedContent.append(lastLineBuffer).append("\n");
lastLineBuffer.setLength(0);
}
}
final String currentContent = accumulatedContent.toString();
new Handler(Looper.getMainLooper()).post(() -> {
if (callBack != null && !isRequestStopped) {
callBack.onMessage(currentContent);
}
});
} catch (Exception e) {
accumulatedContent.append(currentData);
final String currentContent = accumulatedContent.toString();
new Handler(Looper.getMainLooper()).post(() -> {
if (callBack != null && !isRequestStopped) {
callBack.onMessage(currentContent);
}
});
}
} else if ("complete".equals(currentEvent)) {
// 先处理剩余的 lastLineBuffer 内容,但不通过 onMessage 回调
if (lastLineBuffer.length() > 0) {
accumulatedContent.append(lastLineBuffer);
// 注意:这里不调用 callBack.onMessage(),避免触发 onStreamMessageReceived
}
String complateContent = "";
try {
JsonObject completeData = JsonParser.parseString(currentData).getAsJsonObject();
complateContent = completeData.get("fullResponse").getAsString();
} catch (Exception e) {
Log.e(TAG, "解析complete数据失败", e);
}
final String finalComplateContent = complateContent;
new Handler(Looper.getMainLooper()).post(() -> {
if (callBack != null && !isRequestStopped) {
callBack.onComplete(finalComplateContent); // 只调用 onComplete
}
});
}
}
}
// 处理结束前残留内容
// if (lastLineBuffer.length() > 0 && !isRequestStopped) {
// accumulatedContent.append(lastLineBuffer);
// final String finalContent = accumulatedContent.toString();
// new Handler(Looper.getMainLooper()).post(() -> {
// if (callBack != null && !isRequestStopped) {
// callBack.onMessage(finalContent);
// }
// });
// }
}
/**
* 停止当前请求
*/
public void stopCurrentRequest() {
isRequestStopped = true;
if (currentCall != null && !currentCall.isCanceled()) {
currentCall.cancel();
currentCall = null;
}
}
/**
* 判断是否是表格分隔线片段
*/
private boolean isTableLineFragment(String last, String curr) {
return (last.contains("|") && last.contains("-")) || (curr.contains("|") && curr.contains("-"));
}
// 构造 GET 参数
private String buildQueryParams(Map<String, Object> map) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, Object> entry : map.entrySet()) {
try {
if (sb.length() > 0) sb.append("&");
sb.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
sb.append("=");
sb.append(URLEncoder.encode(String.valueOf(entry.getValue()), "UTF-8"));
} catch (Exception e) {
Log.e(TAG, "Encoding error", e);
}
}
return sb.toString();
}
/**
* 获取首页数据
*/
@Override
public void getIndexTemplateDatas(IndexContract.CallBack callBack) {
try {
NetWorkManager.getRequest().getIndexTemplateDatas()
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<List<IndexTemplateEntity>>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<List<IndexTemplateEntity>> 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();
}
}
/**
* 获取会话历史记录
* @param map
* @param callBack
*/
@Override
public void getHistoryChatDatas(Map<String, Object> map, IndexContract.CallBack callBack) {
try {
NetWorkManager.getRequest().getHistoryList(NetWorkManager.getToken(),map)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<CharHistoryEntity>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<CharHistoryEntity> 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) {
throw new RuntimeException(e);
}
}
/**
* 删除历史会话
* @param map
* @param callBack
*/
@Override
public void deleteHistoryBySessionID(Map<String, Object> map, IndexContract.CallBack callBack) {
try {
NetWorkManager.getRequest().deleteHistoryBySessionID(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);
}else{
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 根据会话 id 查询详情
* @param map
* @param callBack
*/
@Override
public void getChatDetailById(Map<String, Object> map, IndexContract.CallBack callBack) {
try {
NetWorkManager.getRequest().getChatDetailById(NetWorkManager.getToken(),map)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<List<ChatAiMsgEntity>>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<List<ChatAiMsgEntity>> 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) {
throw new RuntimeException(e);
}
}
/**
* 对话页,咨询模板获取
* @param callBack
*/
@Override
public void getChatemplateDatas(IndexContract.CallBack callBack) {
try {
NetWorkManager.getRequest().aitebcontent()
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<List<ChatQuestionEntity>>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<List<ChatQuestionEntity>> 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();
}
}
/**
* 举报反馈
* @param map
* @param callBack
*/
@Override
public void commitReport(Map<String, Object> map, IndexContract.CallBack callBack) {
try {
NetWorkManager.getRequest().commitReporting(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.getData());
}else{
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,249 @@
package com.ckkj.water.chat.mvp;
import com.ckkj.water.EventMessage;
import com.ckkj.water.base.BasePresenter;
import com.ckkj.water.chat.entity.CharHistoryEntity;
import com.ckkj.water.chat.entity.ChatAiMsgEntity;
import com.ckkj.water.chat.entity.ChatQuestionEntity;
import com.ckkj.water.chat.entity.IndexTemplateEntity;
import com.ckkj.water.network.BaseBean;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.greenrobot.event.EventBus;
/**
* @author fengxiaoyang
* @date 2025/7/7
* @description TODO: 描述该类的作用
*/
public class IndexPresenter extends BasePresenter<IndexContract.IndexView> {
private IndexImpl impl;
public IndexPresenter(IndexImpl impl) {
this.impl = impl;
}
/**
* 发送消息给 AI
*
* @param content
*/
// public void talkToAi(String content,String type) {
// Map<String,Object> map = new HashMap<>();
// map.put("content",content);
// map.put("type",type);
// map.put("sessionId","");
// impl.sendMsgToAi(map, new IndexContract.CallBack<ChatAiMsgEntity>() {
// @Override
// public void success(ChatAiMsgEntity bean) {
// if( IndexPresenter.this.getView() != null){
// IndexPresenter.this.getView().getTalkResultSuccess(bean);
// }
// }
//
// @Override
// public void fail(String msg) {
// if( IndexPresenter.this.getView() != null){
// IndexPresenter.this.getView().showError(msg);
// }
// }
// });
// }
public void talkToAi(String content, String type, String sessionID) {
Map<String, Object> map = new HashMap<>();
map.put("content", content);
map.put("type", type);
map.put("sessionId", sessionID);
impl.sendMsgToAi(map, new IndexContract.AiStreamCallback() {
@Override
public void onMessage(String messageChunk) {
// 流式数据到达时通知View更新UI
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().onStreamMessageReceived(messageChunk);
}
}
@Override
public void onError(String msg) {
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().showError(msg);
}
}
@Override
public void onComplete(String complateMsg) {
// 流式传输完成
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().onStreamComplete(complateMsg);
}
}
@Override
public void onSessionReceived(String sessionId) {
// 接收到sessionId时通知View
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().onSessionReceived(sessionId);
}
}
@Override
public void loginLost() {
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().loginLost();
}
}
});
}
/**
* 停止当前流式请求
*/
public void stopCurrentRequest() {
impl.stopCurrentRequest();
}
/**
* 首页模板消息数据获取
*/
public void getIndexTemplateDatas() {
impl.getIndexTemplateDatas(new IndexContract.CallBack<List<IndexTemplateEntity>>() {
@Override
public void success(List<IndexTemplateEntity> list) {
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().getIndexTemplateSuccess(list);
}
}
@Override
public void fail(String msg) {
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().showError(msg);
}
}
});
}
/**
* 获取历史记录
* @param mCurrentPage
*/
public void getHistoryDatas(int mCurrentPage) {
Map<String, Object> map = new HashMap<>();
map.put("pageNum", mCurrentPage);
map.put("pageSize", 10);
impl.getHistoryChatDatas(map, new IndexContract.CallBack<CharHistoryEntity>() {
@Override
public void success(CharHistoryEntity entity) {
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().getHistoryDataSuccess(entity);
}
}
@Override
public void fail(String msg) {
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().showError(msg);
}
}
});
}
/**
* 删除历史记录
* @param sessionID
*/
public void deleteHistoryBySessionID(String sessionID,int delPos) {
Map<String, Object> map = new HashMap<>();
map.put("sessionId", sessionID);
impl.deleteHistoryBySessionID(map, new IndexContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean entity) {
EventBus.getDefault().post(new EventMessage(EventMessage.HISTORY_SESSIONID_DELETE_SUCCESS,sessionID));
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().deleteHistorySuccess(entity,delPos);
}
}
@Override
public void fail(String msg) {
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().showError(msg);
}
}
});
}
/**
* 根据sessionID 查询消息记录
* @param sessionId
*/
public void getChatDetailByID(String sessionId) {
Map<String, Object> map = new HashMap<>();
map.put("sessionId", sessionId);
impl.getChatDetailById(map, new IndexContract.CallBack<List<ChatAiMsgEntity>>() {
@Override
public void success(List<ChatAiMsgEntity> list) {
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().getChatDetailSuccess(list);
}
}
@Override
public void fail(String msg) {
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().showError(msg);
}
}
});
}
/**
* 获取首页咨询会话模板
*/
public void getChatTemplateDatas() {
impl.getChatemplateDatas(new IndexContract.CallBack<List<ChatQuestionEntity>>() {
@Override
public void success(List<ChatQuestionEntity> list) {
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().getChatZixunSuccess(list);
}
}
@Override
public void fail(String msg) {
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().showError(msg);
}
}
});
}
/**
* 举报
* @param reason
*/
public void commitReport(String reason) {
Map<String, Object> map = new HashMap<>();
map.put("content", reason);
impl.commitReport(map, new IndexContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean) {
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().commitReportSuccess(bean);
}
}
@Override
public void fail(String msg) {
if (IndexPresenter.this.getView() != null) {
IndexPresenter.this.getView().showError(msg);
}
}
});
}
}

View File

@@ -0,0 +1,38 @@
package com.ckkj.water.custom;
import me.rosuh.filepicker.filetype.FileType;
import com.ckkj.water.R;
import org.jetbrains.annotations.NotNull;
public class CustomFileType implements FileType {
@Override
public int getFileIconResId() {
return R.drawable.ic_unknown_file_picker;
}
@NotNull
@Override
public String getFileType() {
return "Excel";
}
@Override
public boolean verify(@NotNull String fileName) {
boolean isHasSuffix = fileName.contains(".");
if (!isHasSuffix) {
// 如果没有 . 符号,即是没有文件后缀
return false;
}
String suffix = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
return "pdf".equals(suffix)
|| "ppt".equals(suffix)
|| "pptx".equals(suffix)
|| "doc".equals(suffix)
|| "docx".equals(suffix)
|| "xls".equals(suffix)
|| "xlsx".equals(suffix);
}
}

View File

@@ -0,0 +1,53 @@
//package com.ckkj.water.custom;
//
//import android.content.Context;
//import android.graphics.Color;
//import android.view.View;
//import android.widget.Toast;
//
//import androidx.annotation.NonNull;
//
//import com.lxj.xpopup.core.BubbleHorizontalAttachPopupView;
//import com.lxj.xpopup.util.XPopupUtils;
//import com.ckkj.water.R;
//
///**
// * Description: 自定义Attach弹窗水平方向的带气泡的弹窗
// * Create by lxj, at 2019/3/13
// */
//public class CustomHorizontalBubbleAttachPopup extends BubbleHorizontalAttachPopupView {
// private Context mContext;
// public CustomHorizontalBubbleAttachPopup(@NonNull Context context) {
// super(context);
// this.mContext = context;
// }
//
// @Override
// protected int getImplLayoutId() {
// return R.layout.custom_attach_popup;
// }
//
// @Override
// protected void onCreate() {
// super.onCreate();
// setBubbleBgColor(Color.parseColor("#4D5063"));
// setBubbleShadowSize(XPopupUtils.dp2px(getContext(), 3));
// setBubbleShadowColor(Color.BLACK);
// getPopupImplView().setBackgroundResource(0);
// findViewById(R.id.tv_zan).setOnClickListener(new OnClickListener() {
// @Override
// public void onClick(View v) {
// Toast.makeText(mContext, "赞", Toast.LENGTH_LONG).show();
// dismiss();
// }
// });
// findViewById(R.id.tv_comment).setOnClickListener(new OnClickListener() {
// @Override
// public void onClick(View v) {
// Toast.makeText(mContext, "评论", Toast.LENGTH_LONG).show();
// dismiss();
// }
// });
// }
//
//}

View File

@@ -0,0 +1,144 @@
package com.ckkj.water.custom;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.bigkoo.pickerview.builder.TimePickerBuilder;
import com.bigkoo.pickerview.listener.OnTimeSelectListener;
import com.bigkoo.pickerview.view.TimePickerView;
import com.ckkj.water.R;
import com.ckkj.water.utils.show.ToastUtil;
import com.ckkj.water.utils.time.ZYTimeUtils;
import com.lxj.xpopup.impl.PartShadowPopupView;
import java.util.Date;
/**
* Description: 自定义局部阴影弹窗
* Create by dance, at
*/
public class CustomTimeFilterPopupView extends PartShadowPopupView implements View.OnClickListener {
private Context mContext;
private String mStartTime,mEndTime;
private OnClickListener listener;
public CustomTimeFilterPopupView(@NonNull Context context,OnClickListener listener) {
super(context);
this.mContext = context;
this.listener = listener;
}
public interface OnClickListener{
void callBack(String startTime,String endTime);
}
public void setOnclickListener(OnClickListener listener){
this.listener = listener;
}
@Override
protected int getImplLayoutId() {
return R.layout.history_filter_time_dialog;
}
TextView tvStartTime,tvEndTime,tvReset,tvFinish;
@Override
protected void onCreate() {
super.onCreate();
tvStartTime = findViewById(R.id.tv_start_time);
tvEndTime = findViewById(R.id.tv_end_time);
tvReset = findViewById(R.id.tv_reset);
tvFinish = findViewById(R.id.tv_finish);
tvStartTime.setOnClickListener(this);
tvEndTime.setOnClickListener(this);
tvReset.setOnClickListener(this);
tvFinish.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.tv_start_time:
boolean times[] = {true, true, true, false, false, false};
//时间选择器
TimePickerView pvTime = new TimePickerBuilder(mContext, new OnTimeSelectListener() {
@Override
public void onTimeSelect(Date date, View v) {
tvStartTime.setText(ZYTimeUtils.getStrTimeData_YYYY_MM_dd(date));
mStartTime = ZYTimeUtils.getStrTimeData_YYYY_MM_dd(date);
}
}).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();
break;
case R.id.tv_end_time:
boolean endTimes[] = {true, true, true, false, false, false};
//时间选择器
TimePickerView pvEndTime = new TimePickerBuilder(mContext, new OnTimeSelectListener() {
@Override
public void onTimeSelect(Date date, View v) {
tvEndTime.setText(ZYTimeUtils.getStrTimeData_YYYY_MM_dd(date));
mEndTime = ZYTimeUtils.getStrTimeData_YYYY_MM_dd(date);
}
}).setType(endTimes)
.setCancelColor(mContext.getColor(R.color.color_999999))
.setSubmitColor(mContext.getColor(R.color.color_zhu))
.setTextColorCenter(mContext.getColor(R.color.color_zhu))
.build();
pvEndTime.show();
break;
case R.id.tv_reset:
tvStartTime.setText("");
tvEndTime.setText("");
mStartTime = "";
mEndTime = "";
break;
case R.id.tv_finish:
if(TextUtils.isEmpty(mStartTime)){
ToastUtil.showShort(mContext,mContext.getString(R.string.history_filter_start_time_toast));
return;
}
if(TextUtils.isEmpty(mEndTime)){
ToastUtil.showShort(mContext,mContext.getString(R.string.history_filter_end_time_toast));
return;
}
// 比较结束时间和开始时间,结束时间不能早于开始时间
if (!ZYTimeUtils.isEndTimeAfterStartTime(mStartTime, mEndTime)) {
ToastUtil.showShort(mContext, mContext.getString(R.string.history_filter_end_time_error));
return;
}
if(listener != null){
listener.callBack(mStartTime,mEndTime);
this.dismiss();
}
break;
}
}
@Override
protected void onShow() {
super.onShow();
Log.e("tag","CustomPartShadowPopupView onShow");
}
@Override
protected void onDismiss() {
super.onDismiss();
Log.e("tag","CustomPartShadowPopupView onDismiss");
}
}

View File

@@ -0,0 +1,128 @@
package com.ckkj.water.custom;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.bigkoo.pickerview.builder.TimePickerBuilder;
import com.bigkoo.pickerview.listener.OnTimeSelectListener;
import com.bigkoo.pickerview.view.TimePickerView;
import com.ckkj.water.R;
import com.ckkj.water.utils.show.ToastUtil;
import com.ckkj.water.utils.time.ZYTimeUtils;
import com.lxj.xpopup.impl.PartShadowPopupView;
import java.util.Date;
/**
* Description: 自定义局部阴影弹窗
* Create by dance, at
*/
public class CustomTypeFilterPopupView extends PartShadowPopupView implements View.OnClickListener {
private Context mContext;
private OnClickListener listener;
private TextView tvManual,tvAuto,tvReset,tvFinish;
//是否选择了手动
private boolean mSelManual = false;
//是否选择了自动排程
private boolean mSelAuto = false;
public CustomTypeFilterPopupView(@NonNull Context context, OnClickListener listener) {
super(context);
this.mContext = context;
this.listener = listener;
}
public interface OnClickListener{
void callBack(boolean mSelManual,boolean mSelAuto);
}
public void setOnclickListener(OnClickListener listener){
this.listener = listener;
}
@Override
protected int getImplLayoutId() {
return R.layout.history_filter_type_dialog;
}
@Override
protected void onCreate() {
super.onCreate();
tvManual = findViewById(R.id.tv_manual);
tvAuto = findViewById(R.id.tv_auto);
tvReset = findViewById(R.id.tv_reset);
tvFinish = findViewById(R.id.tv_finish);
tvManual.setOnClickListener(this);
tvAuto.setOnClickListener(this);
tvReset.setOnClickListener(this);
tvFinish.setOnClickListener(this);
tvManual.setSelected(false);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.tv_manual:
if(mSelManual){
mSelManual = false;
tvManual.setTextColor(mContext.getColor(R.color.color_zhu));
tvManual.setSelected(mSelManual);
}else{
mSelManual = true;
tvManual.setTextColor(mContext.getColor(R.color.white));
tvManual.setSelected(mSelManual);
}
break;
case R.id.tv_auto:
if(mSelAuto){
mSelAuto = false;
tvAuto.setTextColor(mContext.getColor(R.color.color_zhu));
tvAuto.setSelected(mSelAuto);
}else{
mSelAuto = true;
tvAuto.setTextColor(mContext.getColor(R.color.white));
tvAuto.setSelected(mSelAuto);
}
break;
case R.id.tv_reset:
mSelManual = false;
mSelAuto = false;
tvManual.setTextColor(mContext.getColor(R.color.color_zhu));
tvAuto.setTextColor(mContext.getColor(R.color.color_zhu));
tvManual.setSelected(mSelManual);
tvAuto.setSelected(mSelAuto);
break;
case R.id.tv_finish:
if(!mSelManual && !mSelAuto){
ToastUtil.showShort(mContext,mContext.getString(R.string.history_filter_type_toast));
return;
}
if(listener != null){
listener.callBack(mSelManual,mSelAuto);
this.dismiss();
}
break;
}
}
@Override
protected void onShow() {
super.onShow();
Log.e("tag","CustomPartShadowPopupView onShow");
}
@Override
protected void onDismiss() {
super.onDismiss();
Log.e("tag","CustomPartShadowPopupView onDismiss");
}
}

View File

@@ -0,0 +1,31 @@
package com.ckkj.water.custom;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private final Paint paint;
private final int height;
public DividerItemDecoration(int color, int height) {
paint = new Paint();
paint.setColor(color);
this.height = height;
}
@Override
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
for (int i = 0; i < parent.getChildCount() - 1; i++) {
View child = parent.getChildAt(i);
int top = child.getBottom();
int bottom = top + height;
c.drawRect(left, top, right, bottom, paint);
}
}
}

View File

@@ -0,0 +1,41 @@
package com.ckkj.water.custom;
import android.graphics.Rect;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private final int spanCount; // 列数
private final int spacing; // 间距
private final boolean includeEdge; // 是否包含边缘
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); // item 位置
int column = position % spanCount; // 列数
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount; // 左边距
outRect.right = (column + 1) * spacing / spanCount; // 右边距
if (position < spanCount) { // 第一行
outRect.top = spacing; // 上边距
}
outRect.bottom = spacing; // 下边距
} else {
outRect.left = column * spacing / spanCount; // 左边距
outRect.right = spacing - (column + 1) * spacing / spanCount; // 右边距
if (position >= spanCount) {
outRect.top = spacing; // 上边距
}
}
}
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ckkj.water.custom.helper;
import android.view.KeyEvent;
import android.view.View;
/**
* Helper for accessing features in {@link KeyEvent} introduced after
* API level 4 in a backwards compatible fashion.
*/
public final class KeyEventCompat {
/**
* Interface for the full API.
*/
interface KeyEventVersionImpl {
int normalizeMetaState(int metaState);
boolean metaStateHasModifiers(int metaState, int modifiers);
boolean metaStateHasNoModifiers(int metaState);
boolean isCtrlPressed(KeyEvent event);
}
/**
* Interface implementation that doesn't use anything about v4 APIs.
*/
static class BaseKeyEventVersionImpl implements KeyEventVersionImpl {
private static final int META_MODIFIER_MASK =
KeyEvent.META_SHIFT_ON | KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON
| KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON
| KeyEvent.META_SYM_ON;
// Mask of all lock key meta states.
private static final int META_ALL_MASK = META_MODIFIER_MASK;
private static int metaStateFilterDirectionalModifiers(int metaState,
int modifiers, int basic, int left, int right) {
final boolean wantBasic = (modifiers & basic) != 0;
final int directional = left | right;
final boolean wantLeftOrRight = (modifiers & directional) != 0;
if (wantBasic) {
if (wantLeftOrRight) {
throw new IllegalArgumentException("bad arguments");
}
return metaState & ~directional;
} else if (wantLeftOrRight) {
return metaState & ~basic;
} else {
return metaState;
}
}
@Override
public int normalizeMetaState(int metaState) {
if ((metaState & (KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON)) != 0) {
metaState |= KeyEvent.META_SHIFT_ON;
}
if ((metaState & (KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON)) != 0) {
metaState |= KeyEvent.META_ALT_ON;
}
return metaState & META_ALL_MASK;
}
@Override
public boolean metaStateHasModifiers(int metaState, int modifiers) {
metaState = normalizeMetaState(metaState) & META_MODIFIER_MASK;
metaState = metaStateFilterDirectionalModifiers(metaState, modifiers,
KeyEvent.META_SHIFT_ON, KeyEvent.META_SHIFT_LEFT_ON, KeyEvent.META_SHIFT_RIGHT_ON);
metaState = metaStateFilterDirectionalModifiers(metaState, modifiers,
KeyEvent.META_ALT_ON, KeyEvent.META_ALT_LEFT_ON, KeyEvent.META_ALT_RIGHT_ON);
return metaState == modifiers;
}
@Override
public boolean metaStateHasNoModifiers(int metaState) {
return (normalizeMetaState(metaState) & META_MODIFIER_MASK) == 0;
}
@Override
public boolean isCtrlPressed(KeyEvent event) {
return false;
}
}
/**
* Interface implementation for devices with at least v11 APIs.
*/
static class HoneycombKeyEventVersionImpl extends BaseKeyEventVersionImpl {
@Override
public int normalizeMetaState(int metaState) {
return KeyEventCompatHoneycomb.normalizeMetaState(metaState);
}
@Override
public boolean metaStateHasModifiers(int metaState, int modifiers) {
return KeyEventCompatHoneycomb.metaStateHasModifiers(metaState, modifiers);
}
@Override
public boolean metaStateHasNoModifiers(int metaState) {
return KeyEventCompatHoneycomb.metaStateHasNoModifiers(metaState);
}
@Override
public boolean isCtrlPressed(KeyEvent event) {
return KeyEventCompatHoneycomb.isCtrlPressed(event);
}
}
/**
* Select the correct implementation to use for the current platform.
*/
static final KeyEventVersionImpl IMPL;
static {
if (android.os.Build.VERSION.SDK_INT >= 11) {
IMPL = new HoneycombKeyEventVersionImpl();
} else {
IMPL = new BaseKeyEventVersionImpl();
}
}
// -------------------------------------------------------------------
public static int normalizeMetaState(int metaState) {
return IMPL.normalizeMetaState(metaState);
}
public static boolean metaStateHasModifiers(int metaState, int modifiers) {
return IMPL.metaStateHasModifiers(metaState, modifiers);
}
public static boolean metaStateHasNoModifiers(int metaState) {
return IMPL.metaStateHasNoModifiers(metaState);
}
public static boolean hasModifiers(KeyEvent event, int modifiers) {
return IMPL.metaStateHasModifiers(event.getMetaState(), modifiers);
}
public static boolean hasNoModifiers(KeyEvent event) {
return IMPL.metaStateHasNoModifiers(event.getMetaState());
}
/**
* @deprecated Call {@link KeyEvent#startTracking()} directly. This method will be removed in a
* future release.
*/
@Deprecated
public static void startTracking(KeyEvent event) {
event.startTracking();
}
/**
* @deprecated Call {@link KeyEvent#isTracking()} directly. This method will be removed in a
* future release.
*/
@Deprecated
public static boolean isTracking(KeyEvent event) {
return event.isTracking();
}
/**
* @deprecated Call {@link View#getKeyDispatcherState()} directly. This method will be removed
* in a future release.
*/
@Deprecated
public static Object getKeyDispatcherState(View view) {
return view.getKeyDispatcherState();
}
/**
* @deprecated Call
* {@link KeyEvent#dispatch(KeyEvent.Callback, KeyEvent.DispatcherState, Object)} directly.
* This method will be removed in a future release.
*/
@Deprecated
public static boolean dispatch(KeyEvent event, KeyEvent.Callback receiver, Object state,
Object target) {
return event.dispatch(receiver, (KeyEvent.DispatcherState)state, target);
}
public static boolean isCtrlPressed(KeyEvent event) {
return IMPL.isCtrlPressed(event);
}
private KeyEventCompat() {}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ckkj.water.custom.helper;
import android.annotation.TargetApi;
import android.view.KeyEvent;
import androidx.annotation.RequiresApi;
/**
* Implementation of key event compatibility that can call Honeycomb APIs.
*/
@RequiresApi(11)
@TargetApi(11)
class KeyEventCompatHoneycomb {
public static int normalizeMetaState(int metaState) {
return KeyEvent.normalizeMetaState(metaState);
}
public static boolean metaStateHasModifiers(int metaState, int modifiers) {
return KeyEvent.metaStateHasModifiers(metaState, modifiers);
}
public static boolean metaStateHasNoModifiers(int metaState) {
return KeyEvent.metaStateHasNoModifiers(metaState);
}
public static boolean isCtrlPressed(KeyEvent event) {
return event.isCtrlPressed();
}
}

View File

@@ -0,0 +1,104 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
public class CircleCheckView extends View {
private Paint circlePaint;
private Paint checkPaint;
private int backgroundColor = 0xFF000000; // 默认黑色
private boolean showCheck = false; // 是否显示对号
public CircleCheckView(Context context) {
super(context);
init();
}
public CircleCheckView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public CircleCheckView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
circlePaint.setColor(backgroundColor);
circlePaint.setStyle(Paint.Style.FILL);
checkPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
checkPaint.setColor(0xFFFFFFFF); // 默认白色对号
checkPaint.setStyle(Paint.Style.STROKE);
checkPaint.setStrokeWidth(8f); // 对号线宽
checkPaint.setStrokeCap(Paint.Cap.ROUND);
checkPaint.setStrokeJoin(Paint.Join.ROUND);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
int radius = Math.min(width, height) / 2;
// 画圆
canvas.drawCircle(width / 2f, height / 2f, radius, circlePaint);
// 画对号
if (showCheck) {
drawCheckMark(canvas, width, height);
}
}
private void drawCheckMark(Canvas canvas, int width, int height) {
Path path = new Path();
float size = Math.min(width, height) * 0.2f; // 对号大小大约是圆直径40%
float centerX = width / 2f;
float centerY = height / 2f;
// 起点 (左下)
path.moveTo(centerX - size / 2, centerY);
// 中间点 (中间)
path.lineTo(centerX, centerY + size / 2);
// 终点 (右上)
path.lineTo(centerX + size / 2, centerY - size / 2);
canvas.drawPath(path, checkPaint);
}
// 外部调用,设置背景色
@Override
public void setBackgroundColor(int color) {
backgroundColor = color;
circlePaint.setColor(backgroundColor);
invalidate();
}
// 外部调用,控制显示或隐藏对号
public void setShowCheck(boolean show) {
this.showCheck = show;
invalidate();
}
// 外部调用,可以改变对号颜色
public void setCheckColor(int color) {
checkPaint.setColor(color);
invalidate();
}
// 外部调用,可以改变对号粗细
public void setCheckStrokeWidth(float width) {
checkPaint.setStrokeWidth(width);
invalidate();
}
}

View File

@@ -0,0 +1,38 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.ckkj.water.R;
import com.lxj.xpopup.core.AttachPopupView;
/**
* Description: 自定义背景的Attach弹窗
* Create by lxj, at 2019/3/13
*/
public class CustomAttachPopup extends AttachPopupView {
public CustomAttachPopup(@NonNull Context context) {
super(context);
}
@Override
protected int getImplLayoutId() {
return R.layout.custom_attach_popup;
}
@Override
protected void onCreate() {
super.onCreate();
final TextView tv = findViewById(R.id.tv_content);
tv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// tv.setText(tv.getText() + "\n 啊哈哈哈啊哈");
// tv.setText("\n 啊哈哈哈啊哈");
}
});
}
}

View File

@@ -0,0 +1,39 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.bumptech.glide.Glide;
import com.ckkj.water.R;
import com.lxj.xpopup.core.BubbleAttachPopupView;
import com.lxj.xpopup.util.XPopupUtils;
/**
* Description: 自定义气泡Attach弹窗
* Create by lxj, at 2019/3/13
*/
public class CustomBubbleAttachPopup extends BubbleAttachPopupView {
private String mContent;
public CustomBubbleAttachPopup(@NonNull Context context,String content) {
super(context);
this.mContent = content;
}
@Override
protected int getImplLayoutId() {
return R.layout.custom_bubble_attach_popup;
}
@Override
protected void onCreate() {
super.onCreate();
final TextView tv = findViewById(R.id.tv);
tv.setText(mContent);
}
}

View File

@@ -0,0 +1,37 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.core.widget.NestedScrollView;
public class CustomNestedScrollView extends NestedScrollView {
private boolean isScrollable = true;
public CustomNestedScrollView(Context context) {
super(context);
}
public CustomNestedScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setScrollable(boolean scrollable) {
this.isScrollable = scrollable;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return isScrollable && super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return isScrollable && super.onTouchEvent(ev);
}
}

View File

@@ -0,0 +1,27 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.recyclerview.widget.RecyclerView;
public class CustomNoTouchRecyclerView extends RecyclerView {
public CustomNoTouchRecyclerView(Context context) {
super(context);
}
public CustomNoTouchRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomNoTouchRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// 返回 false 以便父布局可以处理触摸事件
return false;
}
}

View File

@@ -0,0 +1,46 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import com.ckkj.water.R;
public class CustomProgressBar extends View {
private Bitmap bitmap;
private Paint paint;
private float rotation = 0;
public CustomProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
paint = new Paint();
// 加载自定义图片
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.img_loading_progressbar); // 替换为你的图片资源
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 保存当前画布状态
canvas.save();
// 旋转画布
canvas.rotate(rotation, getWidth() / 2, getHeight() / 2);
// 绘制图片
canvas.drawBitmap(bitmap, (getWidth() - bitmap.getWidth()) / 2, (getHeight() - bitmap.getHeight()) / 2, paint);
// 恢复画布状态
canvas.restore();
}
public void setRotation(float rotation) {
this.rotation = rotation;
invalidate(); // 重新绘制
}
}

View File

@@ -0,0 +1,130 @@
package com.ckkj.water.custom.view;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import com.scwang.smart.refresh.layout.api.RefreshHeader;
import com.scwang.smart.refresh.layout.api.RefreshKernel;
import com.scwang.smart.refresh.layout.api.RefreshLayout;
import com.scwang.smart.refresh.layout.constant.RefreshState;
import com.scwang.smart.refresh.layout.constant.SpinnerStyle;
import com.ckkj.water.R;
/**
* @author fengxiaoyang
* @date 2025/7/11
* @description TODO: 描述该类的作用
*/
public class CustomRefreshHeader extends RelativeLayout implements RefreshHeader {
private ImageView ivRefresh;
private ObjectAnimator rotateAnimator;
public CustomRefreshHeader(Context context) {
super(context);
init(context);
}
public CustomRefreshHeader(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
LayoutInflater.from(context).inflate(R.layout.view_refresh_header, this);
ivRefresh = findViewById(R.id.ivRefresh);
// 初始化 ObjectAnimator
rotateAnimator = ObjectAnimator.ofFloat(ivRefresh, "rotation", 0f, 360f);
rotateAnimator.setDuration(1500);
rotateAnimator.setRepeatCount(ValueAnimator.INFINITE);
rotateAnimator.setInterpolator(new LinearInterpolator()); // 匀速旋转
}
@NonNull
@Override
public View getView() {
return this;
}
@SuppressLint("RestrictedApi")
@Override
public void onStartAnimator(@NonNull RefreshLayout layout, int height, int maxDragHeight) {
if (rotateAnimator != null && !rotateAnimator.isRunning()) {
rotateAnimator.start();
}
}
@SuppressLint("RestrictedApi")
@Override
public int onFinish(@NonNull RefreshLayout layout, boolean success) {
if (rotateAnimator != null && rotateAnimator.isRunning()) {
// 为了平滑停止,先设置减速插值器,再 cancel 动画
rotateAnimator.setInterpolator(new DecelerateInterpolator());
postDelayed(() -> {
if (rotateAnimator != null) {
rotateAnimator.cancel();
rotateAnimator.setInterpolator(new LinearInterpolator()); // 恢复为匀速
}
}, 300); // 给一点缓冲时间
}
return 500; // 动画停止后延迟 500ms 收起 Header
}
// --- 必须实现的方法 ---
@NonNull
@Override
public SpinnerStyle getSpinnerStyle() {
return SpinnerStyle.Translate; // Header 跟随内容滑动
}
@Override
public boolean isSupportHorizontalDrag() {
return false;
}
@SuppressLint("RestrictedApi")
@Override
public void setPrimaryColors(@ColorInt int... colors) {}
@SuppressLint("RestrictedApi")
@Override
public void onInitialized(@NonNull RefreshKernel kernel, int height, int maxDragHeight) {}
@SuppressLint("RestrictedApi")
@Override
public void onMoving(boolean isDragging, float percent, int offset, int height, int maxDragHeight) {}
@SuppressLint("RestrictedApi")
@Override
public void onReleased(@NonNull RefreshLayout layout, int height, int maxDragHeight) {}
@SuppressLint("RestrictedApi")
@Override
public void onHorizontalDrag(float percentX, int offsetX, int offsetMax) {}
@Override
public boolean autoOpen(int duration, float dragRate, boolean animationOnly) {
return false;
}
@SuppressLint("RestrictedApi")
@Override
public void onStateChanged(@NonNull RefreshLayout refreshLayout, @NonNull RefreshState oldState, @NonNull RefreshState newState) {
}
}

View File

@@ -0,0 +1,42 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class DashedLineView extends View {
private Paint paint;
public DashedLineView(Context context) {
super(context);
init();
}
public DashedLineView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DashedLineView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
paint = new Paint();
paint.setColor(0xFF0000FF); // 蓝色
paint.setStrokeWidth(1f); // 高度为1px
paint.setStyle(Paint.Style.STROKE);
paint.setPathEffect(new android.graphics.DashPathEffect(new float[]{2, 2}, 0)); // 虚线效果
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float width = getWidth();
float height = getHeight();
canvas.drawLine(0, height / 2, width, height / 2, paint); // 绘制虚线
}
}

View File

@@ -0,0 +1,51 @@
package com.ckkj.water.custom.view;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
public class DottedRoundRectDrawable_blue extends Drawable {
private Paint mPaint;
private RectF mRectF;
private float mCornerRadius;
public DottedRoundRectDrawable_blue(float cornerRadius) {
mPaint = new Paint();
mPaint.setColor(Color.parseColor("#1A72FF")); // 设置虚线颜色
mPaint.setStyle(Paint.Style.STROKE); // 设置为描边
mPaint.setStrokeWidth(3); // 设置虚线宽度
// 设置虚线效果
mPaint.setPathEffect(new DashPathEffect(new float[]{2, 2}, 0)); // 虚线的长度和间隔
mCornerRadius = cornerRadius; // 圆角半径
mRectF = new RectF();
}
@Override
public void draw(Canvas canvas) {
// 获取当前 Drawable 的边界
mRectF.set(getBounds());
// 绘制圆角矩形虚线
canvas.drawRoundRect(mRectF, mCornerRadius, mCornerRadius, mPaint);
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(android.graphics.ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}

View File

@@ -0,0 +1,51 @@
package com.ckkj.water.custom.view;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
public class DottedRoundRectDrawable_gray extends Drawable {
private Paint mPaint;
private RectF mRectF;
private float mCornerRadius;
public DottedRoundRectDrawable_gray(float cornerRadius) {
mPaint = new Paint();
mPaint.setColor(Color.parseColor("#BDBDBD")); // 设置虚线颜色
mPaint.setStyle(Paint.Style.STROKE); // 设置为描边
mPaint.setStrokeWidth(3); // 设置虚线宽度
// 设置虚线效果
mPaint.setPathEffect(new DashPathEffect(new float[]{2, 2}, 0)); // 虚线的长度和间隔
mCornerRadius = cornerRadius; // 圆角半径
mRectF = new RectF();
}
@Override
public void draw(Canvas canvas) {
// 获取当前 Drawable 的边界
mRectF.set(getBounds());
// 绘制圆角矩形虚线
canvas.drawRoundRect(mRectF, mCornerRadius, mCornerRadius, mPaint);
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(android.graphics.ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}

View File

@@ -0,0 +1,40 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.viewpager.widget.ViewPager;
/**
* Hacky fix for Issue #4 and
* http://code.google.com/p/android/issues/detail?id=18990
* <p/>
* ScaleGestureDetector seems to mess up the touch events, which means that
* ViewGroups which make use of onInterceptTouchEvent throw a lot of
* IllegalArgumentException: pointerIndex out of range.
* <p/>
* There's not much I can do in my code for now, but we can mask the result by
* just catching the problem and ignoring it.
*
* @author Chris Banes
*/
public class HackyViewPager extends ViewPager {
public HackyViewPager(Context context) {
super(context);
}
public HackyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException e) {
return false;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.webkit.WebView;
public class MyScollWebView extends WebView {
public MyScollWebView(Context context) {
super(context);
}
public MyScollWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyScollWebView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(true); // 禁止父视图拦截触摸事件
}
return super.onTouchEvent(event);
}
}

View File

@@ -0,0 +1,40 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class NoVerticalScrollRecyclerView extends RecyclerView {
public NoVerticalScrollRecyclerView(@NonNull Context context) {
super(context);
}
public NoVerticalScrollRecyclerView(@NonNull Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoVerticalScrollRecyclerView(@NonNull Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onTouchEvent(MotionEvent e) {
// 禁止上下滑动
if (e.getAction() == MotionEvent.ACTION_MOVE) {
return true; // 返回 true 表示消费事件,不向下传递
}
return super.onTouchEvent(e); // 处理其他事件
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
// 禁止上下滑动
if (e.getAction() == MotionEvent.ACTION_MOVE) {
return true; // 返回 true 表示拦截事件
}
return super.onInterceptTouchEvent(e);
}
}

View File

@@ -0,0 +1,163 @@
package com.ckkj.water.custom.view;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.bumptech.glide.Glide;
import com.github.chrisbanes.photoview.OnPhotoTapListener;
import com.github.chrisbanes.photoview.PhotoView;
import com.gyf.immersionbar.ImmersionBar;
import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.interfaces.OnSelectListener;
import com.ckkj.water.R;
import com.ckkj.water.utils.DownFileUtil;
import java.util.ArrayList;
import java.util.List;
/**
* 图片查看器
*
* @author Mc
*/
@SuppressWarnings({ "unchecked" }) public class PhotoViewActivity extends FragmentActivity {
private HackyViewPager viewPager;
private ArrayList<ImageView> mList;
private TextView textView;
private List<String> img_urls;
private int i;
private boolean crop;
@SuppressLint("MissingInflatedId")
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_photoview);
ImmersionBar.with(this)
.statusBarColor(R.color.black)
.statusBarDarkFont(false)
.titleBar(findViewById(R.id.rl_title)) // 替换为你的标题栏View
.keyboardEnable(true)
.navigationBarDarkIcon(false)
.init();
initShowPhoto();
initView();
}
private void initShowPhoto() {
Bundle bundle = getIntent().getExtras();
if (bundle == null) {
finish();
} else {
i = bundle.getInt("img_item", 0);
crop = bundle.getBoolean("case", false);
img_urls = (List<String>) bundle.getSerializable("img_urls");
String imgUrl = bundle.getString("img_url");
if (img_urls == null) {
img_urls = new ArrayList<>();
if (imgUrl != null) {
img_urls.add(imgUrl);
}
}
}
}
private void initView() {
viewPager = (HackyViewPager) findViewById(R.id.ViewPager);
textView = (TextView) findViewById(R.id.text);
mList = new ArrayList<>();
PagerAdapter pagerAdapter = new PagerAdapter() {
// 获取要滑动的控件的数量在这里我们以滑动的广告栏为例那么这里就应该是展示的广告图片的ImageView数量
@Override public int getCount() {
return img_urls.size();
//return Integer.MAX_VALUE; 返回一个比较大的值,目的是为了实现无限轮播
}
// 来判断显示的是否是同一张图片,这里我们将两个参数相比较返回即可
@Override public boolean isViewFromObject(View view, Object object) {
return view == object;
}
// 当要显示的图片可以进行缓存的时候,会调用这个方法进行显示图片的初始化,
// 我们将要显示的ImageView加入到ViewGroup中然后作为返回值返回即可
@Override public Object instantiateItem(ViewGroup container, int position) {
PhotoView imageView = new PhotoView(PhotoViewActivity.this);
Glide.with(PhotoViewActivity.this).load(img_urls.get(position)).into(imageView);
imageView.setOnPhotoTapListener(new OnPhotoTapListener() {
@Override
public void onPhotoTap(ImageView view, float x, float y) {
}
});
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
imageView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
new XPopup.Builder(PhotoViewActivity.this).asBottomList("请选择", new String[]{"下载"}, new OnSelectListener() {
@Override
public void onSelect(int position, String text) {
if(position == 0){
DownFileUtil.downloadImage(PhotoViewActivity.this,img_urls.get(position));
}
}
}).show();
return false;
}
});
container.addView(imageView, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
mList.add(imageView);
return imageView;
}
//PagerAdapter只缓存三张要显示的图片如果滑动的图片超出了缓存的范围就会调用这个方法将图片销毁
@Override public void destroyItem(ViewGroup container, int position, Object object) {
//container.removeView(mList.get(position));
}
};
textView.setText(((i + 1) + "/" + img_urls.size()));
viewPager.setAdapter(pagerAdapter);
setSelect(i);//通过传值获取点击图片位置,从而显示当前图片
//设置滑动监听事件
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
//滑动到第几张图片的调用的方法position当前显示图片位置
@Override public void onPageSelected(int position) {
setSelect(position);
textView.setText(((position + 1) + "/" + img_urls.size()));
}
@Override public void onPageScrollStateChanged(int state) {
}
});
}
//启动查看图片时,显示你点击图片
public void setSelect(int i) {
viewPager.setCurrentItem(i);
}
}

View File

@@ -0,0 +1,144 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.ckkj.water.R;
import com.lzj.sidebar.SideBarSortView;
public class SideBarLayout extends RelativeLayout implements SideBarSortView.OnIndexChangedListener {
private View mLayout;
private Context mContext;
private TextView mTvTips;
private SideBarSortView mSortView;
private int selectTextColor;
private int unselectTextColor;
private float selectTextSize;
private float unselectTextSize;
private int wordTextColor;
private float wordTextSize;
private Drawable wordBackground;
public SideBarLayout(Context context) {
super(context);
}
public SideBarLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
initView();
}
public SideBarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
initView();
}
private void init(Context context, AttributeSet attrs) {
mContext = context;
//获取自定义属性
if (attrs != null) {
TypedArray ta = mContext.obtainStyledAttributes(attrs, R.styleable.SideBarView);
unselectTextColor = ta.getColor(R.styleable.SideBarView_sidebarUnSelectTextColor, Color.parseColor("#999999"));
selectTextColor = ta.getColor(R.styleable.SideBarView_sidebarSelectTextColor, Color.parseColor("#2E56D7"));
selectTextSize = ta.getDimension(R.styleable.SideBarView_sidebarSelectTextSize, dip2px(mContext, 12));
unselectTextSize = ta.getDimension(R.styleable.SideBarView_sidebarUnSelectTextSize, dip2px(mContext, 10));
wordTextSize = ta.getDimension(R.styleable.SideBarView_sidebarWordTextSize, px2sp(mContext, 45));
wordTextColor = ta.getColor(R.styleable.SideBarView_sidebarWordTextColor, Color.parseColor("#FFFFFF"));
wordBackground = ta.getDrawable(R.styleable.SideBarView_sidebarWordBackground);
if (wordBackground == null) {
wordBackground = context.getResources().getDrawable(R.drawable.sort_text_view_hint_bg);
}
ta.recycle();
}
}
private void initView() {
//引入布局
mLayout = LayoutInflater.from(mContext).inflate(R.layout.view_sidebar_layout, null, true);
mTvTips = (TextView) mLayout.findViewById(R.id.tvTips);
mSortView = (SideBarSortView) mLayout.findViewById(R.id.sortView);
mSortView.setIndexChangedListener(this);
mSortView.setmTextColor(unselectTextColor);
mSortView.setmTextSize(unselectTextSize);
mSortView.setmTextColorChoose(selectTextColor);
mSortView.setmTextSizeChoose(selectTextSize);
mSortView.invalidate();
mTvTips.setTextColor(wordTextColor);
mTvTips.setTextSize(px2sp(mContext, wordTextSize));
mTvTips.setBackground(wordBackground);
this.addView(mLayout); //将子布局添加到父容器,才显示控件
}
/**
* 监听回调由侧边栏滑动更新Item
*/
private OnSideBarLayoutListener mListener;
public static interface OnSideBarLayoutListener {
void onSideBarScrollUpdateItem(String word);
}
public void setSideBarLayout(OnSideBarLayoutListener listener) {
this.mListener = listener;
}
/**
* 侧边栏滑动 更新Item
* @param word 字母
*/
@Override
public void onSideBarScrollUpdateItem(String word) {
mTvTips.setVisibility(View.VISIBLE);
mTvTips.setText(word);
if (mListener != null) {
mListener.onSideBarScrollUpdateItem(word);
}
}
/**
* 侧边栏滑动结束 隐藏提示
*/
@Override
public void onSideBarScrollEndHideText() {
mTvTips.setVisibility(View.GONE);
}
/**
* Item滚动更新 侧边栏
* @param word
*/
public void onItemScrollUpdateSideBarText(String word) {
if (mListener != null) {
mSortView.onUpdateSideBarText(word);
}
}
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
public static int px2sp(Context context, float pxValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
}

View File

@@ -0,0 +1,171 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
import androidx.annotation.Nullable;
/**
* Created by lzj on 2019/12/31
* Describe :字母排序索引
*/
public class SideBarSortView extends View {
private Canvas mCanvas;
private int mSelectIndex = 0;
private float mTextSize;
private int mTextColor;
private float mTextSizeChoose;
private int mTextColorChoose;
//标记 避免重复调用
private boolean isDown = false;
private float radius = 100f; // 圆的半径
public void setmTextSize(float mTextSize) {
this.mTextSize = mTextSize;
}
public void setmTextColor(int mTextColor) {
this.mTextColor = mTextColor;
}
public void setmTextSizeChoose(float mTextSizeChoose) {
this.mTextSizeChoose = mTextSizeChoose;
}
public void setmTextColorChoose(int mTextColorChoose) {
this.mTextColorChoose = mTextColorChoose;
}
public static String[] mList = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K",
"L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "#"};
public Paint paint = new Paint();
public Paint backgroundPaint;
public SideBarSortView(Context context) {
super(context);
}
public SideBarSortView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.mCanvas = canvas;
paintText();
}
private void paintText() {
//计算每一个字母的高度,总告诉除以字母集合的高度就可以
int height = (getHeight()) / mList.length;
for (int i = 0; i < mList.length; i++) {
if (i == mSelectIndex) {
//背景色
backgroundPaint = new Paint();
backgroundPaint.setColor(Color.parseColor("#F53F3F"));
paint.setColor(mTextColorChoose);
paint.setTextSize(mTextSizeChoose);
/******背景色*******/
// 计算圆心位置
float centerX = getWidth() / 2;
float centerY = getHeight() / 2;
mCanvas.drawCircle(centerX, centerY, radius, backgroundPaint);
} else {
paint.setColor(mTextColor);
paint.setTextSize(mTextSize);
}
paint.setAntiAlias(true);//设置抗锯齿
paint.setTypeface(Typeface.DEFAULT_BOLD);
//计算每一个字母x轴
float paintX = getWidth() / 2F - paint.measureText(mList[i]) / 2;
//计算每一个字母Y轴
int paintY = height * i + height;
//绘画出来这个TextView
mCanvas.drawText(mList[i], paintX, paintY, paint);
//画完一个以后重置画笔
paint.reset();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
ViewParent parent;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
int index = (int) (event.getY() / getHeight() * mList.length);
if (index >= 0 && index < mList.length && mSelectIndex != index) {
if (mClickListener != null) {
mClickListener.onSideBarScrollUpdateItem(mList[index]);
}
mSelectIndex = index;
invalidate();
//改变标记状态
isDown = true;
}
parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);// 请求父级拦截,解决水平滑动冲突
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mClickListener != null) {
mClickListener.onSideBarScrollEndHideText();
}
//改变标记状态
isDown = false;
parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(false);// 请求父级放行,解决水平滑动冲突
}
break;
}
return true;
}
private OnIndexChangedListener mClickListener;
public static interface OnIndexChangedListener {
//滚动位置
void onSideBarScrollUpdateItem(String word);
//隐藏提示文本
void onSideBarScrollEndHideText();
}
public void setIndexChangedListener(OnIndexChangedListener listener) {
this.mClickListener = listener;
}
/**
* Item滚动 更新侧边栏字母
*
* @param word 字母
*/
public void onUpdateSideBarText(String word) {
//手指没触摸才调用
if (!isDown) {
for (int i = 0; i < mList.length; i++) {
if (mList[i].equals(word) && mSelectIndex != i) {
mSelectIndex = i;
invalidate();
}
}
}
}
}

View File

@@ -0,0 +1,87 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* @Description TODO
* @systemUser 86133
* @Author FengJingQi
* @Date 04-22-2025 周二 10:00
*/
public class SideBarView extends View {
private static final String[] LETTERS = {
"A", "B", "C", "D", "E", "F", "G", "H", "I",
"J", "K", "L", "M", "N", "O", "P", "Q", "R",
"S", "T", "U", "V", "W", "X", "Y", "Z"
};
private Paint paint = new Paint();
private int choose = -1;
private OnLetterTouchListener listener;
public SideBarView(Context context) {
super(context);
}
public SideBarView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setOnLetterTouchListener(OnLetterTouchListener listener) {
this.listener = listener;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int height = getHeight();
int width = getWidth();
int singleHeight = height / LETTERS.length;
for (int i = 0; i < LETTERS.length; i++) {
paint.setColor(Color.BLACK);
paint.setTextSize(30);
paint.setAntiAlias(true);
float xPos = width / 2 - paint.measureText(LETTERS[i]) / 2;
float yPos = singleHeight * i + singleHeight;
canvas.drawText(LETTERS[i], xPos, yPos, paint);
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
final int action = event.getAction();
final float y = event.getY();
final int oldChoose = choose;
final int c = (int) (y / getHeight() * LETTERS.length);
switch (action) {
case MotionEvent.ACTION_UP:
choose = -1;
invalidate();
break;
default:
if (oldChoose != c && c >= 0 && c < LETTERS.length) {
if (listener != null) {
listener.onLetterTouched(LETTERS[c]);
}
choose = c;
invalidate();
}
break;
}
return true;
}
public interface OnLetterTouchListener {
void onLetterTouched(String letter);
}
}

View File

@@ -0,0 +1,155 @@
package com.ckkj.water.custom.view;
import android.content.Context;
import android.graphics.Color;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import com.ckkj.water.R;
import java.util.ArrayList;
/**
* @author: gaoql
* @date: 2022/3/1 11:04
* @function:封装下拉选框
*/
public class SimpleSpinner extends androidx.appcompat.widget.AppCompatSpinner {
private ArrayAdapter adapter;
private ArrayList<String> contents;
private String defaultContent;
private Context context;
private OnSpinnerEventsListener mListener;
public SimpleSpinner(Context context) {
super(context);
onCreate(context);
}
public SimpleSpinner(Context context, int mode) {
super(context, mode);
onCreate(context);
}
public SimpleSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
onCreate(context);
}
public SimpleSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
onCreate(context);
}
/**
* @author gaoql
* @time 2022/3/1 11:05
* @description 初始化
*/
private void onCreate(Context context){
this.context = context;
}
/**
* @author gaoql
* @time 2022/3/1 11:44
* @description 设置spinner数据
*/
public void setContent(ArrayList<String> contents){
this.contents = contents;
if(adapter!=null){
adapter = null;
}
adapter = new ArrayAdapter(getContext(), R.layout.sp_item_select,contents.toArray(new String[]{}));
adapter.setDropDownViewResource(R.layout.sp_item_dropdown);
this.setAdapter(adapter);
}
/**
* @author gaoql
* @time 2022/3/3 9:12
* @description 设置默认显示内容
*/
public void setDefaultContent(String defaultContent){
this.defaultContent = defaultContent;
}
/**
* @author gaoql
* @time 2022/3/1 13:26
* @description 选择事件
*/
public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener){
setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
//首次刚加载时 判断是否设置默认显示内容,如果有则显示默认内容,逻辑是把第一条的view内容修改掉
if(!TextUtils.isEmpty(defaultContent)){
if(view instanceof TextView){
TextView textView = (TextView) view;
textView.setText(defaultContent);
textView.setTextColor(Color.parseColor("#999999"));
defaultContent = "";
}
}else{
//把刚刚修改的内容和颜色都修改回来
if(position == 0){
if(view instanceof TextView){
TextView textView = (TextView) view;
textView.setText(contents.get(0));
textView.setTextColor(Color.parseColor("#333333"));
}
}
onItemSelectedListener.onItemSelected(parent,view,position,id,contents.get(position));
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
public interface OnItemSelectedListener{
void onItemSelected(AdapterView<?> adapterView, View view, int position, long id,String content);
}
/**
* @author gaoql
* @time 2022/3/3 10:22
* @description 解决 选择相同选项时 点击不触发问题,逻辑是 如果点击的是相同选项则 强制调用一次条码选择事件
*/
@Override
public void setSelection(int position) {
super.setSelection(position);
boolean sameSelected = position == getSelectedItemPosition();
if (sameSelected) {
getOnItemSelectedListener().onItemSelected(this, getSelectedView(),
position, getSelectedItemId());
}
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (mListener != null) {
if (hasWindowFocus) {
// 收起事件
mListener.onSpinnerClosed();
} else {
// 展开事件
mListener.onSpinnerOpened();
}
}
}
public void setOnSpinnerEventsListener(OnSpinnerEventsListener listener) {
mListener = listener;
}
// 定义接口
public interface OnSpinnerEventsListener {
void onSpinnerOpened();
void onSpinnerClosed();
}
}

View File

@@ -0,0 +1,188 @@
package com.ckkj.water.device;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import android.Manifest;
import android.content.Intent;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import com.ckkj.water.ConstantUtil;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.chat.mvp.IndexPresenter;
import com.ckkj.water.databinding.AddDeviceLayoutBinding;
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.network.BaseBean;
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.ArrayList;
import java.util.List;
import pub.devrel.easypermissions.EasyPermissions;
/**
* 添加设备页面
*/
public class AddDeviceActivity extends BaseActivity<AddDeviceLayoutBinding, DevicePresenter>
implements DeviceContract.DeviceView, EasyPermissions.PermissionCallbacks {
@Override
public DevicePresenter createPresenter() {
return new DevicePresenter(new DeviceImpl());
}
@Override
public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
ImmersionBar.with(this)
.statusBarColor(R.color.color_F9F9F9) // 设置状态栏颜色
.statusBarDarkFont(true) // 设置状态栏字体为黑色
.titleBar(viewBinding.rlTitle)
.init();
viewBinding.includedTitle.tvTitle.setText(R.string.add_device_title);
// 启动帧动画
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);
viewBinding.imgDeviceItem.setVisibility(VISIBLE);
}
}
}
},3000);
initListener();
}
private void initListener() {
setClick(viewBinding.includedTitle.imgBack);
setClick(viewBinding.tvScanAdd);
setClick(viewBinding.imgDeviceItem);
}
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.img_device_item:
Bundle bundle = new Bundle();
bundle.putInt(ConstantUtil.ACTIVITY_NAVIGATE_FLAG,100);
goTo(mContext, SelectWifiActivity.class,bundle);
break;
case R.id.tv_scan_add:
//检测有无相机权限
String readPermission = Manifest.permission.CAMERA;
if(!hasRecordPermission(readPermission)){
getPermissionRequst(readPermission,"权限申请",
"智能浇水需要您的授权访问相机,并使用扫一扫",REQUEST_EVENT_CODE_10001);
}else{
scanQrcode();
}
break;
}
}
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 onRequestPermissionsResult(int requestCode, @NonNull @NotNull String[] permissions, @NonNull @NotNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
@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) {
}
}

View File

@@ -0,0 +1,97 @@
package com.ckkj.water.device;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.databinding.DeviceConnectLayoutBinding;
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.network.BaseBean;
import com.ckkj.water.utils.show.ToastUtil;
import com.gyf.immersionbar.ImmersionBar;
/**
* 连接设备页面
*/
public class DeviceConnectActivity extends BaseActivity<DeviceConnectLayoutBinding, DevicePresenter>
implements DeviceContract.DeviceView {
private AnimationDrawable animationDrawable;
private Handler handler = new Handler(Looper.getMainLooper());
private static final long ANIMATION_DURATION = 5000L; // 5秒
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
ImmersionBar.with(this)
.statusBarColor(R.color.color_F9F9F9)
.statusBarDarkFont(true)
.titleBar(viewBinding.rlTitle)
.init();
viewBinding.includedTitle.tvTitle.setText(R.string.select_wifi_tip);
startConnectAnimation();
}
private void startConnectAnimation() {
viewBinding.ivConnectAnimation.setImageResource(R.drawable.anim_connect_device);
animationDrawable = (AnimationDrawable) viewBinding.ivConnectAnimation.getDrawable();
if (animationDrawable != null) {
animationDrawable.start();
handler.postDelayed(() -> {
if (animationDrawable != null && animationDrawable.isRunning()) {
animationDrawable.stop();
}
viewBinding.linearConnectIng.setVisibility(GONE);
viewBinding.linearSuccess.setVisibility(VISIBLE);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
goTo(mContext, DeviceReNameActivity.class,null);
}
},1000);
}, ANIMATION_DURATION);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
if (animationDrawable != null && animationDrawable.isRunning()) {
animationDrawable.stop();
}
}
@Override
public DevicePresenter createPresenter() {
return new DevicePresenter(new DeviceImpl());
}
@Override
public int getLayoutResId(Bundle savedInstanceState) {
return 0;
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
}

View File

@@ -0,0 +1,134 @@
package com.ckkj.water.device;
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.BaseActivity;
import com.ckkj.water.custom.GridSpacingItemDecoration;
import com.ckkj.water.custom.view.CustomAttachPopup;
import com.ckkj.water.custom.view.CustomBubbleAttachPopup;
import com.ckkj.water.databinding.DeviceControlLayoutBinding;
import com.ckkj.water.device.adapter.DeviceTimeSelectAdapter;
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.network.BaseBean;
import com.gyf.immersionbar.ImmersionBar;
import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.core.BasePopupView;
import java.util.ArrayList;
import java.util.List;
/**
* 设备控制页面
*/
public class DeviceControlActivity extends BaseActivity<DeviceControlLayoutBinding, DevicePresenter>
implements DeviceContract.DeviceView {
private List<String> mTimeList = new ArrayList<>();
private DeviceTimeSelectAdapter mAdapter;
@Override
public DevicePresenter createPresenter() {
return new DevicePresenter(new DeviceImpl());
}
@Override
public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
mTimeList.add("1min");
mTimeList.add("2min");
mTimeList.add("3min");
mTimeList.add("4min");
mTimeList.add("5min");
mTimeList.add("10min");
mTimeList.add("15min");
mTimeList.add("30min");
mTimeList.add("1h");
mTimeList.add("2h");
mTimeList.add("3h");
mTimeList.add("4h");
ImmersionBar.with(this)
.statusBarColor(R.color.color_F9F9F9) // 设置状态栏颜色
.statusBarDarkFont(true) // 设置状态栏字体为黑色
.titleBar(viewBinding.rlTitle)
.init();
viewBinding.includedTitle.tvTitle.setText("设备名称");
viewBinding.includedTitle.imgSetting.setVisibility(View.VISIBLE);
mAdapter = new DeviceTimeSelectAdapter(mContext,R.layout.device_work_time_item,mTimeList);
viewBinding.rvTimeList.setAdapter(mAdapter);
viewBinding.rvTimeList.addItemDecoration(new GridSpacingItemDecoration(4, 10, true));
mAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
mAdapter.setOnSelPosition(position);
}
});
initListener();
}
private void initListener() {
setClick(viewBinding.includedTitle.imgBack);
setClick(viewBinding.includedTitle.imgSetting);
setClick(viewBinding.linearBt);
setClick(viewBinding.linearWifi);
setClick(viewBinding.linearBat);
setClick(viewBinding.tvConfirm);
}
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.img_setting:
goTo(mContext, DeviceSettingsActivity.class,null);
break;
case R.id.linear_bt:
break;
case R.id.linear_wifi:
break;
case R.id.linear_bat:
new XPopup.Builder(mContext)
.isTouchThrough(true)
.isDestroyOnDismiss(true) //对于只使用一次的弹窗,推荐设置这个
.atView(viewBinding.linearBat)
.hasShadowBg(false) // 去掉半透明背景
.asCustom(new CustomBubbleAttachPopup(mContext,"设备电量:40% 更新时间: 05- 11 18:00"))
.show();
break;
case R.id.tv_confirm:
showCenterTipDialog(R.mipmap.icon_dialog_success,"开始浇水");
break;
}
}
@Override
public int getLayoutResId(Bundle savedInstanceState) {
return 0;
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
}

View File

@@ -0,0 +1,68 @@
package com.ckkj.water.device;
import android.os.Bundle;
import android.view.View;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.databinding.DeviceInfoLayoutBinding;
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.network.BaseBean;
import com.gyf.immersionbar.ImmersionBar;
/**
* 设备信息
*/
public class DeviceInfoActivity extends BaseActivity<DeviceInfoLayoutBinding, DevicePresenter>
implements DeviceContract.DeviceView {
@Override
public DevicePresenter createPresenter() {
return new DevicePresenter(new DeviceImpl());
}
@Override
public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
ImmersionBar.with(this)
.statusBarColor(R.color.white) // 设置状态栏颜色
.statusBarDarkFont(true) // 设置状态栏字体为黑色
.titleBar(viewBinding.rlTitle)
.init();
viewBinding.includedTitle.tvTitle.setText(R.string.device_setting_info);
initListener();
}
private void initListener() {
setClick(viewBinding.includedTitle.imgBack);
}
private void setClick(View view) {
view.setOnClickListener(this::onClick);
}
public void onClick(View v){
switch (v.getId()){
case R.id.img_back:
finish();
break;
}
}
@Override
public int getLayoutResId(Bundle savedInstanceState) {
return 0;
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
}

View File

@@ -0,0 +1,79 @@
package com.ckkj.water.device;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.databinding.SetDeviceNameLayoutBinding;
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.network.BaseBean;
import com.ckkj.water.utils.show.ToastUtil;
import com.gyf.immersionbar.ImmersionBar;
/**
* 重置设备名称
*/
public class DeviceReNameActivity extends BaseActivity<SetDeviceNameLayoutBinding, DevicePresenter>
implements DeviceContract.DeviceView {
@Override
public DevicePresenter createPresenter() {
return new DevicePresenter(new DeviceImpl());
}
@Override
public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
ImmersionBar.with(this)
.statusBarColor(R.color.color_F9F9F9) // 设置状态栏颜色
.statusBarDarkFont(true) // 设置状态栏字体为黑色
.titleBar(viewBinding.rlTitle)
.init();
viewBinding.includedTitle.tvTitle.setText(R.string.set_name);
initListener();
}
private void initListener() {
setClick(viewBinding.includedTitle.imgBack);
setClick(viewBinding.tvCommit);
}
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_commit:
if(TextUtils.isEmpty(viewBinding.etDeviceName.getText().toString().trim())){
ToastUtil.showShort(mContext,getString(R.string.input_device_name_hint));
return;
}
ToastUtil.showShort(mContext,"名称保存成功");
goTo(mContext,DeviceControlActivity.class,null);
break;
}
}
@Override
public int getLayoutResId(Bundle savedInstanceState) {
return 0;
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
}

View File

@@ -0,0 +1,143 @@
package com.ckkj.water.device;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.Nullable;
import com.ckkj.water.ConstantUtil;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.databinding.DeviceSettingsLayoutBinding;
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.network.BaseBean;
import com.ckkj.water.utils.show.ToastUtil;
import com.gyf.immersionbar.ImmersionBar;
/**
* 设备控制页面
*/
public class DeviceSettingsActivity extends BaseActivity<DeviceSettingsLayoutBinding, DevicePresenter>
implements DeviceContract.DeviceView {
@Override
public DevicePresenter createPresenter() {
return new DevicePresenter(new DeviceImpl());
}
@Override
public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
ImmersionBar.with(this)
.statusBarColor(R.color.white) // 设置状态栏颜色
.statusBarDarkFont(true) // 设置状态栏字体为黑色
.titleBar(viewBinding.rlTitle)
.init();
viewBinding.includedTitle.tvTitle.setText(R.string.settings_title);
initListener();
}
private void initListener() {
setClick(viewBinding.includedTitle.imgBack);
setClick(viewBinding.rlDevName);
setClick(viewBinding.rlDevInfo);
setClick(viewBinding.rlDevWifiManager);
setClick(viewBinding.rlDevUnbind);
}
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.rl_dev_name:
showEditDialog(getString(R.string.device_setting_name),
getString(R.string.input_device_name_hint),
true,
getString(R.string.cancel_text),
getString(R.string.confirm_text), new OnDialogClick() {
@Override
public void onCancelClick() {
}
@Override
public void onConfirmClisk() {
}
@Override
public void onConfirmClisk(String content) {
viewBinding.tvDeviceName.setText(content);
}
@Override
public void onView1Click() {
}
});
break;
case R.id.rl_dev_info:
goTo(mContext, DeviceInfoActivity.class,null);
break;
case R.id.rl_dev_wifi_manager:
Bundle bundle = new Bundle();
bundle.putInt(ConstantUtil.ACTIVITY_NAVIGATE_FLAG,200);
goToForResult(mContext, SelectWifiActivity.class,REQUEST_EVENT_CODE_10001,bundle);
break;
case R.id.rl_dev_unbind:
showDialogtext(null, false, false, true,
getString(R.string.tip_text), getString(R.string.tip_unbind_device),
getString(R.string.cancel_text), getString(R.string.confirm_text), new BaseFragment.OnDialogClick() {
@Override
public void onCancelClick() {
}
@Override
public void onConfirmClick() {
ToastUtil.showShort(mContext,"确定");
}
});
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data != null) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case REQUEST_EVENT_CODE_10001:
ToastUtil.showShort(mContext,data.getStringExtra("wifi_name"));
break;
}
}
}
}
@Override
public int getLayoutResId(Bundle savedInstanceState) {
return 0;
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
}

View File

@@ -0,0 +1,222 @@
package com.ckkj.water.device;
import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import com.ckkj.water.ConstantUtil;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.databinding.DeviceResetWifiBinding;
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.network.BaseBean;
import com.ckkj.water.utils.show.ToastUtil;
import com.ckkj.water.utils.text.TextUtil;
import com.gyf.immersionbar.ImmersionBar;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class SelectWifiActivity extends BaseActivity<DeviceResetWifiBinding, DevicePresenter>
implements DeviceContract.DeviceView {
private WifiManager wifiManager;
private WifiListAdapter wifiListAdapter;
private WifiScanReceiver wifiScanReceiver;
//100 来自设备添加, 200 来自设备信息
private int WITCH_FROM_CODE = 100;
private String mWifiName = "";
@Override
public DevicePresenter createPresenter() {
return new DevicePresenter(new DeviceImpl());
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
wifiScanReceiver = new WifiScanReceiver();
}
@Override
protected void onResume() {
super.onResume();
registerReceiver(wifiScanReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(wifiScanReceiver);
}
@Override
public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
Bundle bundle = getIntent().getExtras();
if(bundle != null){
WITCH_FROM_CODE = bundle.getInt(ConstantUtil.ACTIVITY_NAVIGATE_FLAG);
}
ImmersionBar.with(this)
.statusBarColor(R.color.color_F9F9F9)
.statusBarDarkFont(true)
.titleBar(viewBinding.rlTitle)
.init();
if(WITCH_FROM_CODE == 200){
viewBinding.tvNext.setText(getString(R.string.confirm_text));
}
viewBinding.includedTitle.tvTitle.setText(R.string.select_wifi_tip);
initListener();
initWifiList();
}
private void initWifiList() {
wifiListAdapter = new WifiListAdapter();
viewBinding.rvWifiList.setAdapter(wifiListAdapter);
wifiListAdapter.setOnWifiItemClickListener(wifiName -> {
mWifiName = wifiName;
viewBinding.etWifiName.setText(wifiName);
viewBinding.rvWifiList.setVisibility(View.GONE);
viewBinding.linearWifiInfo.setVisibility(View.VISIBLE);
viewBinding.tvNext.setVisibility(View.VISIBLE);
});
}
private void initListener() {
setClick(viewBinding.includedTitle.imgBack);
setClick(viewBinding.tvSelectWifi);
setClick(viewBinding.tvNext);
}
private void setClick(View view) {
view.setOnClickListener(this::onClick);
}
public void onClick(View view){
switch (view.getId()){
case R.id.img_back:
finish();
break;
case R.id.tv_select_wifi:
scanWifi();
break;
case R.id.tv_next:
if(TextUtils.isEmpty(mWifiName)){
ToastUtil.showShort(mContext,getString(R.string.toast_select_wifi_tip));
return;
}
if(TextUtils.isEmpty(viewBinding.etInputPsd.getText().toString())){
ToastUtil.showShort(mContext,getString(R.string.toast_select_wifi_psd_tip));
return;
}
if(WITCH_FROM_CODE == 100){
goTo(mContext,DeviceConnectActivity.class,null);
}else{
Intent intent = new Intent();
intent.putExtra("wifi_name",mWifiName);
intent.putExtra("wifi_psd",viewBinding.etInputPsd.getText().toString());
setResult(RESULT_OK,intent);
finish();
}
break;
}
}
private void scanWifi() {
showLoadingDialog();
viewBinding.tvNext.setVisibility(View.GONE);
if (wifiManager != null && wifiManager.isWifiEnabled()) {
wifiManager.startScan();
} else {
ToastUtil.showShort(mContext, getString(R.string.wifi_not_enabled));
hideDialogLoading();
}
}
private void displayWifiList(List<ScanResult> scanResults) {
Set<String> wifiSet = new HashSet<>();
List<String> wifiNameList = new ArrayList<>();
for (ScanResult result : scanResults) {
String wifiName = result.SSID;
if (wifiName != null && !wifiName.isEmpty() && !wifiSet.contains(wifiName)) {
wifiSet.add(wifiName);
wifiNameList.add(wifiName);
}
}
hideDialogLoading();
if (wifiNameList.isEmpty()) {
ToastUtil.showShort(mContext, getString(R.string.no_wifi_found));
viewBinding.linearWifiInfo.setVisibility(View.VISIBLE);
viewBinding.rvWifiList.setVisibility(View.GONE);
} else {
wifiListAdapter.setData(wifiNameList);
viewBinding.linearWifiInfo.setVisibility(View.GONE);
viewBinding.rvWifiList.setVisibility(View.VISIBLE);
}
}
private class WifiScanReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) {
boolean success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
if (success) {
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
List<ScanResult> results = wifiManager.getScanResults();
displayWifiList(results);
} else {
ToastUtil.showShort(mContext, getString(R.string.wifi_scan_failed));
}
}
}
}
@Override
public int getLayoutResId(Bundle savedInstanceState) {
return 0;
}
@Override
public void showError(String message) {
ToastUtil.showShort(mContext,message);
}
@Override
public void logOut(BaseBean bean) {
}
}

View File

@@ -0,0 +1,69 @@
package com.ckkj.water.device;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.ckkj.water.R;
import java.util.ArrayList;
import java.util.List;
public class WifiListAdapter extends RecyclerView.Adapter<WifiListAdapter.WifiViewHolder> {
private List<String> wifiList = new ArrayList<>();
private OnWifiItemClickListener listener;
public interface OnWifiItemClickListener {
void onWifiItemClick(String wifiName);
}
public void setOnWifiItemClickListener(OnWifiItemClickListener listener) {
this.listener = listener;
}
public void setData(List<String> list) {
this.wifiList = list;
notifyDataSetChanged();
}
@NonNull
@Override
public WifiViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.wifi_list_item, parent, false);
return new WifiViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull WifiViewHolder holder, int position) {
String wifiName = wifiList.get(position);
holder.tvWifiName.setText(wifiName);
holder.itemView.setOnClickListener(v -> {
if (listener != null) {
listener.onWifiItemClick(wifiName);
}
});
}
@Override
public int getItemCount() {
return wifiList.size();
}
static class WifiViewHolder extends RecyclerView.ViewHolder {
ImageView ivWifiIcon;
TextView tvWifiName;
public WifiViewHolder(@NonNull View itemView) {
super(itemView);
ivWifiIcon = itemView.findViewById(R.id.iv_wifi_icon);
tvWifiName = itemView.findViewById(R.id.tv_wifi_name);
}
}
}

View File

@@ -0,0 +1,43 @@
package com.ckkj.water.device.adapter;
import android.content.Context;
import android.widget.RelativeLayout;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.ckkj.water.R;
import java.util.ArrayList;
import java.util.List;
public class DeviceTimeSelectAdapter extends BaseQuickAdapter<String, BaseViewHolder> {
private Context mContext;
private List<String> mDatas = new ArrayList<>();
private int mSelPostion = -1;
public DeviceTimeSelectAdapter(Context context,int layoutResId, @Nullable List<String> data) {
super(layoutResId, data);
this.mContext = context;
this.mDatas = data;
}
@Override
protected void convert(BaseViewHolder helper, String item) {
helper.setText(R.id.tv_itme,item);
RelativeLayout relTextBg = helper.getView(R.id.rel_text_bg);
if(helper.getLayoutPosition() == mSelPostion){
relTextBg.setBackground(mContext.getResources().getDrawable(R.drawable.shape_green_button_bg));
helper.setTextColor(R.id.tv_itme,mContext.getResources().getColor(R.color.white));
}else{
relTextBg.setBackground(mContext.getResources().getDrawable(R.drawable.shape_f7f7f7_line_button_bg));
helper.setTextColor(R.id.tv_itme,mContext.getResources().getColor(R.color.color_838080));
}
}
public void setOnSelPosition(int position) {
this.mSelPostion = position;
notifyDataSetChanged();
}
}

View File

@@ -0,0 +1,15 @@
package com.ckkj.water.device.mvp;
import com.ckkj.water.base.IView;
public class DeviceContract {
public interface CallBack<T> {
void success(T msg);
void fail(String msg);
}
public interface DataModel{
}
public interface DeviceView extends IView {
}
}

View File

@@ -0,0 +1,5 @@
package com.ckkj.water.device.mvp;
public class DeviceImpl implements DeviceContract.DataModel{
}

View File

@@ -0,0 +1,11 @@
package com.ckkj.water.device.mvp;
import com.ckkj.water.base.BasePresenter;
public class DevicePresenter extends BasePresenter<DeviceContract.DeviceView> {
private DeviceImpl impl;
public DevicePresenter(DeviceImpl impl) {
this.impl = impl;
}
}

View File

@@ -0,0 +1,109 @@
package com.ckkj.water.dialog;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.TextView;
import com.ckkj.water.R;
/**
* @author messi.mo
* @date 2017/11/22
* 底部选择框
*/
public class A_custom_base_Dialog {
public static View layoutView;
private Dialog mDialog;
private Context mContext;
private TextView tvOneMonth,tvThreeMonth,tvSixMonth,tvStartTime,tvEndTime,tvClear,tvConfirm;
private ImageView imgClose,imgClear;
private String startTime = "";
private String endTime = "";
private DialogListener mListener;
private Animation animUp;
private Animation animDown;
public void setOnDialogListener(DialogListener listener){
this.mListener = listener;
}
public interface DialogListener{
void callBackDatas(String startTime,String endTime);
}
public A_custom_base_Dialog(Activity context, int layoutId) {
this.mContext = context;
mDialog = new Dialog(context, R.style.ActionSheetDialogStyle);
//填充对话框的布局
layoutView = LayoutInflater.from(context).inflate(layoutId, null);
//将布局设置给Dialog
mDialog.setContentView(layoutView);
// 为弹出和关闭设置动画
animUp = AnimationUtils.loadAnimation(mContext, R.anim.popup_anim_up);
animDown = AnimationUtils.loadAnimation(mContext, R.anim.popup_anim_down);
try {
//设置滑出动画
layoutView.startAnimation(animUp);
} catch (Exception e) {
e.printStackTrace();
}
//获取当前Activity所在的窗体
Window dialogWindow = mDialog.getWindow();
mDialog.setCanceledOnTouchOutside(true);
//设置Dialog从窗体底部弹出
if (dialogWindow != null) {
dialogWindow.setGravity(Gravity.BOTTOM);
//获得窗体的属性
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
lp.width = context.getWindowManager().getDefaultDisplay().getWidth();
//设置Dialog距离底部的距离
//lp.y = 30;
// 将属性设置给窗体
dialogWindow.setAttributes(lp);
}
imgClose = layoutView.findViewById(R.id.img_close);
imgClose.setOnClickListener(onclick);
}
View.OnClickListener onclick = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.img_close:
mDialog.dismiss();
break;
}
}
};
public void show() {
if(mDialog != null){
mDialog.show();
}
}
public void dismiss() {
if(mDialog != null){
mDialog.dismiss();
}
}
}

View File

@@ -0,0 +1,95 @@
package com.ckkj.water.dialog;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import com.ckkj.water.R;
import java.util.Objects;
/**
* 居中提示弹窗
*/
public class CenterTipDialog extends Dialog {
private int imageRes = 0;
private String title = "";
private ImageView imageView;
private TextView textView;
private Handler handler = new Handler();
private Runnable dismissRunnable;
public CenterTipDialog(Context context) {
super(context);
}
public CenterTipDialog(Context context, int imageRes, String title) {
super(context);
this.imageRes = imageRes;
this.title = title;
}
public CenterTipDialog(Context context, int theme, int imageRes, String title) {
super(context, theme);
this.imageRes = imageRes;
this.title = title;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
}
@SuppressLint("ResourceAsColor")
private void init() {
getWindow().setBackgroundDrawableResource(R.color.translucent_black_95);
getWindow().setDimAmount(0.5f);
getWindow().setGravity(Gravity.CENTER);
setCancelable(true);
setCanceledOnTouchOutside(true);
setContentView(R.layout.center_tip_dialog);
imageView = findViewById(R.id.image);
textView = findViewById(R.id.tv_title);
if (imageRes != 0) {
imageView.setImageResource(imageRes);
}
textView.setText(title);
WindowManager.LayoutParams params = Objects.requireNonNull(getWindow()).getAttributes();
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.MATCH_PARENT;
getWindow().setAttributes(params);
}
@Override
public void show() {
super.show();
if (dismissRunnable != null) {
handler.postDelayed(dismissRunnable, 800);
}
}
public void setDismissDelay(long delayMillis, Runnable onDismiss) {
this.dismissRunnable = new Runnable() {
@Override
public void run() {
if (isShowing()) {
dismiss();
}
if (onDismiss != null) {
onDismiss.run();
}
}
};
}
}

View File

@@ -0,0 +1,201 @@
package com.ckkj.water.dialog;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.TextView;
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.mine.entity.ReportEntity;
import com.ckkj.water.utils.show.ToastUtil;
import java.util.ArrayList;
import java.util.List;
/**
* @author messi.mo
* @date 2017/11/22
* 底部选择框
*/
public class ContentReportDialog {
public static View layoutView;
private Dialog mDialog;
private Context mContext;
private TextView tvCommit,tvThreeMonth,tvSixMonth,tvStartTime,tvEndTime,tvClear,tvConfirm;
private ImageView imgClose,imgClear;
private String startTime = "";
private String endTime = "";
private DialogListener mListener;
private Animation animUp;
private Animation animDown;
//////////////////////////////////////////////
private RecyclerView rvDatas;
private String mReason;
private List<ReportEntity> reportList = new ArrayList<>();
public void setOnDialogListener(DialogListener listener){
this.mListener = listener;
}
public interface DialogListener{
void callBackDatas(String reason);
}
public ContentReportDialog(Activity context, int layoutId, String reason) {
this.mContext = context;
this.mReason = reason;
mDialog = new Dialog(context, R.style.ActionSheetDialogStyle);
//填充对话框的布局
layoutView = LayoutInflater.from(context).inflate(layoutId, null);
//将布局设置给Dialog
mDialog.setContentView(layoutView);
// 为弹出和关闭设置动画
animUp = AnimationUtils.loadAnimation(mContext, R.anim.popup_anim_up);
animDown = AnimationUtils.loadAnimation(mContext, R.anim.popup_anim_down);
try {
//设置滑出动画
layoutView.startAnimation(animUp);
} catch (Exception e) {
e.printStackTrace();
}
//获取当前Activity所在的窗体
Window dialogWindow = mDialog.getWindow();
mDialog.setCanceledOnTouchOutside(true);
//设置Dialog从窗体底部弹出
if (dialogWindow != null) {
dialogWindow.setGravity(Gravity.BOTTOM);
//获得窗体的属性
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
lp.width = context.getWindowManager().getDefaultDisplay().getWidth();
//设置Dialog距离底部的距离
//lp.y = 30;
// 将属性设置给窗体
dialogWindow.setAttributes(lp);
}
List<String> reasonList = new ArrayList<>();
reasonList.add("有害/不安全");
reasonList.add("涉嫌广告");
reasonList.add("虚假信息");
reasonList.add("不准确");
reasonList.add("毫无作用");
reasonList.add("其他原因");
for(String content : reasonList){
ReportEntity entity = new ReportEntity(content,false);
reportList.add(entity);
}
imgClose = layoutView.findViewById(R.id.img_close);
rvDatas = layoutView.findViewById(R.id.rv_reasons);
tvCommit = layoutView.findViewById(R.id.tv_commit);
imgClose.setOnClickListener(onclick);
tvCommit.setOnClickListener(onclick);
ReasonAdapter adapter = new ReasonAdapter(R.layout.order_cancel_item_layout,reportList,mReason);
rvDatas.setAdapter(adapter);
adapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter ada, View view, int position) {
if(mListener != null){
adapter.setSelectPos(position);
}
}
});
}
View.OnClickListener onclick = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.img_close:
mDialog.dismiss();
break;
case R.id.tv_commit:
boolean hasSel = false;
ReportEntity selEntity = null;
for(ReportEntity entity : reportList){
if(entity.isCheck()){
hasSel = true;
selEntity = entity;
}
}
if(!hasSel){
ToastUtil.showShort(mContext,"请选择举报/反馈理由");
return;
}
if(mListener != null){
mListener.callBackDatas(selEntity.getReportReason());
dismiss();
}
break;
}
}
};
public void show() {
if(mDialog != null){
mDialog.show();
}
}
public void dismiss() {
if(mDialog != null){
mDialog.dismiss();
}
}
class ReasonAdapter extends BaseQuickAdapter<ReportEntity, BaseViewHolder>{
private String mReason = "";
private int mPos = -1;
public ReasonAdapter(int layoutResId, @Nullable List<ReportEntity> data,String reason) {
super(layoutResId, data);
mReason = reason;
}
public void setSelectPos(int position){
mPos = position;
List<ReportEntity> list = getData();
for (int i = 0; i < list.size(); i++) {
list.get(i).setCheck(i == position);
}
notifyDataSetChanged();
};
@Override
protected void convert(BaseViewHolder helper, ReportEntity item) {
RadioButton radioButton = helper.getView(R.id.radio6);
helper.setText(R.id.tv_reason, item.getReportReason());
int adapterPosition = helper.getAdapterPosition();
radioButton.setChecked(mPos == adapterPosition);
// 添加点击事件
helper.itemView.setOnClickListener(v -> {
if (mPos != adapterPosition) { // 不允许取消选中,只能换选项
setSelectPos(adapterPosition);
}
});
}
}
}

View File

@@ -0,0 +1,227 @@
package com.ckkj.water.dialog;
import android.Manifest;
import android.app.Activity;
import android.app.Dialog;
import android.app.DownloadManager;
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.text.Html;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import com.chiclaim.android.downloader.DownloadRequest;
import com.ckkj.water.AppConfig;
import com.ckkj.water.R;
import com.ckkj.water.main.entity.CheckVersionEntity;
import com.ckkj.water.utils.DownLoadApk;
import com.ckkj.water.utils.FileNameHelper;
import com.ckkj.water.utils.show.ToastUtil;
import java.io.File;
/**
* @author messi.mo
* @date 2017/11/22
* 底部选择框
*/
public class DialogAppUpdate {
public static View layoutView;
private Dialog mDialog;
private Activity mContext;
private TextView tvTitle,tvContent,tvConfirm,tvCancel;
private RelativeLayout rlUpdateContent;
private ImageView imgClose,imgClear;
private String startTime = "";
private String endTime = "";
private DialogListener mListener;
private Animation animUp;
private Animation animDown;
private ProgressBar progressBar;
private String mDwonLoadUrl = "";
// private String mDwonLoadUrl = "https://jsjk-private.oss-cn-hangzhou.aliyuncs.com/invoice/2024-11-26/3a9c5e76b4bb4ae297a219a663e9e82a.png";
private DownloadManager downloadManager;
private long downloadId;
private NotificationManager notificationManager;
private NotificationCompat.Builder notificationBuilder;
private final String CHANNEL_ID = "download_channel"; // 通知渠道ID
private boolean mIsForceUpdate;
private CheckVersionEntity mVersionBean;
public void setOnDialogListener(DialogListener listener){
this.mListener = listener;
}
public interface DialogListener{
void callBackGetPermisson(String permission);
void downLoadFinish();
}
public DialogAppUpdate(Activity context, int layoutId, boolean isForceUpdate, CheckVersionEntity bean) {
this.mContext = context;
this.mIsForceUpdate = isForceUpdate;
this.mVersionBean = bean;
mDwonLoadUrl = bean.getVersionUrl();
mDialog = new Dialog(context, R.style.ActionSheetDialogStyle);
//填充对话框的布局
layoutView = LayoutInflater.from(context).inflate(layoutId, null);
//将布局设置给Dialog
mDialog.setContentView(layoutView);
// 为弹出和关闭设置动画
animUp = AnimationUtils.loadAnimation(mContext, R.anim.popup_anim_up);
animDown = AnimationUtils.loadAnimation(mContext, R.anim.popup_anim_down);
try {
//设置滑出动画
// layoutView.startAnimation(animUp);
} catch (Exception e) {
e.printStackTrace();
}
//获取当前Activity所在的窗体
Window dialogWindow = mDialog.getWindow();
mDialog.setOnKeyListener((dialog1, keyCode, event) -> {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
// 如果需要拦截返回键,返回 true
return true;
}
return false; // 不拦截其他按键
});
mDialog.setCanceledOnTouchOutside(false);
//设置Dialog从窗体底部弹出
if (dialogWindow != null) {
dialogWindow.setGravity(Gravity.CENTER_VERTICAL);
//获得窗体的属性
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
lp.width = context.getWindowManager().getDefaultDisplay().getWidth();
//设置Dialog距离底部的距离
//lp.y = 30;
// 将属性设置给窗体
dialogWindow.setAttributes(lp);
}
tvTitle = layoutView.findViewById(R.id.tv_title);
tvContent = layoutView.findViewById(R.id.tv_update_content);
tvConfirm = layoutView.findViewById(R.id.tv_update);
tvCancel = layoutView.findViewById(R.id.tv_cencel);
progressBar = layoutView.findViewById(R.id.progress_bar);
rlUpdateContent = layoutView.findViewById(R.id.rel_file_content);
tvConfirm.setOnClickListener(onclick);
tvCancel.setOnClickListener(onclick);
if(isForceUpdate){
tvCancel.setVisibility(View.GONE);
}
// 初始化 DownloadManager
downloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
tvContent.setText(Html.fromHtml(bean.getVersionDescription(), Html.FROM_HTML_MODE_LEGACY));
} else {
}
String [] desStr = bean.getVersionDescription().split("#");
String desLine = "";
for(String str : desStr){
desLine = desLine + str + "\n";
}
tvContent.setText(desLine);
tvContent.setLineSpacing(0, 1.2f);
}
private DownloadRequest request;
View.OnClickListener onclick = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.tv_update:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
if(mListener != null){
mListener.callBackGetPermisson(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
return;
}
}
startUpdateApp();
break;
case R.id.tv_cencel:
dismiss();
AppConfig.USER_CONFIRM_UPDATE_APP = true;
break;
}
}
};
public void startUpdateApp() {
//强制更新不需要隐藏dialog
if(mIsForceUpdate){
progressBar.setVisibility(View.VISIBLE);
rlUpdateContent.setVisibility(View.GONE);
progressBar.setMax(100);
}else{
ToastUtil.showShort(mContext,"可在任务栏查看下载进度");
dismiss();
}
String fileName = FileNameHelper.getFileNameFromUrl(mDwonLoadUrl);
File downloadDir = Environment.getExternalStorageDirectory();
File apkFile = new File(downloadDir, fileName);
String apkPath = apkFile.getAbsolutePath();
DownLoadApk downloadTask = new DownLoadApk(mContext,mIsForceUpdate);
downloadTask.startDownload(mDwonLoadUrl, fileName,apkPath);
downloadTask.setDownLoadCallback(new DownLoadApk.DownLoadCallback() {
@Override
public void updateProgress(long currentProgress, long total) {
int progress = (int) ((currentProgress * 100) / total);
progressBar.setProgress(progress);
mContext.runOnUiThread(new Runnable() {
@Override
public void run() {
tvTitle.setText("正在下载 " + progress + "%");
}
});
}
@Override
public void downLoadFinish() {
if(mListener != null){
mListener.downLoadFinish();
}
}
});
}
public void show() {
if(mDialog != null){
mDialog.show();
}
}
public void dismiss() {
if(mDialog != null){
mDialog.dismiss();
}
}
}

View File

@@ -0,0 +1,115 @@
package com.ckkj.water.dialog;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.view.WindowManager;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.TextView;
import com.ckkj.water.R;
import java.util.Objects;
/**
* author:
* time: 2019/9/18 9:34
* desc:
* version: 1.0.0
*/
public class LoadingDialog extends Dialog {
private String string="";
private TextView textView;
private Context context;
private String [] strLoadContent = {"加载中.","加载中..","加载中..."};
private int mIndex = 0;
private TextView tvLoading;
private Handler handler = new Handler();
// 创建一个Runnable对象用于定时执行任务
Runnable runnable = new Runnable() {
@Override
public void run() {
// 在这里编写需要定时执行的操作
// 比如更新UI、发送网络请求等
if(tvLoading != null){
tvLoading.setText(strLoadContent[mIndex]);
mIndex ++;
if(mIndex == strLoadContent.length){
mIndex = 0;
}
}
handler.postDelayed(this, 300);
}
};
public LoadingDialog(Context context) {
super(context); // 应用透明背景样式
this.context=context;
}
public LoadingDialog(Context context, String s) {
super(context);
this.string=s;
this.context=context;
}
public LoadingDialog(Context context, int theme) {
super(context, theme);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
}
@SuppressLint("ResourceAsColor")
private void init() {
// 设置对话框背景为透明
getWindow().setBackgroundDrawable(context.getResources().getDrawable(R.color.translucent_black_95));
getWindow().setDimAmount(0.2f);
setCancelable(true);
setCanceledOnTouchOutside(false);
setContentView(R.layout.dialog_loading_my);//loading的xml文件
tvLoading = findViewById(R.id.tv_load_dialog);
ImageView imgLoading = findViewById(R.id.img_loading);
// 初始化 ObjectAnimator
ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(imgLoading, "rotation", 0f, 360f);
rotateAnimator.setDuration(1500);
rotateAnimator.setRepeatCount(ValueAnimator.INFINITE);
rotateAnimator.setInterpolator(new LinearInterpolator()); // 匀速旋转
rotateAnimator.start();
//加载动画资源
// Drawable animation = (AnimationDrawable) imgLoading.getDrawable();
// ((AnimationDrawable) animation).start();
WindowManager.LayoutParams params = Objects.requireNonNull(getWindow()).getAttributes();
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.MATCH_PARENT;
getWindow().setAttributes(params);
// 可选: 设置窗口大小
getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
}
@Override
public void show() {//开启
// if (context==null){
// return;
// }
super.show();
}
@Override
public void dismiss() {//关闭
// if (context==null){
// return;
// }
super.dismiss();
}
}

View File

@@ -0,0 +1,141 @@
package com.ckkj.water.dialog;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.ckkj.water.R;
/**
* @author messi.mo
* @date 2017/11/22
* 底部选择框
*/
public class PayTypeDialog {
public static View layoutView;
private Dialog mDialog;
private Context mContext;
private ImageView imgClose,imgClear;
private DialogListener mListener;
private Animation animUp;
private Animation animDown;
private RelativeLayout rlAliPay,rlWxPay;
private TextView tvPay;
private RadioButton mRdBtnAlipay,mRdBtnWxpay;
private int mPayCode = 100;//100支付宝 200微信
public void setOnDialogListener(DialogListener listener){
this.mListener = listener;
}
public interface DialogListener{
void goToPay(int payCode);
}
public PayTypeDialog(Activity context, String payInfo, String payPriceInfo) {
this.mContext = context;
mDialog = new Dialog(context, R.style.ActionSheetDialogStyle);
//填充对话框的布局
layoutView = LayoutInflater.from(context).inflate(R.layout.dialog_pay_option_layout, null);
//将布局设置给Dialog
mDialog.setContentView(layoutView);
// 为弹出和关闭设置动画
animUp = AnimationUtils.loadAnimation(mContext, R.anim.popup_anim_up);
animDown = AnimationUtils.loadAnimation(mContext, R.anim.popup_anim_down);
try {
//设置滑出动画
layoutView.startAnimation(animUp);
} catch (Exception e) {
e.printStackTrace();
}
//获取当前Activity所在的窗体
Window dialogWindow = mDialog.getWindow();
mDialog.setCanceledOnTouchOutside(true);
//设置Dialog从窗体底部弹出
if (dialogWindow != null) {
dialogWindow.setGravity(Gravity.BOTTOM);
//获得窗体的属性
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
lp.width = context.getWindowManager().getDefaultDisplay().getWidth();
//设置Dialog距离底部的距离
//lp.y = 30;
// 将属性设置给窗体
dialogWindow.setAttributes(lp);
}
imgClose = layoutView.findViewById(R.id.img_close);
rlAliPay = layoutView.findViewById(R.id.rl_zfb);
rlWxPay = layoutView.findViewById(R.id.rl_wx);
tvPay = layoutView.findViewById(R.id.tv_go_pay);
mRdBtnAlipay = layoutView.findViewById(R.id.radio_zdb);
mRdBtnWxpay = layoutView.findViewById(R.id.radio_wx);
TextView tvPayInfo = layoutView.findViewById(R.id.tv_pay_info);
TextView tvPayPriceInfo = layoutView.findViewById(R.id.tv_pay_price);
imgClose.setOnClickListener(onclick);
tvPay.setOnClickListener(onclick);
rlAliPay.setOnClickListener(onclick);
rlWxPay.setOnClickListener(onclick);
tvPayInfo.setText("支付账单信息:" + payInfo);
tvPayPriceInfo.setText("实付金额: ¥" + payPriceInfo);
}
View.OnClickListener onclick = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.img_close:
mDialog.dismiss();
break;
case R.id.rl_zfb:
mPayCode = 100;
mRdBtnAlipay.setChecked(true);
mRdBtnWxpay.setChecked(false);
break;
case R.id.rl_wx:
mPayCode = 200;
mRdBtnAlipay.setChecked(false);
mRdBtnWxpay.setChecked(true);
break;
case R.id.tv_go_pay:
if(mListener != null){
mListener.goToPay(mPayCode);
dismiss();
}
break;
}
}
};
public void show() {
if(mDialog != null){
mDialog.show();
}
}
public void dismiss() {
if(mDialog != null){
mDialog.dismiss();
}
}
}

View File

@@ -0,0 +1,197 @@
package com.ckkj.water.dialog;
import android.app.Activity;
import android.app.Dialog;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.google.zxing.client.android.utils.ZXingUtils;
import com.ckkj.water.AppConfig;
import com.ckkj.water.R;
import com.ckkj.water.utils.show.ToastUtil;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
/**
* @author messi.mo
* @date 2017/11/22
* 底部选择框
*/
public class ShareQrcodeDialog {
public static View layoutView;
private Dialog mDialog;
private Context mContext;
private TextView tvOneMonth,tvThreeMonth,tvSixMonth,tvStartTime,tvEndTime,tvClear,tvConfirm;
private ImageView imgDown,imgCopy,imgHb,imgQrcode;
private String startTime = "";
private RelativeLayout rlHaibao;
private String endTime = "";
private DialogListener mListener;
private Animation animUp;
private Animation animDown;
private List<Drawable> mImgUrls = new ArrayList<>();
private String mInviteeCode = "";
public void setOnDialogListener(DialogListener listener){
this.mListener = listener;
}
public interface DialogListener{
void downShape();
void copyLink(String url);
}
public ShareQrcodeDialog(Activity context, int layoutId,String shareCode) {
this.mContext = context;
this.mInviteeCode = shareCode;
mDialog = new Dialog(context, R.style.ActionShareDialogStyle);
//填充对话框的布局
layoutView = LayoutInflater.from(context).inflate(layoutId, null);
//将布局设置给Dialog
mDialog.setContentView(layoutView);
// 为弹出和关闭设置动画
animUp = AnimationUtils.loadAnimation(mContext, R.anim.popup_anim_up);
animDown = AnimationUtils.loadAnimation(mContext, R.anim.popup_anim_down);
try {
//设置滑出动画
layoutView.startAnimation(animUp);
} catch (Exception e) {
e.printStackTrace();
}
//获取当前Activity所在的窗体
Window dialogWindow = mDialog.getWindow();
mDialog.setCanceledOnTouchOutside(true);
//设置Dialog在屏幕中间显示
if (dialogWindow != null) {
dialogWindow.setGravity(Gravity.CENTER);
//获得窗体的属性
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
// 设置Dialog宽度为屏幕宽度的85%(可根据需要调整)
int screenWidth = context.getWindowManager().getDefaultDisplay().getWidth();
lp.width = (int) (screenWidth * 0.85);
int screenHeight = context.getWindowManager().getDefaultDisplay().getHeight();
lp.height = (int) (screenHeight * 0.85);
//将属性设置给窗体
dialogWindow.setAttributes(lp);
}
//添加图片集合
mImgUrls.add(mContext.getResources().getDrawable(R.mipmap.img_share_bg));
imgDown = layoutView.findViewById(R.id.img_down);
imgCopy = layoutView.findViewById(R.id.img_copy);
imgHb = layoutView.findViewById(R.id.img_haibao);
imgQrcode = layoutView.findViewById(R.id.img_qr_code);
rlHaibao = layoutView.findViewById(R.id.relative_hb);
imgDown.setOnClickListener(onclick);
imgCopy.setOnClickListener(onclick);
authUrlToQrcode(shareCode);
}
View.OnClickListener onclick = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.img_down:
saveLayoutAsImage();
break;
case R.id.img_copy:
ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("label", AppConfig.USER_SHARE_URL + mInviteeCode);
clipboard.setPrimaryClip(clip);
ToastUtil.showShort(mContext,"已复制邀请链接");
mDialog.dismiss();
break;
}
}
};
/**
* 保存名片的 bitmap 到手机相册中
*/
private void saveLayoutAsImage() {
// 1. 创建 Bitmap
Bitmap bitmap = Bitmap.createBitmap(rlHaibao.getWidth(), rlHaibao.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
rlHaibao.draw(canvas);
// 2. 保存到 MediaStoreAndroid 10+ 适用)
String filename = "layout_" + System.currentTimeMillis() + ".png";
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, filename);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/MyLayouts");
ContentResolver resolver = mContext.getContentResolver();
Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
if (uri != null) {
try (OutputStream out = resolver.openOutputStream(uri)) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
ToastUtil.showShort(mContext,"保存成功");
mDialog.dismiss();
} catch (IOException e) {
e.printStackTrace();
ToastUtil.showShort(mContext,"保存失败:" + e.getMessage());
mDialog.dismiss();
}
}
}
/**
* url转为二维码显示
* @param data
*/
private void authUrlToQrcode(String data) {
try {
Bitmap qrImage = ZXingUtils.createQRCodeImage(AppConfig.USER_SHARE_URL + data);
imgQrcode.setImageBitmap(qrImage);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void show() {
if(mDialog != null){
mDialog.show();
}
}
public void dismiss() {
if(mDialog != null){
mDialog.dismiss();
}
}
}

View File

@@ -0,0 +1,52 @@
package com.ckkj.water.fate.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.fate.entity.FateHistoryEntity;
import com.ckkj.water.utils.color.FateDataUtil;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2025/7/24
* @description TODO: 描述该类的作用
*/
public class FateHistoryAdapter extends BaseQuickAdapter<FateHistoryEntity.HistoryList, BaseViewHolder> {
private Context mContext;
public FateHistoryAdapter(Context context,int layoutResId, @Nullable List<FateHistoryEntity.HistoryList> data) {
super(layoutResId, data);
this.mContext = context;
}
@Override
protected void convert(BaseViewHolder holder, FateHistoryEntity.HistoryList item) {
holder.setText(R.id.tv_date,item.getRecordDate());
holder.setText(R.id.tv_week,item.getDayOfWeek());
if(item.isToday()){
holder.setVisible(R.id.tv_today,true);
}else{
holder.setVisible(R.id.tv_today,false);
}
holder.setText(R.id.tv_name,item.getName());
holder.setText(R.id.tv_location,item.getCurrentPlace());
holder.setText(R.id.tv_weather,item.getWeatherCondition());
holder.setText(R.id.tv_star,item.getConstellation());
holder.setText(R.id.tv_score,item.getOverallScore() + "");
holder.setText(R.id.tv_syy_score,item.getCareerScore() + "");
holder.setText(R.id.tv_gqy_score,item.getLoveScore() + "");
holder.setText(R.id.tv_jky_score,item.getHealthScore() + "");
holder.setText(R.id.tv_cfy_score,item.getWealthScore() + "");
holder.setTextColor(R.id.tv_score, FateDataUtil.getScoreColor(item.getOverallScore()));
holder.setTextColor(R.id.tv_syy_score, FateDataUtil.getScoreColor(item.getCareerScore()));
holder.setTextColor(R.id.tv_gqy_score, FateDataUtil.getScoreColor(item.getLoveScore()));
holder.setTextColor(R.id.tv_jky_score, FateDataUtil.getScoreColor(item.getHealthScore()));
holder.setTextColor(R.id.tv_cfy_score, FateDataUtil.getScoreColor(item.getWealthScore()));
}
}

View File

@@ -0,0 +1,50 @@
package com.ckkj.water.fate.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.fate.entity.CityDataEntity;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2025/7/18
* @description TODO: 描述该类的作用
*/
public class SelectCityAdapter extends BaseQuickAdapter<CityDataEntity, BaseViewHolder> {
private Context mContext;
private int mSelPos = -1;
public SelectCityAdapter(Context context,int layoutResId, @Nullable List<CityDataEntity> data) {
super(layoutResId, data);
this.mContext = context;
}
@Override
protected void convert(BaseViewHolder helper, CityDataEntity item) {
helper.setText(R.id.tv_city_name,item.getCityName());
if(mSelPos == helper.getLayoutPosition()){
helper.setVisible(R.id.img_select,true);
}else{
helper.setVisible(R.id.img_select,false);
}
}
public void setSelPos(int pos){
this.mSelPos = pos;
notifyDataSetChanged();
}
public int getmSelPos() {
return mSelPos;
}
public void setmSelPos(int mSelPos) {
this.mSelPos = mSelPos;
}
}

View File

@@ -0,0 +1,203 @@
package com.ckkj.water.fate.entity;
import java.io.Serializable;
/**
* @author fengxiaoyang
* @date 2025/7/18
* @description TODO: 描述该类的作用
*/
public class CityDataEntity implements Serializable {
private int id;
private String cityCode;
private String cityName;
private String cityNameEn;
private String provinceCode;
private String provinceName;
private int cityLevel;
private String cityType;
private double longitude;
private double latitude;
private String population;
private String area;
private String gdp;
private String zipCode;
private String phoneCode;
private int isCapital;
private int isActive;
private int sortOrder;
private String remark;
private String createdTime;
private String updatedTime;
private String capitalCity;
public String getCapitalCity() {
return capitalCity;
}
public void setCapitalCity(String capitalCity) {
this.capitalCity = capitalCity;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCityCode() {
return cityCode;
}
public void setCityCode(String cityCode) {
this.cityCode = cityCode;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public String getCityNameEn() {
return cityNameEn;
}
public void setCityNameEn(String cityNameEn) {
this.cityNameEn = cityNameEn;
}
public String getProvinceCode() {
return provinceCode;
}
public void setProvinceCode(String provinceCode) {
this.provinceCode = provinceCode;
}
public String getProvinceName() {
return provinceName;
}
public void setProvinceName(String provinceName) {
this.provinceName = provinceName;
}
public int getCityLevel() {
return cityLevel;
}
public void setCityLevel(int cityLevel) {
this.cityLevel = cityLevel;
}
public String getCityType() {
return cityType;
}
public void setCityType(String cityType) {
this.cityType = cityType;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public String getPopulation() {
return population;
}
public void setPopulation(String population) {
this.population = population;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
public String getGdp() {
return gdp;
}
public void setGdp(String gdp) {
this.gdp = gdp;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
public String getPhoneCode() {
return phoneCode;
}
public void setPhoneCode(String phoneCode) {
this.phoneCode = phoneCode;
}
public int getIsCapital() {
return isCapital;
}
public void setIsCapital(int isCapital) {
this.isCapital = isCapital;
}
public int getIsActive() {
return isActive;
}
public void setIsActive(int isActive) {
this.isActive = isActive;
}
public int getSortOrder() {
return sortOrder;
}
public void setSortOrder(int sortOrder) {
this.sortOrder = sortOrder;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public void setCreatedTime(String createdTime) {
this.createdTime = createdTime;
}
public void setUpdatedTime(String updatedTime) {
this.updatedTime = updatedTime;
}
}

View File

@@ -0,0 +1,139 @@
package com.ckkj.water.fate.entity;
import java.io.Serializable;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2025/7/25
* @description TODO: 描述该类的作用
*/
public class FateHistoryEntity {
private List<HistoryList> list;
private int total;
public void setList(List<HistoryList> list) {
this.list = list;
}
public List<HistoryList> getList() {
return list;
}
public void setTotal(int total) {
this.total = total;
}
public int getTotal() {
return total;
}
public static class HistoryList implements Serializable{
private String recordDate;
private String dayOfWeek;
private String name;
private String currentPlace;
private String weatherCondition;
private String constellation;
private int overallScore;
private int careerScore;
private int loveScore;
private int healthScore;
private int wealthScore;
private boolean isToday;
public String getRecordDate() {
return recordDate;
}
public void setRecordDate(String recordDate) {
this.recordDate = recordDate;
}
public String getDayOfWeek() {
return dayOfWeek;
}
public void setDayOfWeek(String dayOfWeek) {
this.dayOfWeek = dayOfWeek;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCurrentPlace() {
return currentPlace;
}
public void setCurrentPlace(String currentPlace) {
this.currentPlace = currentPlace;
}
public String getWeatherCondition() {
return weatherCondition;
}
public void setWeatherCondition(String weatherCondition) {
this.weatherCondition = weatherCondition;
}
public String getConstellation() {
return constellation;
}
public void setConstellation(String constellation) {
this.constellation = constellation;
}
public int getOverallScore() {
return overallScore;
}
public void setOverallScore(int overallScore) {
this.overallScore = overallScore;
}
public int getCareerScore() {
return careerScore;
}
public void setCareerScore(int careerScore) {
this.careerScore = careerScore;
}
public int getLoveScore() {
return loveScore;
}
public void setLoveScore(int loveScore) {
this.loveScore = loveScore;
}
public int getHealthScore() {
return healthScore;
}
public void setHealthScore(int healthScore) {
this.healthScore = healthScore;
}
public int getWealthScore() {
return wealthScore;
}
public void setWealthScore(int wealthScore) {
this.wealthScore = wealthScore;
}
public boolean isToday() {
return isToday;
}
public void setToday(boolean today) {
isToday = today;
}
}
}

View File

@@ -0,0 +1,66 @@
package com.ckkj.water.fate.entity;
import java.io.Serializable;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2025/7/16
* @description TODO: 描述该类的作用
*/
public class LunarYearEntity implements Serializable {
public String year; // 年份
public List<LunarMonth> month; // 月份列表
// Gson需要无参构造
public LunarYearEntity() {}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public List<LunarMonth> getMonth() {
return month;
}
public void setMonth(List<LunarMonth> month) {
this.month = month;
}
public static class LunarMonth implements Serializable{
public String name; // 月份数字(字符串形式)
public int isRun; // 是否闰月0=否1=是)
public int isAllDay; // 是否包含三十0=29天1=30天
// Gson需要无参构造
public LunarMonth() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIsRun() {
return isRun;
}
public void setIsRun(int isRun) {
this.isRun = isRun;
}
public int getIsAllDay() {
return isAllDay;
}
public void setIsAllDay(int isAllDay) {
this.isAllDay = isAllDay;
}
}
}

View File

@@ -0,0 +1,526 @@
package com.ckkj.water.fate.entity;
import com.ckkj.water.base.entity.UserInfoEntity;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2025/7/21
* @description TODO: 描述该类的作用
*/
public class TodayFateEntity implements Serializable {
private FortuneAnalysis fortuneAnalysis;
private UserInfoEntity userInfo;
private TodayInfo todayInfo;
private String weatherCondition;
private String weatherTemperature;
private int todayVisitCount;
private int totalVisitDays;
public void setFortuneAnalysis(FortuneAnalysis fortuneAnalysis) {
this.fortuneAnalysis = fortuneAnalysis;
}
public FortuneAnalysis getFortuneAnalysis() {
return fortuneAnalysis;
}
public void setUserInfo(UserInfoEntity userInfo) {
this.userInfo = userInfo;
}
public UserInfoEntity getUserInfo() {
return userInfo;
}
public void setTodayInfo(TodayInfo todayInfo) {
this.todayInfo = todayInfo;
}
public TodayInfo getTodayInfo() {
return todayInfo;
}
public void setWeatherCondition(String weatherCondition) {
this.weatherCondition = weatherCondition;
}
public String getWeatherCondition() {
return weatherCondition;
}
public void setWeatherTemperature(String weatherTemperature) {
this.weatherTemperature = weatherTemperature;
}
public String getWeatherTemperature() {
return weatherTemperature;
}
public void setTodayVisitCount(int todayVisitCount) {
this.todayVisitCount = todayVisitCount;
}
public int getTodayVisitCount() {
return todayVisitCount;
}
public void setTotalVisitDays(int totalVisitDays) {
this.totalVisitDays = totalVisitDays;
}
public int getTotalVisitDays() {
return totalVisitDays;
}
/**
* Copyright 2025 bejson.com
*/
/**
* Auto-generated: 2025-07-21 17:23:17
*
* @author bejson.com (i@bejson.com)
* @website http://www.bejson.com/java2pojo/
*/
public static class TodayInfo implements Serializable{
private Date date;
private String weekDay;
private int year;
private int month;
private int day;
public void setDate(Date date) {
this.date = date;
}
public Date getDate() {
return date;
}
public void setWeekDay(String weekDay) {
this.weekDay = weekDay;
}
public String getWeekDay() {
return weekDay;
}
public void setYear(int year) {
this.year = year;
}
public int getYear() {
return year;
}
public void setMonth(int month) {
this.month = month;
}
public int getMonth() {
return month;
}
public void setDay(int day) {
this.day = day;
}
public int getDay() {
return day;
}
}
/**
* Copyright 2025 bejson.com
*/
/**
* Auto-generated: 2025-07-21 17:23:17
*
* @author bejson.com (i@bejson.com)
* @website http://www.bejson.com/java2pojo/
*/
public static class FortuneAnalysis implements Serializable{
private int overallScore;
private String overallDescription;
private String destiny;
private String todayGanzhi;
private BaziAnalysis baziAnalysis;
private Weather weather;
private AstrologyInfluence astrologyInfluence;
private LuckyInfo luckyInfo;
private int careerScore;
private String careerDescription;
private int loveScore;
private String loveDescription;
private int healthScore;
private String healthDescription;
private int wealthScore;
private String wealthDescription;
private Suggestions suggestions;
private String fiveElementsAnalysis;
public void setOverallScore(int overallScore) {
this.overallScore = overallScore;
}
public int getOverallScore() {
return overallScore;
}
public void setOverallDescription(String overallDescription) {
this.overallDescription = overallDescription;
}
public String getOverallDescription() {
return overallDescription;
}
public void setDestiny(String destiny) {
this.destiny = destiny;
}
public String getDestiny() {
return destiny;
}
public void setTodayGanzhi(String todayGanzhi) {
this.todayGanzhi = todayGanzhi;
}
public String getTodayGanzhi() {
return todayGanzhi;
}
public void setBaziAnalysis(BaziAnalysis baziAnalysis) {
this.baziAnalysis = baziAnalysis;
}
public BaziAnalysis getBaziAnalysis() {
return baziAnalysis;
}
public void setWeather(Weather weather) {
this.weather = weather;
}
public Weather getWeather() {
return weather;
}
public void setAstrologyInfluence(AstrologyInfluence astrologyInfluence) {
this.astrologyInfluence = astrologyInfluence;
}
public AstrologyInfluence getAstrologyInfluence() {
return astrologyInfluence;
}
public void setLuckyInfo(LuckyInfo luckyInfo) {
this.luckyInfo = luckyInfo;
}
public LuckyInfo getLuckyInfo() {
return luckyInfo;
}
public void setCareerScore(int careerScore) {
this.careerScore = careerScore;
}
public int getCareerScore() {
return careerScore;
}
public void setCareerDescription(String careerDescription) {
this.careerDescription = careerDescription;
}
public String getCareerDescription() {
return careerDescription;
}
public void setLoveScore(int loveScore) {
this.loveScore = loveScore;
}
public int getLoveScore() {
return loveScore;
}
public void setLoveDescription(String loveDescription) {
this.loveDescription = loveDescription;
}
public String getLoveDescription() {
return loveDescription;
}
public void setHealthScore(int healthScore) {
this.healthScore = healthScore;
}
public int getHealthScore() {
return healthScore;
}
public void setHealthDescription(String healthDescription) {
this.healthDescription = healthDescription;
}
public String getHealthDescription() {
return healthDescription;
}
public void setWealthScore(int wealthScore) {
this.wealthScore = wealthScore;
}
public int getWealthScore() {
return wealthScore;
}
public void setWealthDescription(String wealthDescription) {
this.wealthDescription = wealthDescription;
}
public String getWealthDescription() {
return wealthDescription;
}
public void setSuggestions(Suggestions suggestions) {
this.suggestions = suggestions;
}
public Suggestions getSuggestions() {
return suggestions;
}
public void setFiveElementsAnalysis(String fiveElementsAnalysis) {
this.fiveElementsAnalysis = fiveElementsAnalysis;
}
public String getFiveElementsAnalysis() {
return fiveElementsAnalysis;
}
}
/**
* Copyright 2025 bejson.com
*/
/**
* Auto-generated: 2025-07-21 17:23:17
*
* @author bejson.com (i@bejson.com)
* @website http://www.bejson.com/java2pojo/
*/
public static class Suggestions implements Serializable{
private String positive;
private String negative;
public void setPositive(String positive) {
this.positive = positive;
}
public String getPositive() {
return positive;
}
public void setNegative(String negative) {
this.negative = negative;
}
public String getNegative() {
return negative;
}
}
/**
* Copyright 2025 bejson.com
*/
/**
* Auto-generated: 2025-07-21 17:23:17
*
* @author bejson.com (i@bejson.com)
* @website http://www.bejson.com/java2pojo/
*/
public static class LuckyInfo implements Serializable{
private String[] numbers;
private String color;
private String direction;
private List<LuckyTimes> luckyTimes;
private String flower;
private String food;
public String[] getNumbers() {
return numbers;
}
public void setNumbers(String[] numbers) {
this.numbers = numbers;
}
public void setColor(String color) {
this.color = color;
}
public String getColor() {
return color;
}
public void setDirection(String direction) {
this.direction = direction;
}
public String getDirection() {
return direction;
}
public void setLuckyTimes(List<LuckyTimes> luckyTimes) {
this.luckyTimes = luckyTimes;
}
public List<LuckyTimes> getLuckyTimes() {
return luckyTimes;
}
public void setFlower(String flower) {
this.flower = flower;
}
public String getFlower() {
return flower;
}
public void setFood(String food) {
this.food = food;
}
public String getFood() {
return food;
}
}
/**
* Copyright 2025 bejson.com
*/
/**
* Auto-generated: 2025-07-21 17:23:17
*
* @author bejson.com (i@bejson.com)
* @website http://www.bejson.com/java2pojo/
*/
public static class LuckyTimes implements Serializable{
private String time;
private String description;
public void setTime(String time) {
this.time = time;
}
public String getTime() {
return time;
}
public void setDescription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
/**
* Copyright 2025 bejson.com
*/
/**
* Auto-generated: 2025-07-21 17:23:17
*
* @author bejson.com (i@bejson.com)
* @website http://www.bejson.com/java2pojo/
*/
public static class AstrologyInfluence implements Serializable{
private String constellation;
private String value;
private String description;
public void setConstellation(String constellation) {
this.constellation = constellation;
}
public String getConstellation() {
return constellation;
}
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setDescription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
/**
* Copyright 2025 bejson.com
*/
/**
* Auto-generated: 2025-07-21 17:23:17
*
* @author bejson.com (i@bejson.com)
* @website http://www.bejson.com/java2pojo/
*/
public static class Weather implements Serializable{
private String condition;
private String temperature;
public void setCondition(String condition) {
this.condition = condition;
}
public String getCondition() {
return condition;
}
public void setTemperature(String temperature) {
this.temperature = temperature;
}
public String getTemperature() {
return temperature;
}
}
/**
* Copyright 2025 bejson.com
*/
/**
* Auto-generated: 2025-07-21 17:23:17
*
* @author bejson.com (i@bejson.com)
* @website http://www.bejson.com/java2pojo/
*/
public static class BaziAnalysis implements Serializable{
private String nianzhu;
private String yuezhu;
private String rizhu;
private String shizhu;
private String todayInfluence;
public void setNianzhu(String nianzhu) {
this.nianzhu = nianzhu;
}
public String getNianzhu() {
return nianzhu;
}
public void setYuezhu(String yuezhu) {
this.yuezhu = yuezhu;
}
public String getYuezhu() {
return yuezhu;
}
public void setRizhu(String rizhu) {
this.rizhu = rizhu;
}
public String getRizhu() {
return rizhu;
}
public void setShizhu(String shizhu) {
this.shizhu = shizhu;
}
public String getShizhu() {
return shizhu;
}
public void setTodayInfluence(String todayInfluence) {
this.todayInfluence = todayInfluence;
}
public String getTodayInfluence() {
return todayInfluence;
}
}
}

View File

@@ -0,0 +1,56 @@
package com.ckkj.water.fate.mvp;
import com.ckkj.water.base.IView;
import com.ckkj.water.base.entity.MineUserInfoBean;
import com.ckkj.water.fate.entity.CityDataEntity;
import com.ckkj.water.fate.entity.FateHistoryEntity;
import com.ckkj.water.fate.entity.TodayFateEntity;
import com.ckkj.water.network.BaseBean;
import org.json.JSONObject;
import java.util.List;
import java.util.Map;
/**
* @author fengxiaoyang
* @date 2025/7/15
* @description TODO: 描述该类的作用
*/
public class FateContract {
public interface CallBack<T> {
void success(T msg);
void fail(String msg);
}
public interface DataModel{
//查询所有城市
void getAllCityDatas(Map<String,Object> map, CallBack callBack);
//保存用户生日信息
void saveUserBirthInfo(JSONObject json, CallBack callBack);
//用户修改生日信息
void saveUserEditBirthInfo(JSONObject json, CallBack callBack);
//查询用户今日运势
void getUserTodayFateDatas(Map<String,Object> map, CallBack callBack);
//查询历史运势
void getUserFateHistory(Map<String,Object> map, CallBack callBack);
}
public interface FateView extends IView{
//查询所有城市成功
void getAllCitySuccess(List<CityDataEntity> list);
//获取今日运势成功
void getUserTodayFateDataSuccess(TodayFateEntity entity);
//获取历史运势成功
void getFateHistorySuccess(FateHistoryEntity entity);
//用户保存生辰八字成功
void userSaveBirthInfoSuccess(TodayFateEntity bean);
//用户信息
void getUserInfoSuccess(MineUserInfoBean bean);
//提交举报反馈成功
void commitReportSuccess(BaseBean bean);
}
}

View File

@@ -0,0 +1,232 @@
package com.ckkj.water.fate.mvp;
import com.ckkj.water.fate.entity.CityDataEntity;
import com.ckkj.water.fate.entity.FateHistoryEntity;
import com.ckkj.water.fate.entity.TodayFateEntity;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.network.NetWorkManager;
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;
/**
* @author fengxiaoyang
* @date 2025/7/15
* @description TODO: 描述该类的作用
*/
public class FateImpl implements FateContract.DataModel{
/**
* 所有城市
* @param map
* @param callBack
*/
@Override
public void getAllCityDatas(Map<String, Object> map, FateContract.CallBack callBack) {
try {
NetWorkManager.getRequest().getCityDatas(NetWorkManager.getToken(),map)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<List<CityDataEntity>>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<List<CityDataEntity>> 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) {
throw new RuntimeException(e);
}
}
/**
* 保存用户生辰信息
* @param json
* @param callBack
*/
@Override
public void saveUserBirthInfo(JSONObject json, FateContract.CallBack callBack) {
try {
NetWorkManager.getRequest().saveUserBirthInfo(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 saveUserEditBirthInfo(JSONObject json, FateContract.CallBack callBack) {
try {
NetWorkManager.getRequest().saveUserEditBirthInfo(NetWorkManager.getToken(),NetWorkManager.toRequestBody(json))
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<TodayFateEntity>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<TodayFateEntity> 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();
}
}
/**
* 获取今日运势
* @param map
* @param callBack
*/
@Override
public void getUserTodayFateDatas(Map<String, Object> map, FateContract.CallBack callBack) {
try {
NetWorkManager.getRequest().getUserTodayFateDatas(NetWorkManager.getToken())
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<TodayFateEntity>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<TodayFateEntity> 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();
}
}
/**
* 获取历史数据
* @param map
* @param callBack
*/
@Override
public void getUserFateHistory(Map<String, Object> map, FateContract.CallBack callBack) {
try {
NetWorkManager.getRequest().getUserFateHistory(NetWorkManager.getToken())
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean<FateHistoryEntity>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean<FateHistoryEntity> 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

@@ -0,0 +1,191 @@
package com.ckkj.water.fate.mvp;
import com.ckkj.water.base.BasePresenter;
import com.ckkj.water.base.entity.MineUserInfoBean;
import com.ckkj.water.chat.mvp.IndexContract;
import com.ckkj.water.chat.mvp.IndexImpl;
import com.ckkj.water.fate.entity.CityDataEntity;
import com.ckkj.water.fate.entity.FateHistoryEntity;
import com.ckkj.water.fate.entity.TodayFateEntity;
import com.ckkj.water.login.mvp.LoginContract;
import com.ckkj.water.mine.mvp.MineImpl;
import com.ckkj.water.network.BaseBean;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author fengxiaoyang
* @date 2025/7/15
* @description TODO: 描述该类的作用
*/
public class FatePresenter extends BasePresenter<FateContract.FateView> {
private FateImpl impl;
public FatePresenter(FateImpl impl) {
this.impl = impl;
}
/**
* 获取城市列表
*/
public void getCityDatas() {
Map<String, Object> map = new HashMap<>();
impl.getAllCityDatas(map, new FateContract.CallBack<List<CityDataEntity>>() {
@Override
public void success(List<CityDataEntity> list) {
if(FatePresenter.this.getView() != null){
FatePresenter.this.getView().getAllCitySuccess(list);
}
}
@Override
public void fail(String msg) {
if(FatePresenter.this.getView() != null){
FatePresenter.this.getView().showError(msg);
}
}
});
}
/**
* 保存用户生辰
* @param json
*/
public void saveUserBirthInfo(JSONObject json) {
impl.saveUserBirthInfo(json, new FateContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean) {
if(FatePresenter.this.getView() != null){
FatePresenter.this.getView().userSaveBirthInfoSuccess(null);
}
}
@Override
public void fail(String msg) {
if(FatePresenter.this.getView() != null){
FatePresenter.this.getView().showError(msg);
}
}
});
}
/**
* 获取今日运势
*/
public void getTodayFateDatas() {
impl.getUserTodayFateDatas(new HashMap<>(), new FateContract.CallBack<TodayFateEntity>() {
@Override
public void success(TodayFateEntity bean) {
if(FatePresenter.this.getView() != null){
FatePresenter.this.getView().getUserTodayFateDataSuccess(bean);
}
}
@Override
public void fail(String msg) {
if(FatePresenter.this.getView() != null){
FatePresenter.this.getView().showError(msg);
}
}
});
}
/**
* 获取历史运势
* @param page
*/
public void getHistoryDatas(int page) {
Map<String, Object> map = new HashMap<>();
map.put("pageNum", page);
map.put("pageSize", 10);
impl.getUserFateHistory(map, new FateContract.CallBack<FateHistoryEntity>() {
@Override
public void success(FateHistoryEntity entity) {
if(FatePresenter.this.getView() != null){
FatePresenter.this.getView().getFateHistorySuccess(entity);
}
}
@Override
public void fail(String msg) {
if(FatePresenter.this.getView() != null){
FatePresenter.this.getView().showError(msg);
}
}
});
}
/**
* 用户修改的生辰八字保存
* @param json
*/
public void saveEditBirthInfo(JSONObject json) {
impl.saveUserEditBirthInfo(json, new FateContract.CallBack<TodayFateEntity>() {
@Override
public void success(TodayFateEntity bean) {
if(FatePresenter.this.getView() != null){
FatePresenter.this.getView().userSaveBirthInfoSuccess(bean);
}
}
@Override
public void fail(String msg) {
if(FatePresenter.this.getView() != null){
FatePresenter.this.getView().showError(msg);
}
}
});
}
/**
* 获取个人信息
*/
public void getUserInfo() {
Map<String,Object> map = new HashMap<>();
// new MineImpl().getUserInfo(map, new LoginContract.CallBack<MineUserInfoBean>() {
// @Override
// public void success(MineUserInfoBean bean) {
// if( FatePresenter.this.getView() != null){
// FatePresenter.this.getView().getUserInfoSuccess(bean);
// }
// }
//
// @Override
// public void fail(String msg) {
// if( FatePresenter.this.getView() != null){
// FatePresenter.this.getView().showError(msg);
// }
// }
// });
}
/**
* 举报
* @param reason
*/
public void commitReport(String reason) {
Map<String, Object> map = new HashMap<>();
map.put("content", reason);
new IndexImpl().commitReport(map, new IndexContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean) {
if (FatePresenter.this.getView() != null) {
FatePresenter.this.getView().commitReportSuccess(bean);
}
}
@Override
public void fail(String msg) {
if (FatePresenter.this.getView() != null) {
FatePresenter.this.getView().showError(msg);
}
}
});
}
}

View File

@@ -0,0 +1,75 @@
package com.ckkj.water.fate.util;
import android.content.Context;
import androidx.annotation.Nullable;
import org.json.JSONArray;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
public class LunarDateLoader {
// 缓存静态变量
private static JSONArray cachedLunarJsonArray = null;
/**
* 初始化缓存(异步调用,建议在 Application 中调用)
*/
public static void preloadLunarJson(final Context context) {
if (cachedLunarJsonArray != null) return; // 已加载过则跳过
new Thread(() -> {
try {
InputStream inputStream = context.getAssets().open("lunar_1899_2099.json");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
inputStream.close();
String jsonStr = outputStream.toString("UTF-8");
cachedLunarJsonArray = new JSONArray(jsonStr);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
/**
* 获取缓存的农历 JSON 数据(同步获取)
* 可在页面中直接调用
*/
@Nullable
public static JSONArray getCachedLunarJson() {
return cachedLunarJsonArray;
}
/**
* 同步加载(兜底)
*/
@Nullable
public static JSONArray loadJsonFromAssets(Context context, String fileName) {
try {
InputStream inputStream = context.getAssets().open(fileName);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
inputStream.close();
String jsonStr = outputStream.toString("UTF-8");
return new JSONArray(jsonStr);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@@ -0,0 +1,96 @@
package com.ckkj.water.fate.util;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.ckkj.water.fate.entity.LunarYearEntity;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
public class LunarDatePicker {
private List<LunarYearEntity> lunarYears; // 所有年份数据
private List<LunarYearEntity.LunarMonth> currentYearMonths; // 当前选中年的月份数据
// 月份名称映射(数字->中文)
private static final String[] MONTH_NAMES = {
"正月", "二月", "三月", "四月", "五月", "六月",
"七月", "八月", "九月", "十月", "冬月", "腊月"
};
// 日期名称列表(初一到三十)
private static final String[] DAY_NAMES = {
"初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十",
"十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
"廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"
};
public LunarDatePicker(String jsonData) {
// 解析JSON数据
parseLunarData(jsonData);
}
// 解析JSON数据
private void parseLunarData(String jsonData) {
Gson gson = new Gson();
Type type = new TypeToken<List<LunarYearEntity>>(){}.getType();
lunarYears = gson.fromJson(jsonData, type);
}
// 获取年份列表用于年的WheelView
public List<String> getYearList() {
List<String> years = new ArrayList<>();
for (LunarYearEntity year : lunarYears) {
years.add(year.getYear());
}
return years;
}
// 根据选中的年份索引获取月份列表用于月的WheelView
public List<String> getMonthList(int yearIndex) {
if (yearIndex < 0 || yearIndex >= lunarYears.size()) {
return new ArrayList<>();
}
LunarYearEntity selectedYear = lunarYears.get(yearIndex);
currentYearMonths = selectedYear.getMonth(); // 保存当前年的月份数据
List<String> monthList = new ArrayList<>();
for (LunarYearEntity.LunarMonth month : selectedYear.month) {
int monthNum = Integer.parseInt(month.name);
String monthName = MONTH_NAMES[monthNum - 1]; // 数组索引从0开始
// 处理闰月
if (month.isRun == 1) {
monthName = "" + monthName;
}
monthList.add(monthName);
}
return monthList;
}
// 根据选中的月份索引获取日期列表用于日的WheelView
public List<String> getDayList(int monthIndex) {
if (currentYearMonths == null || monthIndex < 0 || monthIndex >= currentYearMonths.size()) {
return new ArrayList<>();
}
LunarYearEntity.LunarMonth selectedMonth = currentYearMonths.get(monthIndex);
int days = selectedMonth.isAllDay == 1 ? 30 : 29; // 确定天数
List<String> dayList = new ArrayList<>();
for (int i = 0; i < days; i++) {
dayList.add(DAY_NAMES[i]);
}
return dayList;
}
// 获取选中的完整日期(年、月、日索引)
public String getSelectedDate(int yearIndex, int monthIndex, int dayIndex) {
String year = lunarYears.get(yearIndex).year + "";
String month = getMonthList(yearIndex).get(monthIndex);
String day = getDayList(monthIndex).get(dayIndex);
return year + month + day;
}
}

View File

@@ -0,0 +1,758 @@
package com.ckkj.water.fate.view;
import static android.app.Activity.RESULT_OK;
import static com.qweather.sdk.QWeather.instance;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.amap.api.services.core.AMapException;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.geocoder.GeocodeAddress;
import com.amap.api.services.geocoder.GeocodeQuery;
import com.amap.api.services.geocoder.GeocodeResult;
import com.amap.api.services.geocoder.GeocodeSearch;
import com.google.android.material.progressindicator.CircularProgressIndicator;
import com.google.android.material.progressindicator.LinearProgressIndicator;
import com.ckkj.water.AppConfig;
import com.ckkj.water.ConstantUtil;
import com.ckkj.water.EventMessage;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.base.entity.MineUserInfoBean;
import com.ckkj.water.custom.view.CustomRefreshHeader;
import com.ckkj.water.databinding.FateLayoutBinding;
import com.ckkj.water.dialog.ContentReportDialog;
import com.ckkj.water.fate.entity.CityDataEntity;
import com.ckkj.water.fate.entity.FateHistoryEntity;
import com.ckkj.water.fate.entity.TodayFateEntity;
import com.ckkj.water.fate.mvp.FateContract;
import com.ckkj.water.fate.mvp.FateImpl;
import com.ckkj.water.fate.mvp.FatePresenter;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.utils.WeatherIconUtil;
import com.ckkj.water.utils.click.ClickUtil;
import com.ckkj.water.utils.color.FateDataUtil;
import com.ckkj.water.utils.dataUtil.SharePreUtil;
import com.ckkj.water.utils.manager.MingDengUserInfoManager;
import com.ckkj.water.utils.number.NumberDecimalFilter;
import com.ckkj.water.utils.show.ToastUtil;
import com.ckkj.water.utils.time.ZYTimeUtils;
import com.qweather.sdk.Callback;
import com.qweather.sdk.JWTGenerator;
import com.qweather.sdk.QWeather;
import com.qweather.sdk.basic.Lang;
import com.qweather.sdk.basic.Unit;
import com.qweather.sdk.parameter.weather.WeatherParameter;
import com.qweather.sdk.response.error.ErrorResponse;
import com.qweather.sdk.response.geo.GeoPoiResponse;
import com.qweather.sdk.response.weather.WeatherNowResponse;
import com.scwang.smart.refresh.layout.api.RefreshHeader;
import java.util.List;
import java.util.Calendar;
import android.os.Handler;
import android.os.Looper;
import de.greenrobot.event.Subscribe;
import de.greenrobot.event.ThreadMode;
import pub.devrel.easypermissions.EasyPermissions;
/**
* @author fengxiaoyang
* @date 2025/7/7
* @description TODO: 描述该类的作用
*/
public class FateFragment extends BaseFragment<FateLayoutBinding, FatePresenter>
implements FateContract.FateView , EasyPermissions.PermissionCallbacks{
private TodayFateEntity mTodayEntity;
// 添加动画执行标志位
private boolean isCareerAnimPlayed = false;
private boolean isLoveAnimPlayed = false;
private boolean isHealthAnimPlayed = false;
private boolean isWealthAnimPlayed = false;
private boolean isOverallAnimPlayed = false;
//是否已经加载过
private boolean hasLoaded = false;
// 添加Toast相关的成员变量
private Handler toastHandler = new Handler(Looper.getMainLooper());
private Runnable toastRunnable;
private boolean isToastTaskRunning = false;
private int currentToastIndex = 0;
private String[] toastMessages = {
"正在查看您的今日能量值",
"让我帮你看看今天的星座运势",
"正在生成您的幸运元素",
"别着急,让我来想想今天的事宜"
};
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
}
@Override
protected void onResumeInitData() {
super.onResumeInitData();
// 确保在Fragment可见时检查动画
viewBinding.getRoot().postDelayed(() -> {
checkAndAnimateProgressBars();
}, 300);
if(AppConfig.USER_LOGIN){
mPresenter.getUserInfo();
}else{
viewBinding.llInput.setVisibility(View.VISIBLE);
}
if (getUserVisibleHint() && !hasLoaded) {
if(AppConfig.USER_LOGIN){
showLoadingDialog();
// 调用接口并启动延迟Toast任务
startFateDataRequest();
hasLoaded = true;
}
}
}
@Override
public void initData(Bundle state) {
//请求定位权限
// String permission = Manifest.permission.ACCESS_FINE_LOCATION;
// if(!hasRecordPermission(permission)){
// getPermissionRequst(permission,"定位权限申请","叮叮车需要您的授权,获取您当前所在的城市",REQUEST_EVENT_CODE_10002);
// }else{
// AMapLocationClient.updatePrivacyAgree(mContext, true);
// initLocationInfo();
// }
// 设置当前日期和星期几
setCurrentDate();
//和风天气 init
try {
JWTGenerator jwt = new JWTGenerator(
"-----BEGIN PRIVATE KEY-----\n" +
"MC4CAQAwBQYDK2VwBCIEIFH+qB/0rER1mEpgAIwpBiAShW9pnSAj8OipGY/eFLRb\n" +
"-----END PRIVATE KEY-----",//密钥
"2A89MF5WVU",//项目 ID
"K5PU3M4P2A");//凭据 ID
instance = QWeather.getInstance(mContext, "mr3597qqpv.re.qweatherapi.com")
.setTokenGenerator(jwt)
.setLogEnable(true);
Log.d(TAG,"和风天气初始化成功");
} catch (Throwable e) {
Log.d(TAG,"和风天气初始化异常");
throw new RuntimeException(e);
}
// 添加视图可见性监听
setupProgressAnimations();
ClickUtil.addClickPart(viewBinding.imgHistory,60);
// 设置自定义刷新头
RefreshHeader header = new CustomRefreshHeader(mContext);
viewBinding.refresh.setRefreshHeader(header);
// viewBinding.refresh.setRefreshFooter(new ClassicsFooter(mContext));
viewBinding.refresh.setOnRefreshListener(layout -> {
if(AppConfig.USER_LOGIN){
showLoadingDialog();
// 调用接口并启动延迟Toast任务
startFateDataRequest();
hasLoaded = true;
}
});
}
/**
* 设置当前日期和星期几
*/
private void setCurrentDate() {
Calendar calendar = Calendar.getInstance();
int month = calendar.get(Calendar.MONTH) + 1; // Calendar.MONTH 从0开始所以要+1
int day = calendar.get(Calendar.DAY_OF_MONTH);
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
// 将数字星期转换为中文
String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
String weekDayStr = weekDays[dayOfWeek - 1]; // Calendar.DAY_OF_WEEK 从1开始星期日=1
// 格式化日期字符串:例如 "9 月 9 日 星期三"
String dateStr = month + "" + day + "" + weekDayStr;
// 设置到TextView
viewBinding.tvDate.setText(dateStr);
}
private void setupProgressAnimations() {
// 监听父滚动视图假设外层是NestedScrollView
View scrollView = viewBinding.getRoot().findViewById(R.id.nesd_scrollview); // 替换为你的NestedScrollView id
if (scrollView != null) {
scrollView.getViewTreeObserver().addOnScrollChangedListener(() -> {
checkAndAnimateProgressBars();
});
}
// 初始检查(如果视图已经可见)
viewBinding.getRoot().postDelayed(() -> {
checkAndAnimateProgressBars();
}, 300); // 延迟300ms确保布局完成
}
private void checkAndAnimateProgressBars() {
if(mTodayEntity == null){
return;
}
// 圆形进度条(运势分数)
if (isViewVisible(viewBinding.includedTodayFateDatas.progressIndicator) && !isOverallAnimPlayed) {
animateCircularProgress(
viewBinding.includedTodayFateDatas.progressIndicator,
mTodayEntity.getFortuneAnalysis().getOverallScore()
);
isOverallAnimPlayed = true;
}
// 检查每个进度条是否需要执行动画
if (isViewVisible(viewBinding.includedSyy.proSyy) && !isCareerAnimPlayed) {
animateProgress(viewBinding.includedSyy.proSyy,
mTodayEntity.getFortuneAnalysis().getCareerScore());
isCareerAnimPlayed = true;
}
if (isViewVisible(viewBinding.includedSyy.proGqy) && !isLoveAnimPlayed) {
animateProgress(viewBinding.includedSyy.proGqy,
mTodayEntity.getFortuneAnalysis().getLoveScore());
isLoveAnimPlayed = true;
}
if (isViewVisible(viewBinding.includedSyy.proJky) && !isHealthAnimPlayed) {
animateProgress(viewBinding.includedSyy.proJky,
mTodayEntity.getFortuneAnalysis().getHealthScore());
isHealthAnimPlayed = true;
}
if (isViewVisible(viewBinding.includedSyy.proCfy) && !isWealthAnimPlayed) {
animateProgress(viewBinding.includedSyy.proCfy,
mTodayEntity.getFortuneAnalysis().getWealthScore());
isWealthAnimPlayed = true;
}
}
// 判断视图是否可见
private boolean isViewVisible(View view) {
if (view == null) return false;
Rect scrollBounds = new Rect();
View scrollView = viewBinding.getRoot().findViewById(R.id.nesd_scrollview);
if (scrollView != null) {
scrollView.getHitRect(scrollBounds);
return view.getLocalVisibleRect(scrollBounds);
}
return false;
}
// 执行进度条动画
private void animateProgress(LinearProgressIndicator progressBar, int targetProgress) {
// 保存原始进度值
final int originalProgress = progressBar.getProgress();
// 先重置为0
progressBar.setProgress(0);
// 创建动画
ObjectAnimator animator = ObjectAnimator.ofInt(progressBar, "progress", 0, targetProgress);
animator.setDuration(800); // 动画时长800ms
animator.setInterpolator(new AccelerateDecelerateInterpolator());
// 添加脉冲效果
animator.addUpdateListener(animation -> {
float fraction = animation.getAnimatedFraction();
float scale = 1 + 0.2f * (float) Math.sin(fraction * Math.PI);
progressBar.setScaleX(scale);
progressBar.setScaleY(scale);
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// 恢复原始大小
progressBar.animate()
.scaleX(1f)
.scaleY(1f)
.setDuration(200)
.start();
}
});
animator.start();
}
// 执行圆形进度条动画(带旋转效果)
private void animateCircularProgress(CircularProgressIndicator progressBar, int targetProgress) {
// 保存原始进度值
final int originalProgress = progressBar.getProgress();
// 先重置为0
progressBar.setProgress(0);
// 创建进度动画
ValueAnimator progressAnimator = ValueAnimator.ofInt(0, targetProgress);
progressAnimator.setDuration(1000); // 动画时长1000ms
progressAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
// 创建旋转动画
ObjectAnimator rotationAnimator = ObjectAnimator.ofFloat(progressBar, "rotation", 0f, 360f);
rotationAnimator.setDuration(800);
rotationAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
// 组合动画
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(progressAnimator, rotationAnimator);
// 添加脉冲缩放效果
progressAnimator.addUpdateListener(animation -> {
int progress = (int) animation.getAnimatedValue();
progressBar.setProgress(progress);
// 脉冲效果:在动画过程中轻微缩放
float fraction = animation.getAnimatedFraction();
float scale = 1 + 0.12f * (float) Math.sin(fraction * Math.PI);
progressBar.setScaleX(scale);
progressBar.setScaleY(scale);
});
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// 恢复原始大小
progressBar.animate()
.scaleX(1f)
.scaleY(1f)
.setDuration(200)
.start();
}
});
animatorSet.start();
}
@Override
public FatePresenter createPresenter() {
return new FatePresenter(new FateImpl());
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(data != null){
if(resultCode == RESULT_OK){
switch (requestCode){
case REQUEST_EVENT_CODE_10002:
break;
case REQUEST_EVENT_CODE_10001:
break;
}
}
}
}
@Subscribe(threadMode = ThreadMode.MainThread)
public void onGetMessage(EventMessage message) {
switch (message.msg){
case EventMessage.DATA_REFRESH_EVENT:
showLoadingDialog();
startFateDataRequest();
break;
case EventMessage.USER_LOGIN_SUCCESS:
startFateDataRequest();
break;
}
}
/**
* 启动今日运势数据请求并开始延迟Toast任务
*/
private void startFateDataRequest() {
// 停止之前的Toast任务如果有的话
stopToastTask();
// 调用接口
mPresenter.getTodayFateDatas();
// 启动延迟Toast任务
startDelayedToastTask();
}
/**
* 启动延迟Toast任务
*/
private void startDelayedToastTask() {
// 5秒后开始显示Toast
toastHandler.postDelayed(() -> {
if (!isToastTaskRunning) {
isToastTaskRunning = true;
currentToastIndex = 0;
startToastLoop();
}
}, 5000);
}
/**
* 开始Toast循环显示
*/
private void startToastLoop() {
if (!isToastTaskRunning) {
return;
}
toastRunnable = new Runnable() {
@Override
public void run() {
if (isToastTaskRunning && currentToastIndex < toastMessages.length) {
// 显示当前Toast
ToastUtil.showLong(mContext, toastMessages[currentToastIndex]);
currentToastIndex++;
// 如果还有下一条消息5秒后显示
if (currentToastIndex < toastMessages.length && isToastTaskRunning) {
toastHandler.postDelayed(this, 5000);
} else {
// 所有消息显示完毕,重新开始循环
if (isToastTaskRunning) {
currentToastIndex = 0;
toastHandler.postDelayed(this, 5000);
}
}
}
}
};
// 立即执行第一次
toastRunnable.run();
}
/**
* 停止Toast任务
*/
private void stopToastTask() {
isToastTaskRunning = false;
if (toastRunnable != null) {
toastHandler.removeCallbacks(toastRunnable);
}
// 移除所有待执行的任务
toastHandler.removeCallbacksAndMessages(null);
}
/**
* 今日运势请求成功
* @param entity
*/
@Override
public void getUserTodayFateDataSuccess(TodayFateEntity entity) {
// 立即停止Toast任务
stopToastTask();
hideDialogLoading();
mTodayEntity = entity;
getLatLngByCityName(entity.getUserInfo().getCurrentPlace());
setDataShow();
viewBinding.refresh.finishRefresh(300);
}
@Override
public void getFateHistorySuccess(FateHistoryEntity entity) {
}
@Override
public void userSaveBirthInfoSuccess(TodayFateEntity bean) {
}
@Override
public void getUserInfoSuccess(MineUserInfoBean bean) {
if(bean != null){
MingDengUserInfoManager.getInstance().setUserInfo(bean.getUserInfo());
SharePreUtil.putBoolean(ConstantUtil.SHARE_PRE_NAME,mContext,ConstantUtil.USER_HAS_SET_BIRTH,bean.isHasEightCharacters());
AppConfig.USER_SET_BIRTH_INFO = bean.isHasEightCharacters();
//是否设置过生辰
if(AppConfig.USER_SET_BIRTH_INFO){
viewBinding.llInput.setVisibility(View.GONE);
viewBinding.refresh.setVisibility(View.VISIBLE);
}else{
viewBinding.llInput.setVisibility(View.VISIBLE);
viewBinding.refresh.setVisibility(View.GONE);
}
}
}
/**
* 提交举报成功
* @param bean
*/
@Override
public void commitReportSuccess(BaseBean bean) {
ToastUtil.showShort(mContext, "星语明灯感谢您的反馈");
hideDialogLoading();
}
/**
* 设置显示内容
*/
private void setDataShow() {
//出生日期
String birthDay = mTodayEntity.getUserInfo().getBirthTime();
viewBinding.includedBirthInfo.tvBirthdayTime.setText(ZYTimeUtils.formatDateString(birthDay));
//真太阳时
String realSunTime = mTodayEntity.getUserInfo().getTrueSolarTime();
viewBinding.includedBirthInfo.tvZhentaiyangValue.setText(TextUtils.isEmpty(realSunTime) ?
"未知":ZYTimeUtils.formatToChineseDate(realSunTime));
//命格
viewBinding.includedBirthInfo.tvMingge.setText(TextUtils.isEmpty(mTodayEntity.getFortuneAnalysis().getDestiny()) ?
"未知": mTodayEntity.getFortuneAnalysis().getDestiny());
//经纬度
String lng = NumberDecimalFilter.truncateToTwoDecimal(Double.parseDouble(mTodayEntity.getUserInfo().getLongitude()));
String lat = NumberDecimalFilter.truncateToTwoDecimal(Double.parseDouble(mTodayEntity.getUserInfo().getLatitude()));
viewBinding.includedBirthInfo.tvLonglat.setText(lng + "," + lat);
//出生地
viewBinding.includedBirthInfo.tvBirthAddress.setText(mTodayEntity.getUserInfo().getBirthPlace());
//星座
viewBinding.includedBirthInfo.tvXingzuo.setText(mTodayEntity.getUserInfo().getConstellation());
//运势分数
int todayScore = mTodayEntity.getFortuneAnalysis().getOverallScore();
int color = FateDataUtil.getScoreColor(todayScore);
viewBinding.includedTodayFateDatas.progressIndicator.setIndicatorColor(color);
// viewBinding.includedTodayFateDatas.progressIndicator.setProgress(todayScore,true);
viewBinding.includedTodayFateDatas.tvFeenValue.setText(String.valueOf(todayScore));
viewBinding.includedTodayFateDatas.tvFeenValue.setTextColor(color);
//运势内容
viewBinding.includedTodayFateDatas.tvYunshiContent.setText(TextUtils.isEmpty(mTodayEntity.getFortuneAnalysis().getOverallDescription())?
"暂无内容" : mTodayEntity.getFortuneAnalysis().getOverallDescription());
//今日吉时
viewBinding.includedTodayFateDatas.tvTimeZc.setText(mTodayEntity.getFortuneAnalysis().getLuckyInfo().getLuckyTimes().get(0).getTime());
viewBinding.includedTodayFateDatas.tvThingZc.setText(mTodayEntity.getFortuneAnalysis().getLuckyInfo().getLuckyTimes().get(0).getDescription());
viewBinding.includedTodayFateDatas.tvTimeZw.setText(mTodayEntity.getFortuneAnalysis().getLuckyInfo().getLuckyTimes().get(1).getTime());
viewBinding.includedTodayFateDatas.tvThingZw.setText(mTodayEntity.getFortuneAnalysis().getLuckyInfo().getLuckyTimes().get(1).getDescription());
viewBinding.includedTodayFateDatas.tvTimeXw.setText(mTodayEntity.getFortuneAnalysis().getLuckyInfo().getLuckyTimes().get(2).getTime());
viewBinding.includedTodayFateDatas.tvThingXw.setText(mTodayEntity.getFortuneAnalysis().getLuckyInfo().getLuckyTimes().get(2).getDescription());
//天象星座
viewBinding.includedXingzuo.tvXingzuo.setText(mTodayEntity.getUserInfo().getConstellation());
viewBinding.includedXingzuo.tvWendu.setText(mTodayEntity.getWeatherTemperature());
viewBinding.includedXingzuo.tvTianqi.setText(mTodayEntity.getWeatherCondition());
viewBinding.includedXingzuo.tvXzType.setText(FateDataUtil.getConstellationType(mTodayEntity.getUserInfo().getConstellation()));
viewBinding.includedXingzuo.tvXingzuoYingxiang.setText(mTodayEntity.getFortuneAnalysis().getAstrologyInfluence().getDescription());
//事业运
viewBinding.includedSyy.tvSyyScore.setText(String.valueOf(mTodayEntity.getFortuneAnalysis().getCareerScore()));
// viewBinding.includedSyy.proSyy.setProgress(mTodayEntity.getFortuneAnalysis().getCareerScore());
viewBinding.includedSyy.tvSyyContent.setText(mTodayEntity.getFortuneAnalysis().getCareerDescription());
//事业运
viewBinding.includedSyy.tvGqyScore.setText(String.valueOf(mTodayEntity.getFortuneAnalysis().getLoveScore()));
// viewBinding.includedSyy.proGqy.setProgress(mTodayEntity.getFortuneAnalysis().getLoveScore());
viewBinding.includedSyy.tvGqyContent.setText(mTodayEntity.getFortuneAnalysis().getLoveDescription());
//事业运
viewBinding.includedSyy.tvJkyScore.setText(String.valueOf(mTodayEntity.getFortuneAnalysis().getHealthScore()));
// viewBinding.includedSyy.proJky.setProgress(mTodayEntity.getFortuneAnalysis().getHealthScore());
viewBinding.includedSyy.tvJkyContent.setText(mTodayEntity.getFortuneAnalysis().getHealthDescription());
//事业运
viewBinding.includedSyy.tvCfyScore.setText(String.valueOf(mTodayEntity.getFortuneAnalysis().getWealthScore()));
// viewBinding.includedSyy.proCfy.setProgress(mTodayEntity.getFortuneAnalysis().getWealthScore());
viewBinding.includedSyy.tvCfyContent.setText(mTodayEntity.getFortuneAnalysis().getWealthDescription());
//幸运数字
String [] numbers = mTodayEntity.getFortuneAnalysis().getLuckyInfo().getNumbers();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < numbers.length; i++) {
sb.append(numbers[i]);
if (i < numbers.length - 1) {
sb.append("");
}
}
viewBinding.includeXingyun.tvLuckNum.setText(sb.toString());
//幸运颜色
viewBinding.includeXingyun.tvLuckColor.setText(mTodayEntity.getFortuneAnalysis().getLuckyInfo().getColor());
//幸运方位
viewBinding.includeXingyun.tvLuckFw.setText(mTodayEntity.getFortuneAnalysis().getLuckyInfo().getDirection());
//幸运时间
viewBinding.includeXingyun. tvLuckTime.setText(mTodayEntity.getFortuneAnalysis().getLuckyInfo().getLuckyTimes().get(0).getTime());
//幸运花卉
viewBinding.includeXingyun.tvLuckFlower.setText(mTodayEntity.getFortuneAnalysis().getLuckyInfo().getFlower());
//幸运方位
viewBinding.includeXingyun.tvLuckFood.setText(mTodayEntity.getFortuneAnalysis().getLuckyInfo().getFood());
//宜 忌
String positive = mTodayEntity.getFortuneAnalysis().getSuggestions().getPositive();
String negative = mTodayEntity.getFortuneAnalysis().getSuggestions().getNegative();
viewBinding.includeYsjy.tvPositive.setText(positive);
viewBinding.includeYsjy.tvNegative.setText(negative);
//五行分析
viewBinding.includeYsjy.tvFive.setText(mTodayEntity.getFortuneAnalysis().getFiveElementsAnalysis());
// 重置动画标志位
resetAnimationFlags();
}
/**
* 通过城市逆地理编码,获取经纬度
* @param cityName
*/
private void getLatLngByCityName(String cityName) {
try {
GeocodeSearch geocodeSearch = new GeocodeSearch(mContext);
geocodeSearch.setOnGeocodeSearchListener(new GeocodeSearch.OnGeocodeSearchListener() {
@Override
public void onRegeocodeSearched(com.amap.api.services.geocoder.RegeocodeResult regeocodeResult, int i) {
// Not used here
}
@Override
public void onGeocodeSearched(GeocodeResult geocodeResult, int rCode) {
if (rCode == AMapException.CODE_AMAP_SUCCESS) {
List<GeocodeAddress> addressList = geocodeResult.getGeocodeAddressList();
if (addressList != null && !addressList.isEmpty()) {
GeocodeAddress address = addressList.get(0);
LatLonPoint latLonPoint = address.getLatLonPoint();
String lat = String.valueOf(NumberDecimalFilter.roundToTwoDecimalPlaces(latLonPoint.getLatitude()));
String lng = String.valueOf(NumberDecimalFilter.roundToTwoDecimalPlaces(latLonPoint.getLongitude()));
WeatherParameter parameter = new WeatherParameter(lng + "," + lat)
.lang(Lang.ZH_HANS)
.unit(Unit.METRIC);
instance.weatherNow(parameter, new Callback<WeatherNowResponse>() {
@Override
public void onSuccess(WeatherNowResponse response) {
mContext.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
WeatherIconUtil.loadWeatherIcon(mContext,viewBinding.includedBirthInfo.imgWeather,response.getNow().getIcon());
viewBinding.includedBirthInfo.tvTianqi.setText(response.getNow().getText() + " " +response.getNow().getTemp() + "");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
}
@Override
public void onFailure(ErrorResponse errorResponse) {
Log.d(TAG,"调用和风 API--onFailure" + errorResponse.toString());
}
@Override
public void onException(Throwable e) {
Log.d(TAG,"调用和风 API--onException" + e.getMessage());
e.printStackTrace();
}
});
} else {
Log.d("GeoUtil", "未找到城市: " + cityName);
}
} else {
Log.e("GeoUtil", "查询失败,错误码: " + rCode);
}
}
});
// 创建 GeocodeQuery第一个参数是城市名第二个参数可指定省份可选
GeocodeQuery query = new GeocodeQuery(cityName, null);
geocodeSearch.getFromLocationNameAsyn(query); // 异步查询
} catch (AMapException e) {
throw new RuntimeException(e);
}
}
// 重置动画标志位
private void resetAnimationFlags() {
isOverallAnimPlayed = false;
isCareerAnimPlayed = false;
isLoveAnimPlayed = false;
isHealthAnimPlayed = false;
isWealthAnimPlayed = false;
}
@Override
public void onPause() {
super.onPause();
// 停止Toast任务
stopToastTask();
// 重置标志位以便下次可见时重新动画
resetAnimationFlags();
}
@Override
public void onDestroy() {
super.onDestroy();
// 清理资源
stopToastTask();
}
@Override
public void onNetChange(int netModel) {
}
@Override
public void showError(String message) {
// 停止Toast任务
stopToastTask();
hideDialogLoading();
ToastUtil.showShort(mContext,message);
}
@Override
public void logOut(BaseBean bean) {
}
@Override
public void getAllCitySuccess(List<CityDataEntity> list) {
}
private void getCurrentCityWeather(GeoPoiResponse response) {
}
@Override
public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
}
@Override
public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
hidePermissionDialog();
if(requestCode == REQUEST_EVENT_CODE_10002){
if(grantResults[0] == 0){
ToastUtil.showShort(mContext,"定位获取成功");
}
}
}
}

View File

@@ -0,0 +1,236 @@
package com.ckkj.water.guide;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.bumptech.glide.Glide;
import com.ckkj.water.AppConfig;
import com.ckkj.water.ConstantUtil;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.databinding.GuideActivityLayoutBinding;
import com.ckkj.water.login.entity.LoginEntity;
import com.ckkj.water.login.mvp.LoginContract;
import com.ckkj.water.login.mvp.LoginImpl;
import com.ckkj.water.login.mvp.LoginPresenter;
import com.ckkj.water.main.activity.MainActivity;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.utils.dataUtil.SharePreUtil;
import java.util.ArrayList;
import java.util.List;
public class GuideActivity extends BaseActivity<GuideActivityLayoutBinding, LoginPresenter>
implements LoginContract.LoginView {
private List<Drawable> mImgUrls = new ArrayList<>();
private List<ImageView> mPointList = new ArrayList<>();
private boolean mHasEnterAppFlag = false;
private String desc[] = {"探索你的个性特征",
"一键生成,智能排盘工具",
"贴心提供每日生活指南"};
private int[] guideDrawableIds = {
R.mipmap.img_guide_1,
R.mipmap.img_guide_2,
R.mipmap.img_guide_3
};
@Override
public LoginPresenter createPresenter() {
return new LoginPresenter(new LoginImpl());
}
@Override
public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
for (int resId : guideDrawableIds) {
mImgUrls.add(ContextCompat.getDrawable(mContext, resId));
}
mHasEnterAppFlag = SharePreUtil.getBoolean(ConstantUtil.SHARE_PRE_NAME, mContext, ConstantUtil.FIRST_ENTER_APP_FLAG);
if (!mHasEnterAppFlag) {
viewBinding.viewpage.setAdapter(new MyAdapter());
viewBinding.viewpage.setPageTransformer(true, new CrossFadePageTransformer());
viewBinding.viewpage.setOffscreenPageLimit(1);
viewBinding.viewpage.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
setPointSelect(position);
if (position == mImgUrls.size() - 1) {
viewBinding.tvStart.setVisibility(View.VISIBLE);
AlphaAnimation fadeIn = new AlphaAnimation(0f, 1f);
fadeIn.setDuration(400);
viewBinding.tvStart.startAnimation(fadeIn);
} else {
viewBinding.tvStart.setVisibility(View.INVISIBLE);
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
viewBinding.tvStart.setOnClickListener(v -> {
SharePreUtil.putBoolean(ConstantUtil.SHARE_PRE_NAME, mContext, ConstantUtil.FIRST_ENTER_APP_FLAG, true);
Intent intent = new Intent(mContext, MainActivity.class);
startActivity(intent);
finish();
});
}
private void setPointSelect(int position) {
for (int i = 0; i < mPointList.size(); i++) {
mPointList.get(i).setImageResource(
i == position ? R.drawable.indicator_dot_selected : R.drawable.indicator_dot_normal);
}
}
private int dp2px(float dp) {
float density = getResources().getDisplayMetrics().density;
return Math.round(dp * density);
}
@Override
protected void initWidget() {
super.initWidget();
}
@Override
public void getPhoneCodeSuccess(BaseBean bean) {
}
@Override
public void loginBySmsCodeSuccess(LoginEntity entity) {
}
class MyAdapter extends PagerAdapter {
@Override
public int getCount() {
return mImgUrls.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object obj) {
return view == obj;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
FrameLayout page = new FrameLayout(mContext);
page.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
ImageView imageView = new ImageView(mContext);
imageView.setAdjustViewBounds(true);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
Gravity.TOP | Gravity.CENTER_HORIZONTAL
);
imageView.setLayoutParams(lp);
Glide.with(mContext).load(mImgUrls.get(position)).into(imageView);
page.addView(imageView);
container.addView(page);
return page;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView((View) object);
}
}
/**
* Cross-fade page transition: outgoing page fades out (alpha 1→0),
* incoming page fades in (alpha 0→1) simultaneously.
*/
public class CrossFadePageTransformer implements ViewPager.PageTransformer {
private static final float MIN_ALPHA = 0.0f;
@Override
public void transformPage(@NonNull View page, float position) {
if (position < -1f) {
page.setAlpha(MIN_ALPHA);
} else if (position <= 0f) {
page.setAlpha(1f + position);
} else if (position <= 1f) {
page.setAlpha(1f - position);
} else {
page.setAlpha(MIN_ALPHA);
}
}
}
@RequiresApi(api = Build.VERSION_CODES.P)
@Override
public int getLayoutResId(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
hideStatusBar();
}
hideBottomUIMenu();
return R.layout.guide_activity_layout;
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
@RequiresApi(api = Build.VERSION_CODES.P)
protected void hideStatusBar() {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(lp);
}
protected void hideBottomUIMenu() {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) {
View v = this.getWindow().getDecorView();
v.setSystemUiVisibility(View.GONE);
} else if (Build.VERSION.SDK_INT >= 19) {
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
decorView.setSystemUiVisibility(uiOptions);
}
}
}

View File

@@ -0,0 +1,156 @@
package com.ckkj.water.guide;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import com.ckkj.water.login.LoginActivity;
import com.gyf.immersionbar.ImmersionBar;
import com.ckkj.water.ConstantUtil;
import com.ckkj.water.MyApplication;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.base.entity.MineUserInfoBean;
import com.ckkj.water.databinding.GuideLayoutBinding;
import com.ckkj.water.main.MainContract;
import com.ckkj.water.main.MainImpl;
import com.ckkj.water.main.MainPresenter;
import com.ckkj.water.main.activity.MainActivity;
import com.ckkj.water.main.entity.CheckVersionEntity;
import com.ckkj.water.mine.WebviewUserAgreement;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.utils.dataUtil.SharePreUtil;
import com.ckkj.water.utils.manager.ActivityManager;
import me.jessyan.autosize.internal.CancelAdapt;
import me.jessyan.autosize.internal.CustomAdapt;
/**
* @author fengxiaoyang
* @date 2025/7/7
* @description TODO: 启动页面
*/
public class LaunchActivity extends BaseActivity<GuideLayoutBinding, MainPresenter>
implements MainContract.MainView, CancelAdapt {
private boolean mIsFirstEnterApp = false;
@Override
public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
viewBinding.includeTitle.imgBack.setVisibility(View.GONE);
viewBinding.includeTitle.tvTitle.setVisibility(View.GONE);
ImmersionBar.with(this)
.statusBarColor(R.color.white)
.statusBarDarkFont(true)
.titleBar(viewBinding.rlTitle) // 替换为你的标题栏View
.keyboardEnable(true)
.navigationBarDarkIcon(true)
.init();
mIsFirstEnterApp = SharePreUtil.getBooleanDefTrue(ConstantUtil.SHARE_PRE_NAME, mContext, ConstantUtil.FIRST_ENTER_APP_AGREEMENT_TIPS);
//首次进入,弹框提示隐私政策
if (mIsFirstEnterApp) {
//首次进入
showDialogtext("温馨提示", mContext.getResources().getString(R.string.tips_yinsizhengce_dialog),
"同意", "拒绝", "用户隐私协议", new OnDialogClick() {
@Override
public void onCancelClick() {
finish();
}
@Override
public void onConfirmClisk() {
//第一次进入App隐私弹窗是否显示
SharePreUtil.putBoolean(ConstantUtil.SHARE_PRE_NAME, mContext, ConstantUtil.FIRST_ENTER_APP_AGREEMENT_TIPS, false);
//用户是否同意了隐私政策
SharePreUtil.putBoolean(ConstantUtil.SHARE_PRE_NAME, mContext, ConstantUtil.PRIVACY_POLICY_AGREED, true);
MyApplication app = (MyApplication) getApplicationContext();
app.initializeUmengSDK();
goTo(mContext, GuideActivity.class, null);
finish();
}
@Override
public void onConfirmClisk(String content) {
}
@Override
public void onView1Click() {
Bundle bundle = new Bundle();
bundle.putInt("from_requse_code", WebviewUserAgreement.PRIVACY_CODE);
goToWihoutNoPresent(mContext, WebviewUserAgreement.class, bundle);
}
}, false, true);
} else {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(mContext, MainActivity.class);
startActivity(intent);
finish();
}
}, 2000);
}
}
@Override
public void onBackPressed() {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
ActivityManager.removeAllActivity();
finish();
}
@Override
public MainPresenter createPresenter() {
return new MainPresenter(new MainImpl());
}
@Override
public int getLayoutResId(Bundle savedInstanceState) {
return 0;
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
@Override
public void getAppVersionSuccess(CheckVersionEntity bean) {
}
@Override
public void activationVipSuccess(BaseBean bean) {
}
@Override
public void getVersionCheck(CheckVersionEntity entity) {
}
@Override
public void getYunshiDataSuccess(BaseBean bean) {
}
@Override
public void getUserInfoSuccess(MineUserInfoBean bean) {
}
}

View File

@@ -0,0 +1,99 @@
package com.ckkj.water.history;
import static android.view.View.INVISIBLE;
import android.os.Bundle;
import android.view.View;
import androidx.fragment.app.Fragment;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.databinding.HistoryFragmentLayoutBinding;
import com.ckkj.water.history.mvp.HistoryContract;
import com.ckkj.water.history.mvp.HistoryPresenter;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plan.BindDeviceFragment;
import com.ckkj.water.plan.WaterConfigFragment;
import com.ckkj.water.plate.adapter.ViewPagerAdapter;
import com.gyf.immersionbar.ImmersionBar;
import java.util.ArrayList;
import java.util.List;
/**
* 历史
*/
public class HistoryFragment extends BaseFragment<HistoryFragmentLayoutBinding, HistoryPresenter>
implements HistoryContract.HistoryView {
private List<Fragment> mFragmentList = new ArrayList<>();
@Override
public void initData(Bundle state) {
ImmersionBar.with(mContext)
.statusBarColor(R.color.white)
.statusBarDarkFont(true)
.titleBar(viewBinding.rlTitle)
.init();
viewBinding.includedTitle.imgBack.setVisibility(INVISIBLE);
viewBinding.includedTitle.tvTitle.setText(getString(R.string.history_title));
mFragmentList.add(new TabHistoryFragment());
mFragmentList.add(new StatisticFragment());
ViewPagerAdapter adapter = new ViewPagerAdapter(this, mFragmentList);
viewBinding.viewpage.setAdapter(adapter);
viewBinding.viewpage.setCurrentItem(0);
//viewpage2 特有的 api禁止滑动
viewBinding.viewpage.setUserInputEnabled(false);
viewBinding.tvHistory.setSelected(true);
viewBinding.tvData.setSelected(false);
initListener();
}
private void initListener() {
setClick(viewBinding.tvHistory);
setClick(viewBinding.tvData);
}
private void setClick(View view) {
view.setOnClickListener(this::onClick);
}
public void onClick(View v){
switch (v.getId()){
case R.id.tv_history:
viewBinding.tvHistory.setSelected(true);
viewBinding.tvData.setSelected(false);
viewBinding.viewpage.setCurrentItem(0);
break;
case R.id.tv_data:
viewBinding.tvHistory.setSelected(false);
viewBinding.tvData.setSelected(true);
viewBinding.viewpage.setCurrentItem(1);
break;
}
}
@Override
public HistoryPresenter createPresenter() {
return null;
}
@Override
public void onNetChange(int netModel) {
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
}

View File

@@ -0,0 +1,42 @@
package com.ckkj.water.history;
import android.os.Bundle;
import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.databinding.WaterCountFragmentLayoutBinding;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plan.mvp.WaterPlanContract;
import com.ckkj.water.plan.mvp.WaterPlanPresenter;
/**
* @author fengxiaoyang
* @date 2026/5/16
* @description TODO: 描述该类的作用
*/
public class StatisticFragment extends BaseFragment<WaterCountFragmentLayoutBinding, WaterPlanPresenter>
implements WaterPlanContract.WaterPlanView {
@Override
public void initData(Bundle state) {
}
@Override
public WaterPlanPresenter createPresenter() {
return null;
}
@Override
public void onNetChange(int netModel) {
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
}

View File

@@ -0,0 +1,159 @@
package com.ckkj.water.history;
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.custom.CustomTimeFilterPopupView;
import com.ckkj.water.custom.CustomTypeFilterPopupView;
import com.ckkj.water.databinding.TabHistoryFragmentLayoutBinding;
import com.ckkj.water.history.adapter.WateringHistoryAdapter;
import com.ckkj.water.history.entity.WateringRecord;
import com.ckkj.water.history.mvp.HistoryContract;
import com.ckkj.water.history.mvp.HistoryPresenter;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.utils.show.ToastUtil;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.core.BasePopupView;
import com.lxj.xpopup.interfaces.SimpleCallback;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2026/5/14
* @description TODO: 描述该类的作用
*/
public class TabHistoryFragment extends BaseFragment<TabHistoryFragmentLayoutBinding, HistoryPresenter>
implements HistoryContract.HistoryView {
List<WateringRecord> recordList = new ArrayList<>();
private WateringHistoryAdapter mAdapter;
@Override
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);
viewBinding.rvHisttory.setAdapter(mAdapter);
initListener();
}
private void initListener() {
setClick(viewBinding.linearTimeFilter);
setClick(viewBinding.linearTypeFilter);
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() {
mAdapter.remove(position);
}
});
break;
}
}
});
}
private void setClick(View view) {
view.setOnClickListener(this::onClick);
}
public void onClick(View v){
switch (v.getId()){
case R.id.linear_time_filter:
CustomTimeFilterPopupView popupView = (CustomTimeFilterPopupView) new XPopup.Builder(getContext())
.isViewMode(true)
.isTouchThrough(false)
.isDestroyOnDismiss(true)
.dismissOnTouchOutside(true)
.atView(v)
.setPopupCallback(new SimpleCallback() {
@Override
public void onShow(BasePopupView popupView) {
viewBinding.tvTimeFilter.setTextColor(mContext.getColor(R.color.color_zhu));
viewBinding.imgTimeFilter.setImageResource(R.mipmap.icon_green_triangle_up);
}
@Override
public void onDismiss(BasePopupView popupView) {
viewBinding.tvTimeFilter.setTextColor(mContext.getColor(R.color.color_222222));
viewBinding.imgTimeFilter.setImageResource(R.mipmap.icon_triangle_down);
}
})
.asCustom(new CustomTimeFilterPopupView(getContext(), new CustomTimeFilterPopupView.OnClickListener() {
@Override
public void callBack(String startTime, String endTime) {
ToastUtil.showShort(mContext,startTime + "---" + endTime);
}
}));
popupView.show();
break;
case R.id.linear_type_filter:
CustomTypeFilterPopupView typePopupView = (CustomTypeFilterPopupView) new XPopup.Builder(getContext())
.isViewMode(true)
.isTouchThrough(false)
.isDestroyOnDismiss(true)
.dismissOnTouchOutside(true)
.atView(v)
.setPopupCallback(new SimpleCallback() {
@Override
public void onShow(BasePopupView popupView) {
viewBinding.tvTypeFilter.setTextColor(mContext.getColor(R.color.color_zhu));
viewBinding.imgTypeFilter.setImageResource(R.mipmap.icon_green_triangle_up);
}
@Override
public void onDismiss(BasePopupView popupView) {
viewBinding.tvTypeFilter.setTextColor(mContext.getColor(R.color.color_222222));
viewBinding.imgTypeFilter.setImageResource(R.mipmap.icon_triangle_down);
}
})
.asCustom(new CustomTypeFilterPopupView(getContext(), new CustomTypeFilterPopupView.OnClickListener() {
@Override
public void callBack(boolean mSelManual, boolean mSelAuto) {
}
}));
typePopupView.show();
break;
}
}
@Override
public HistoryPresenter createPresenter() {
return null;
}
@Override
public void onNetChange(int netModel) {
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
}

View File

@@ -0,0 +1,38 @@
package com.ckkj.water.history.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.history.entity.WateringRecord;
import java.util.List;
/**
* @author fengxiaoyang
* @date 2026/5/15
* @description TODO: 描述该类的作用
*/
public class WateringHistoryAdapter extends BaseQuickAdapter<WateringRecord, BaseViewHolder> {
private Context mContext;
public WateringHistoryAdapter(Context context,int layoutResId, @Nullable List<WateringRecord> data) {
super(layoutResId, data);
this.mContext = context;
}
@Override
protected void convert(BaseViewHolder helper, WateringRecord item) {
helper.setText(R.id.tv_device_name,item.getDeviceName());
helper.setText(R.id.tv_device_serial,item.getDeviceCode());
helper.setText(R.id.tv_plan_time,mContext.getString(R.string.history_watering_adapter_time)
+ ":" + item.getStartTime() + "-" + item.getEndTime());
helper.setText(R.id.tv_plan_duration,mContext.getString(R.string.device_work_times_title)
+ ":" + item.getDuration());
helper.setText(R.id.tv_plan_type,mContext.getString(R.string.tab_filter_type)
+ ":" + item.getTriggerType());
helper.addOnClickListener(R.id.img_delete);
}
}

View File

@@ -0,0 +1,32 @@
package com.ckkj.water.history.entity;
import java.io.Serializable;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author fengxiaoyang
* @date 2026/5/15
* @description TODO: 描述该类的作用
*/
@NoArgsConstructor
@Data
public class WateringRecord implements Serializable {
/**
* deviceName : 智能浇水设备A1
* deviceCode : YA226641000107
* startTime : 2026-10-10 16:00
* endTime : 2026-10-10 16:30
* duration : 30min
* triggerType : 排程
*/
private String deviceName;
private String deviceCode;
private String startTime;
private String endTime;
private String duration;
private String triggerType;
}

View File

@@ -0,0 +1,16 @@
package com.ckkj.water.history.mvp;
import com.ckkj.water.base.IView;
public class HistoryContract {
public interface CallBack<T> {
void success(T msg);
void fail(String msg);
}
public interface DataModel{
}
public interface HistoryView extends IView {
}
}

View File

@@ -0,0 +1,5 @@
package com.ckkj.water.history.mvp;
public class HistoryImpl implements HistoryContract.DataModel{
}

View File

@@ -0,0 +1,11 @@
package com.ckkj.water.history.mvp;
import com.ckkj.water.base.BasePresenter;
public class HistoryPresenter extends BasePresenter<HistoryContract.HistoryView> {
private HistoryImpl impl;
public HistoryPresenter(HistoryImpl impl) {
this.impl = impl;
}
}

View File

@@ -0,0 +1,151 @@
package com.ckkj.water.index;
import android.Manifest;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.databinding.IndexFragmentLayoutBinding;
import com.ckkj.water.device.AddDeviceActivity;
import com.ckkj.water.device.DeviceControlActivity;
import com.ckkj.water.index.adapter.DeviceAdapter;
import com.ckkj.water.index.entity.IndexDeviceEntity;
import com.ckkj.water.index.mvp.IndexContract;
import com.ckkj.water.index.mvp.IndexImpl;
import com.ckkj.water.index.mvp.IndexPresenter;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.utils.show.ToastUtil;
import com.maning.mlkitscanner.scan.MNScanManager;
import com.maning.mlkitscanner.scan.callback.act.MNScanCallback;
import java.util.ArrayList;
import java.util.List;
import pub.devrel.easypermissions.EasyPermissions;
public class IndexFragment extends BaseFragment<IndexFragmentLayoutBinding, IndexPresenter>
implements IndexContract.IndexView , EasyPermissions.PermissionCallbacks{
private DeviceAdapter deviceAdapter;
private List<IndexDeviceEntity> devList = new ArrayList<>();
@Override
protected void initArgs(Bundle bundle) {
}
@Override
public void initData(@Nullable Bundle savedInstanceState) {
IndexDeviceEntity entity = new IndexDeviceEntity("智能浇水设备A1","YA226641000101","工作中",100);
IndexDeviceEntity entity2 = new IndexDeviceEntity("智能浇水设备B1","YA22664100000","工作中",80);
IndexDeviceEntity entity3 = new IndexDeviceEntity("智能浇水设备C5","YA234534000101","工作中",70);
IndexDeviceEntity entity4 = new IndexDeviceEntity("智能浇水设备D6","YA2266678543101","工作中",50);
devList.add(entity);
devList.add(entity2);
devList.add(entity3);
devList.add(entity4);
}
@Override
public IndexPresenter createPresenter() {
return new IndexPresenter(new IndexImpl());
}
@Override
protected void initView() {
super.initView();
setupRecyclerView();
initListener();
}
private void initListener() {
setClick(viewBinding.imgScan);
setClick(viewBinding.imgAdd);
}
private void setClick(View view) {
view.setOnClickListener(this::onClick);
}
public void onClick(View v){
switch (v.getId()){
case R.id.img_scan:
//检测有无相机权限
String readPermission = Manifest.permission.CAMERA;
if(!hasRecordPermission(readPermission)){
getPermissionRequst(readPermission,"权限申请",
"智能浇水需要您的授权访问相机,并使用扫一扫",REQUEST_EVENT_CODE_10001);
}else{
scanQrcode();
}
break;
case R.id.img_add:
goTo(mContext, AddDeviceActivity.class,null);
break;
}
}
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;
}
}
});
}
private void setupRecyclerView() {
deviceAdapter = new DeviceAdapter(mContext,R.layout.index_device_list_item,devList);
viewBinding.rvDevices.setAdapter(deviceAdapter);
deviceAdapter.setOnItemClickListener((adapter, view, position) -> {
goTo(mContext, DeviceControlActivity.class,null);
});
}
@Override
public void onDestroyView() {
super.onDestroyView();
}
@Override
public void onNetChange(int netModel) {
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
hidePermissionDialog();
if (requestCode == REQUEST_EVENT_CODE_10001) {
scanQrcode();
}
}
}

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