first
This commit is contained in:
119
app/src/main/java/com/ckkj/water/AppConfig.java
Normal file
119
app/src/main/java/com/ckkj/water/AppConfig.java
Normal 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=";
|
||||
|
||||
}
|
||||
118
app/src/main/java/com/ckkj/water/ConstantUtil.java
Normal file
118
app/src/main/java/com/ckkj/water/ConstantUtil.java
Normal file
@@ -0,0 +1,118 @@
|
||||
package com.ckkj.water;
|
||||
|
||||
/**
|
||||
* @author messi.mo
|
||||
* date:2019/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;
|
||||
|
||||
|
||||
|
||||
}
|
||||
62
app/src/main/java/com/ckkj/water/EventMessage.java
Normal file
62
app/src/main/java/com/ckkj/water/EventMessage.java
Normal 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;
|
||||
}
|
||||
}
|
||||
187
app/src/main/java/com/ckkj/water/MyApplication.java
Normal file
187
app/src/main/java/com/ckkj/water/MyApplication.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
1116
app/src/main/java/com/ckkj/water/base/BaseActivity.java
Normal file
1116
app/src/main/java/com/ckkj/water/base/BaseActivity.java
Normal file
File diff suppressed because it is too large
Load Diff
440
app/src/main/java/com/ckkj/water/base/BaseActivityNoP.java
Normal file
440
app/src/main/java/com/ckkj/water/base/BaseActivityNoP.java
Normal 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() {
|
||||
|
||||
}
|
||||
}
|
||||
890
app/src/main/java/com/ckkj/water/base/BaseFragment.java
Normal file
890
app/src/main/java/com/ckkj/water/base/BaseFragment.java
Normal 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中重写,这里可以留空或者提供默认实现
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
31
app/src/main/java/com/ckkj/water/base/BasePresenter.java
Normal file
31
app/src/main/java/com/ckkj/water/base/BasePresenter.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
21
app/src/main/java/com/ckkj/water/base/IPresenter.java
Normal file
21
app/src/main/java/com/ckkj/water/base/IPresenter.java
Normal 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();
|
||||
}
|
||||
47
app/src/main/java/com/ckkj/water/base/IView.java
Normal file
47
app/src/main/java/com/ckkj/water/base/IView.java
Normal 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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
279
app/src/main/java/com/ckkj/water/base/entity/UserInfoEntity.java
Normal file
279
app/src/main/java/com/ckkj/water/base/entity/UserInfoEntity.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
900
app/src/main/java/com/ckkj/water/chat/ChatFragment.java
Normal file
900
app/src/main/java/com/ckkj/water/chat/ChatFragment.java
Normal 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) {
|
||||
|
||||
}
|
||||
}
|
||||
225
app/src/main/java/com/ckkj/water/chat/ChatHistoryActivity.java
Normal file
225
app/src/main/java/com/ckkj/water/chat/ChatHistoryActivity.java
Normal 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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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); // 应用背景
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
78
app/src/main/java/com/ckkj/water/chat/mvp/IndexContract.java
Normal file
78
app/src/main/java/com/ckkj/water/chat/mvp/IndexContract.java
Normal 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);
|
||||
}
|
||||
}
|
||||
575
app/src/main/java/com/ckkj/water/chat/mvp/IndexImpl.java
Normal file
575
app/src/main/java/com/ckkj/water/chat/mvp/IndexImpl.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
249
app/src/main/java/com/ckkj/water/chat/mvp/IndexPresenter.java
Normal file
249
app/src/main/java/com/ckkj/water/chat/mvp/IndexPresenter.java
Normal 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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
38
app/src/main/java/com/ckkj/water/custom/CustomFileType.java
Normal file
38
app/src/main/java/com/ckkj/water/custom/CustomFileType.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; // 上边距
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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() {}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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 啊哈哈哈啊哈");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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(); // 重新绘制
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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); // 绘制虚线
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
1716
app/src/main/java/com/ckkj/water/custom/view/LazyViewPager.java
Normal file
1716
app/src/main/java/com/ckkj/water/custom/view/LazyViewPager.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
144
app/src/main/java/com/ckkj/water/custom/view/SideBarLayout.java
Normal file
144
app/src/main/java/com/ckkj/water/custom/view/SideBarLayout.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
155
app/src/main/java/com/ckkj/water/custom/view/SimpleSpinner.java
Normal file
155
app/src/main/java/com/ckkj/water/custom/view/SimpleSpinner.java
Normal 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();
|
||||
}
|
||||
}
|
||||
188
app/src/main/java/com/ckkj/water/device/AddDeviceActivity.java
Normal file
188
app/src/main/java/com/ckkj/water/device/AddDeviceActivity.java
Normal 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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
222
app/src/main/java/com/ckkj/water/device/SelectWifiActivity.java
Normal file
222
app/src/main/java/com/ckkj/water/device/SelectWifiActivity.java
Normal 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) {
|
||||
|
||||
}
|
||||
}
|
||||
69
app/src/main/java/com/ckkj/water/device/WifiListAdapter.java
Normal file
69
app/src/main/java/com/ckkj/water/device/WifiListAdapter.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.ckkj.water.device.mvp;
|
||||
|
||||
public class DeviceImpl implements DeviceContract.DataModel{
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
95
app/src/main/java/com/ckkj/water/dialog/CenterTipDialog.java
Normal file
95
app/src/main/java/com/ckkj/water/dialog/CenterTipDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
201
app/src/main/java/com/ckkj/water/dialog/ContentReportDialog.java
Normal file
201
app/src/main/java/com/ckkj/water/dialog/ContentReportDialog.java
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
227
app/src/main/java/com/ckkj/water/dialog/DialogAppUpdate.java
Normal file
227
app/src/main/java/com/ckkj/water/dialog/DialogAppUpdate.java
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
115
app/src/main/java/com/ckkj/water/dialog/LoadingDialog.java
Normal file
115
app/src/main/java/com/ckkj/water/dialog/LoadingDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
141
app/src/main/java/com/ckkj/water/dialog/PayTypeDialog.java
Normal file
141
app/src/main/java/com/ckkj/water/dialog/PayTypeDialog.java
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
197
app/src/main/java/com/ckkj/water/dialog/ShareQrcodeDialog.java
Normal file
197
app/src/main/java/com/ckkj/water/dialog/ShareQrcodeDialog.java
Normal 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. 保存到 MediaStore(Android 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
203
app/src/main/java/com/ckkj/water/fate/entity/CityDataEntity.java
Normal file
203
app/src/main/java/com/ckkj/water/fate/entity/CityDataEntity.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
56
app/src/main/java/com/ckkj/water/fate/mvp/FateContract.java
Normal file
56
app/src/main/java/com/ckkj/water/fate/mvp/FateContract.java
Normal 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);
|
||||
}
|
||||
}
|
||||
232
app/src/main/java/com/ckkj/water/fate/mvp/FateImpl.java
Normal file
232
app/src/main/java/com/ckkj/water/fate/mvp/FateImpl.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
191
app/src/main/java/com/ckkj/water/fate/mvp/FatePresenter.java
Normal file
191
app/src/main/java/com/ckkj/water/fate/mvp/FatePresenter.java
Normal 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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
758
app/src/main/java/com/ckkj/water/fate/view/FateFragment.java
Normal file
758
app/src/main/java/com/ckkj/water/fate/view/FateFragment.java
Normal 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,"定位获取成功");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
236
app/src/main/java/com/ckkj/water/guide/GuideActivity.java
Normal file
236
app/src/main/java/com/ckkj/water/guide/GuideActivity.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
156
app/src/main/java/com/ckkj/water/guide/LaunchActivity.java
Normal file
156
app/src/main/java/com/ckkj/water/guide/LaunchActivity.java
Normal 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) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
159
app/src/main/java/com/ckkj/water/history/TabHistoryFragment.java
Normal file
159
app/src/main/java/com/ckkj/water/history/TabHistoryFragment.java
Normal 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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.ckkj.water.history.mvp;
|
||||
|
||||
public class HistoryImpl implements HistoryContract.DataModel{
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
151
app/src/main/java/com/ckkj/water/index/IndexFragment.java
Normal file
151
app/src/main/java/com/ckkj/water/index/IndexFragment.java
Normal 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
Reference in New Issue
Block a user