diff --git a/.run/app.run.xml b/.run/app.run.xml new file mode 100644 index 00000000..76af515f --- /dev/null +++ b/.run/app.run.xml @@ -0,0 +1,45 @@ + + + + + \ No newline at end of file diff --git a/app/my-release-key.jks b/app/my-release-key.jks new file mode 100644 index 00000000..ec173e42 Binary files /dev/null and b/app/my-release-key.jks differ diff --git a/app/releas/release/output-metadata.json b/app/releas/release/output-metadata.json new file mode 100644 index 00000000..975d1e36 --- /dev/null +++ b/app/releas/release/output-metadata.json @@ -0,0 +1,37 @@ +{ + "version": 3, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "com.qxcm.qxlive", + "variantName": "releasRelease", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "attributes": [], + "versionCode": 1, + "versionName": "1.0.0.0", + "outputFile": "羽声_1.0.0.0_1.apk" + } + ], + "elementType": "File", + "baselineProfiles": [ + { + "minApi": 28, + "maxApi": 30, + "baselineProfiles": [ + "baselineProfiles/1/羽声_1.0.0.0_1.dm" + ] + }, + { + "minApi": 31, + "maxApi": 2147483647, + "baselineProfiles": [ + "baselineProfiles/0/羽声_1.0.0.0_1.dm" + ] + } + ], + "minSdkVersionForDexing": 24 +} \ No newline at end of file diff --git a/app/src/main/java/com/qxcm/qxlive/AppContext.java b/app/src/main/java/com/qxcm/qxlive/AppContext.java new file mode 100644 index 00000000..b6e8f669 --- /dev/null +++ b/app/src/main/java/com/qxcm/qxlive/AppContext.java @@ -0,0 +1,103 @@ +package com.qxcm.qxlive; + +import com.alibaba.android.arouter.launcher.ARouter; +import com.hjq.toast.ToastUtils; +import com.xscm.moduleutil.base.CommonAppContext; + + +/** + * Created by cxf on 2017/8/3. + */ + +public class AppContext extends CommonAppContext { + + private boolean mBeautyInited; + + @Override + public void onCreate() { + super.onCreate(); + ToastUtils.init(this); + ARouter.init(this); + + /* mqttClient = MyMQTTClient.getInstance(this); + mqttClient.initialize("tcp://81.70.45.221:1883"); + new Thread(() -> { + boolean connected = mqttClient.connect(); + runOnUiThread(() -> { + if (connected) { + } else { + com.blankj.utilcode.util.ToastUtils.showShort("MQTT连接失败"); + } + }); + }).start();*/ + +// ToastUtils.setInterceptor(new IToastInterceptor() { +// @Override +// public boolean intercept(CharSequence charSequence) { +// return !CommonAppContext.getInstance().isFront(); +// } +// }); +// L.setDeBug(BuildConfig.DEBUG); + } + public static void initSdk() { +// CommonAppContext context = CommonAppContext.getInstance(); + +// if (BuildConfig.DEBUG) { +// L.e("应用签名:" + context.getAppSignature()); +// //L.e("facebook散列秘钥------>" + context.getFacebookHashKey()); +// } +// //腾讯云直播鉴权url +// String liveLicenceUrl = "https://license.vod2.myqcloud.com/license/v2/1346816652_1/v_cube.license"; +// //腾讯云直播鉴权key +// String liveKey = "c30f209835056ba00f738a014ca4448a"; +// //腾讯云视频鉴权url +// String ugcLicenceUrl = "https://license.vod2.myqcloud.com/license/v2/1346816652_1/v_cube.license"; +// //腾讯云视频鉴权key +// String ugcKey = "c30f209835056ba00f738a014ca4448a"; +// TXLiveBase.getInstance().setDebug(BuildConfig.DEBUG); +// TXLiveBase.getInstance().setLicence(context, liveLicenceUrl, liveKey, ugcLicenceUrl, ugcKey); +// //初始化腾讯bugly +// CrashReport.initCrashReport(context); +// CrashReport.setAppVersion(context, CommonAppConfig.getInstance().getVersion()); +// //初始化ShareSdk +// MobSDK.init(context); +// MobSDK.submitPolicyGrantResult(true); +// //初始化IM +// ImMessageUtil.getInstance().init(); +// //初始化腾讯TPNS 移动推送 +// TpnsUtil.register(BuildConfig.DEBUG); +// //初始化友盟统计 +// UmengUtil.init(context, BuildConfig.DEBUG); +// //OpenInstall +// OpenInstall.init(context); + + + + } + + /** + * 初始化美狐 + */ + public void initBeautySdk(String beautyAppId, String beautyKey) { +// if (!TextUtils.isEmpty(beautyAppId) && !TextUtils.isEmpty(beautyKey)) { +// if (!mBeautyInited) { +// mBeautyInited = true; +// if (CommonAppConfig.isYunBaoApp()) { +// beautyAppId = DecryptUtil.decrypt(beautyAppId); +// beautyKey = DecryptUtil.decrypt(beautyKey); +// } +// MHSDK.init(this, beautyAppId, beautyKey); +// CommonAppConfig.getInstance().setMhBeautyEnable(true); +// L.e("美狐初始化----AppId--->" + beautyAppId + "---AppKey--->" + beautyKey); +// } +// } else { +// CommonAppConfig.getInstance().setMhBeautyEnable(false); +// } + } + + @Override + public void startInitSdk() { + initSdk(); + } + +} diff --git a/app/src/main/java/com/qxcm/qxlive/LaunchContacter.java b/app/src/main/java/com/qxcm/qxlive/LaunchContacter.java new file mode 100644 index 00000000..f92d468a --- /dev/null +++ b/app/src/main/java/com/qxcm/qxlive/LaunchContacter.java @@ -0,0 +1,20 @@ +package com.xscm.midi; + +import android.app.Activity; + +import com.xscm.moduleutil.activity.IPresenter; +import com.xscm.moduleutil.activity.IView; + +public final class LaunchContacter { + + public interface View extends IView { + + } + + public interface ILoginPre extends IPresenter { + + void oauthLogin(String login_token); + + void address_ip(String address_ip); + } +} diff --git a/app/src/main/java/com/qxcm/qxlive/LaunchPageActivity.java b/app/src/main/java/com/qxcm/qxlive/LaunchPageActivity.java new file mode 100644 index 00000000..de4a7447 --- /dev/null +++ b/app/src/main/java/com/qxcm/qxlive/LaunchPageActivity.java @@ -0,0 +1,191 @@ +package com.qxcm.qxlive; + + +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.PersistableBundle; +import android.util.Log; + +import androidx.annotation.Nullable; + +import com.alibaba.android.arouter.launcher.ARouter; +import com.qxcm.qxlive.databinding.ActivityLaunchPageBinding; +import com.xscm.modulelogin.activity.ImproveInfoActivity; +import com.xscm.moduleutil.activity.BaseAppCompatActivity; +import com.xscm.moduleutil.activity.WebViewActivity; +import com.xscm.moduleutil.base.AppStateListener; +import com.xscm.moduleutil.base.AppStateManager; +import com.xscm.moduleutil.base.CommonAppContext; +import com.xscm.moduleutil.dialog.PolicyDialog; +import com.xscm.moduleutil.utils.ARouteConstants; +import com.xscm.moduleutil.utils.SpUtil; +/** + APP准备启动 + * + * _oo0oo_ + * o8888888o + * 88" . "88 + * (| -_- |) + * 0\ = /0 + * ___/`---'\___ + * .' \\| |// '. + * / \\||| : |||// \ + * / _||||| -卍-|||||- \ + * | | \\\ - /// | | + * | \_| ''\---/'' |_/ | + * \ .-\__ '-' ___/-. / + * ___'. .' /--.--\ `. .'___ + * ."" '< `.___\_<|>_/___.' >' "". + * | | : `- \`.;`\ _ /`;.`/ - ` : | | + * \ \ `_. \_ __\ /__ _/ .-` / / + *=====`-.____`.___ \_____/___.-`___.-'===== + * `=---=' + * + * 佛祖保佑 永无BUG + * 佛曰: + * 写字楼里写字间,写字间里程序员; + * 程序人员写程序,又拿程序换酒钱。 + * 酒醒只在网上坐,酒醉还来网下眠; + * 酒醉酒醒日复日,网上网下年复年。 + * 但愿老死电脑间,不愿鞠躬老板前; + * 奔驰宝马贵者趣,公交自行程序员。 + * 别人笑我忒疯癫,我笑自己命太贱; + * 不见满街漂亮妹,哪个归得程序员? + */ +public class LaunchPageActivity extends BaseAppCompatActivity { + private Handler handler; + private PolicyDialog policyDialog; + private AppStateListener appStateListener; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { + super.onCreate(savedInstanceState, persistentState); + + // 获取Application实例并设置监听器 + CommonAppContext app = (CommonAppContext) getApplication(); + appStateListener = AppStateManager.getInstance(); + app.setAppStateListener(appStateListener); + + if (!isTaskRoot()) { + + if (SpUtil.getUnderagePassword() != null && !SpUtil.getUnderagePassword().isEmpty()) { +// ARouter.getInstance().build(ARouteConstants.H5).withString("url", CommonAppContext.getInstance().getCurrentEnvironment().getH5Url() + "/web/index.html#/pages/feedback/teenage?id=" + SpUtil.getToken()) +// .withString("type", "1").navigation();//type==1:青少年模式 + + Intent intent = new Intent(this, WebViewActivity.class); + intent.putExtra("url", CommonAppContext.getInstance().getCurrentEnvironment().getH5Url() + "/web/index.html#/pages/feedback/teenage?id=" + SpUtil.getToken()); + intent.putExtra("title", "1"); + startActivity(intent); + } else { + // 如果没有设置青少年模式,应该导航到首页 + try { + ARouter.getInstance().build(ARouteConstants.ME).navigation(); + } catch (Exception e) { + Log.e("LaunchPageActivity", "导航到首页失败", e); + } + } + finish(); + return; + } +// if (shouldRestoreRoom()) { +// ARouter.getInstance().build(ARouteConstants.ROOM_DETAILS).withString("form", "首页").withString("roomId", CommonAppContext.getInstance().playId).navigation(); +// } + + } + + private boolean shouldRestoreRoom() { + // 检查是否应该恢复房间: + // 1. 应用有正在播放的房间 + // 2. 应用应该显示房间 + // 3. 应用是从后台恢复的(通过检查 CommonAppContext 状态) + return CommonAppContext.getInstance().isPlaying + && CommonAppContext.getInstance().isShow; + } + + @Override + protected void initData() { + handler = new Handler(); + // 定义一个Runnable + Runnable runnable = new Runnable() { + @Override + public void run() { + initLogin(); + } + }; + if (SpUtil.isAgreePolicy()) { + initLogin(); +// //延迟1.5秒执行 +// handler.postDelayed(runnable, 2500); + } else { + policyDialog = new PolicyDialog(this); + policyDialog.setCancelable(false); + policyDialog.setCanceledOnTouchOutside(false); + policyDialog.setPolicyClickListener(new PolicyDialog.PolicyClickListener() { + @Override + public void policyAgree() { + SpUtil.completeAgreePolicy(); +// CommonAppContext.getInstance().initialization(); + initLogin(); + } + + @Override + public void policyExit() { + finish(); + } + }); + policyDialog.show(); + } + + + } + + @Override + protected void onDestroy() { + // 如果 PolicyDialog 仍在显示,则 dismiss 它 + if (policyDialog != null && policyDialog.isShowing()) { + policyDialog.dismiss(); + policyDialog = null; + } + + // 移除所有待处理的回调以防止内存泄漏 + if (handler != null) { + handler.removeCallbacksAndMessages(null); + } + + super.onDestroy(); + } + + @Override + protected void initView() { + + } + + private void initLogin() { + // 在启动新 Activity 前先关闭对话框 + if (policyDialog != null && policyDialog.isShowing()) { + policyDialog.dismiss(); + policyDialog = null; + } + startActivity(new Intent(this, PasswordLoginActivity.class)); + finish(); + + } + + + @Override + protected int getLayoutId() { + return R.layout.activity_launch_page; + } + + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (!isTaskRoot()) { + finish(); + return; + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/qxcm/qxlive/LaunchPresenter.java b/app/src/main/java/com/qxcm/qxlive/LaunchPresenter.java new file mode 100644 index 00000000..fdad3f6e --- /dev/null +++ b/app/src/main/java/com/qxcm/qxlive/LaunchPresenter.java @@ -0,0 +1,99 @@ +package com.xscm.midi; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import com.blankj.utilcode.util.ToastUtils; +import com.xscm.modulelogin.activity.ImproveInfoActivity; +import com.xscm.modulelogin.activity.SwitchAccountsActivity; +import com.xscm.modulemain.activity.MainActivity; +import com.xscm.moduleutil.base.CommonAppContext; +import com.xscm.moduleutil.bean.UserBean; +import com.xscm.moduleutil.http.BaseObserver; +import com.xscm.moduleutil.presenter.BasePresenter; + +import org.greenrobot.eventbus.EventBus; + +import java.util.List; + +import io.reactivex.disposables.Disposable; + +public class LaunchPresenter extends BasePresenter implements LaunchContacter.ILoginPre { + + public LaunchPresenter(LaunchContacter.View view, Context context) { + super(view, context); + } + + @Override + public void oauthLogin(String login_token) { + api.oauthLogin(login_token, new BaseObserver>() { + + @Override + public void onSubscribe(Disposable d) { + addDisposable(d); + } + + @Override + public void onNext(List userBeans) { + loginSuccess(userBeans); + } + }); + } + + @Override + public void address_ip(String address_ip) { + api.address_ip(address_ip, new BaseObserver() { + @Override + public void onSubscribe(Disposable d) { +// addDisposable(d); + } + + @Override + public void onNext(String s) { + + } + }); + } + + public void loginSuccess(List userBean) { + if (userBean==null) { + ToastUtils.showShort("登录失败请重试"); + return; + } + if (userBean.size()==1) { + + CommonAppContext.getInstance().setUser(userBean.get(0)); + +// PreferencesUtils.putString( CommonAppContext.getInstance(), "mobile", userBean.get()); + + if (isViewAttach()) { +// MvpRef.get().disLoadings(); + } + if (userBean.get(0).getSex() == 0) { + try { + Intent intent = new Intent(com.blankj.utilcode.util.ActivityUtils.getTopActivity(), ImproveInfoActivity.class); + + Bundle bundle = new Bundle(); + bundle.putSerializable("userBean", userBean.get(0)); + intent.putExtras(bundle); + com.blankj.utilcode.util.ActivityUtils.startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + com.blankj.utilcode.util.ActivityUtils.startActivity(MainActivity.class); + } + }else { + Intent intent=new Intent(com.blankj.utilcode.util.ActivityUtils.getTopActivity(), SwitchAccountsActivity.class); + Bundle bundle=new Bundle(); + bundle.putSerializable("userBean", userBean.get(0)); + intent.putExtras(bundle); + com.blankj.utilcode.util.ActivityUtils.startActivity(intent); + + } + EventBus.getDefault().post(userBean); +// EventBus.getDefault().post(new SplashFinishEvent()); +// AppLog.setUserUniqueID(userBean.getUser_id()); // 设置您自己的账号体系ID, 并保证其唯一性 ! + } +} diff --git a/app/src/main/java/com/qxcm/qxlive/PasswordLoginActivity.java b/app/src/main/java/com/qxcm/qxlive/PasswordLoginActivity.java new file mode 100644 index 00000000..6d105f8d --- /dev/null +++ b/app/src/main/java/com/qxcm/qxlive/PasswordLoginActivity.java @@ -0,0 +1,662 @@ +package com.qxcm.qxlive; + +import static android.view.View.VISIBLE; + +import android.content.Intent; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.text.method.PasswordTransformationMethod; +import android.view.Gravity; +import android.view.View; +import android.widget.ImageView; + +import androidx.annotation.Nullable; + +import com.alibaba.fastjson.JSON; +import com.alipay.sdk.app.AuthTask; +import com.blankj.utilcode.util.LogUtils; +import com.blankj.utilcode.util.ThreadUtils; +import com.hjq.toast.ToastUtils; +import com.mobile.auth.gatewayauth.AuthUIConfig; +import com.mobile.auth.gatewayauth.PhoneNumberAuthHelper; +import com.mobile.auth.gatewayauth.PreLoginResultListener; +import com.mobile.auth.gatewayauth.TokenResultListener; +import com.mobile.auth.gatewayauth.model.TokenRet; +import com.qxcm.qxlive.databinding.ActivityPasswordLoginBinding; +import com.xscm.modulelogin.activity.ImproveInfoActivity; +import com.xscm.modulelogin.even.LoginFinishEvent; +import com.xscm.modulelogin.present.LoginContacter; +import com.xscm.modulelogin.present.LoginPresenter; +import com.xscm.modulemain.activity.MainActivity; +import com.xscm.moduleutil.activity.BaseMvpActivity; +import com.xscm.moduleutil.base.CommonAppContext; +import com.xscm.moduleutil.bean.ThemeBean; +import com.xscm.moduleutil.bean.UserBean; +import com.xscm.moduleutil.utils.BarUtils; +import com.xscm.moduleutil.utils.PreferencesUtils; +import com.xscm.moduleutil.utils.logger.Logger; +import com.tencent.mm.opensdk.modelbase.BaseResp; +import com.tencent.mm.opensdk.modelmsg.SendAuth; +import com.tencent.mm.opensdk.openapi.IWXAPI; +import com.tencent.mm.opensdk.openapi.WXAPIFactory; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PasswordLoginActivity extends BaseMvpActivity implements LoginContacter.View, View.OnClickListener { + + private CountDownTimer mTimer; + public String mobile; + private int type;//1:验证码登录2:密码登录 + boolean isPasswordVisible = false; + public PhoneNumberAuthHelper phoneNumberAuthHelper; + private TokenResultListener tokenResultListener; + private boolean canOnePass; + @Override + protected void initData() { + + } + + @Override + protected int getLayoutId() { + return R.layout.activity_password_login; + } + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + // 检查是否已经创建过该Activity + if (!isTaskRoot()) { + Intent intent = getIntent(); + if (intent != null) { + String action = intent.getAction(); + // 如果是从Launcher启动的,并且Activity已经存在,则finish当前实例 + if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && Intent.ACTION_MAIN.equals(action)) { + finish(); + return; + } + } + } + // 新增版本检查逻辑 + checkAppVersion(); + super.onCreate(savedInstanceState); +// EventBus.getDefault().register(this); +// AppLogUtil.reportAppLog(AppLogEvent.A0101); + } + private void checkAppVersion() { + // 获取当前版本号 + int currentVersionCode = 0; + try { + currentVersionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode; + } catch (Exception e) { + e.printStackTrace(); + } + + // 从SharedPreferences中获取上次运行的版本号 + int lastVersionCode = PreferencesUtils.getInt(CommonAppContext.getInstance(), "last_version_code", 0); + + // 如果版本号不同,说明应用已更新 + if (currentVersionCode != lastVersionCode) { + // 保存当前版本号 + PreferencesUtils.putInt(CommonAppContext.getInstance(), "last_version_code", currentVersionCode); + + // 如果不是首次安装,则需要清理任务栈 + if (lastVersionCode != 0) { + clearTaskAndRestart(); + } + } + } + + private void clearTaskAndRestart() { + // 清理所有Activity并重启应用 + Intent intent = new Intent(this, PasswordLoginActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(intent); + finish(); + } + + @Override + protected void onDestroy() { + EventBus.getDefault().unregister(this); + if (phoneNumberAuthHelper!=null) { + phoneNumberAuthHelper.hideLoginLoading(); + //获取成功 dimiss就去登录、登录成功 + phoneNumberAuthHelper.quitLoginPage(); + } + super.onDestroy(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void finishEvent(LoginFinishEvent event) { + finish(); + } + + + @Override + protected void initView() { + super.initView(); + MvpPre.getThemeData(); + initQuickLogin(); + checkOnePass(); + + BarUtils.setStatusBarAlpha(this, 0); + mBinding.edPhone.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) { + setUpLoginBtn(); + } + + @Override + public void afterTextChanged(Editable s) { + + } + }); + mBinding.edPhone.setOnFocusChangeListener(new View. + OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (mBinding.edPhone == null) { + return; + } + if (hasFocus) { + mBinding.relPhone.setSelected(true); + } else { + // 此处为失去焦点时的处理内容 + mBinding.relPhone.setSelected(false); + } + } + }); + mBinding.edPhone.setText(PreferencesUtils.getString(CommonAppContext.getInstance(), "mobile")); + if (!TextUtils.isEmpty(mobile)) { + mBinding.edPhone.setText(mobile); + } + mBinding.tvCodeText.setOnClickListener(this::onClick); + mBinding.flLogin.setOnClickListener(this::onClick); + mBinding.tvYhxy.setOnClickListener(this::onClick); + mBinding.tvYsxy.setOnClickListener(this::onClick); + mBinding.ivZfb.setOnClickListener(this::onClick); + mBinding.ivWeixin.setOnClickListener(this::onClick); + mBinding.tvSendCode.setOnClickListener(this::onClick); + mBinding.ivEye.setOnClickListener(this::onClick); + + if (mBinding.tvCodeText.getText().equals("切换密码登录")){ + type=1; + }else { + type=2; + } + + } + + private void initQuickLogin() { + tokenResultListener = new TokenResultListener() { + @Override + public void onTokenSuccess(String s) { + Logger.e("onTokenSuccess", s); + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + TokenRet tokenRet = null; + try { + tokenRet = JSON.parseObject(s, TokenRet.class); + if (tokenRet != null && ("600000").equals(tokenRet.getCode())) { + + LogUtils.e("@@@",tokenRet.getToken()); + MvpPre.oauthLoginLogin(tokenRet.getToken()); +// phoneNumberAuthHelper.hideLoginLoading(); +// //获取成功 dimiss就去登录、登录成功 +// phoneNumberAuthHelper.quitLoginPage(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + @Override + public void onTokenFailed(String s) { + Logger.e("onTokenFailed", s); + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + phoneNumberAuthHelper.hideLoginLoading(); + phoneNumberAuthHelper.quitLoginPage(); + } + }); + } + }; + + try { + phoneNumberAuthHelper = PhoneNumberAuthHelper.getInstance(getApplicationContext(), null); + phoneNumberAuthHelper.getReporter().setLoggerEnable(true); +// phoneNumberAuthHelper.setAuthSDKInfo("6rdWuz058oq5OahdbFiGEybUcdahd12J83L34Uc7MrPIrxtFG+rXiwDvRcqNvjwbClbbmvMrmxKVkIysFByBsl0Qe9kqd2w8T/nhK5G6eXXlk2V9AjYCieIU+jRnjZBB+Cfechr6rCGJ2aeBARIsXcRPW7wm9WFK9euh5T+v6Pyte68yNaNdcYCll3+U4/uCEog7HygCnMIbAU+kqoPdmn2H+51YOHW+VsnsHd4w1+I3f8Tt0xLIXGM4GWnQueZ5GR46GTWiSYMy8dCIh9SPIMRyC91GosVcfGPMJSdcXqc="); + phoneNumberAuthHelper.setAuthSDKInfo(((CommonAppContext) getApplication()).getCurrentEnvironment().getALI_AUTH_KEY()); + phoneNumberAuthHelper.checkEnvAvailable(2); + + } catch (Throwable ignored) { + Logger.e("initAuthSDK", ignored); + } + } + + + + private void checkOnePass() { + if (!TextUtils.isEmpty(CommonAppContext.getInstance().getToken()) && !TextUtils.isEmpty(CommonAppContext.getInstance().getUser().getTencent_im())) { + isRoot(); + return; + } + showLoadings(); + if (phoneNumberAuthHelper != null) { + phoneNumberAuthHelper.accelerateLoginPage(3 * 1000, new PreLoginResultListener() { + @Override + public void onTokenSuccess(String s) { + Logger.e("onTokenSuccess", s); + canOnePass = true; + isRoot(); + } + + @Override + public void onTokenFailed(String s, String s1) { + Logger.e("onTokenFailed", "错误信息" + s, s1); + isRoot(); + } + }); + } else { + canOnePass = false; + isRoot(); + } + } + + private void isRoot() { + runOnUiThread(new Runnable() { + @Override + public void run() { + disLoadings(); + if (!PasswordLoginActivity.this.isTaskRoot()) { + Intent intent = getIntent(); + if (intent != null) { + String action = intent.getAction(); + if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && Intent.ACTION_MAIN.equals(action)) { + finish(); + } else { + goNextActivity(); + } + } else { + goNextActivity(); + } + } else { + goNextActivity(); + } + } + }); + } + + private void goNextActivity() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + if (isFinishing() || isDestroyed()) { + return; + } + } + if (TextUtils.isEmpty(CommonAppContext.getInstance().getToken()) || TextUtils.isEmpty(CommonAppContext.getInstance().getUser().getTencent_im())) { + Logger.e("SplashEnd", "ARouters.CODE_LOGIN"); + if (canOnePass) { + phoneNumberAuthHelper.setAuthListener(tokenResultListener); + doOnePass(); + } else { + + } + } else { + Logger.e("SplashEnd", "ARouters.MAIN"); + + UserBean userBean = CommonAppContext.getInstance().getUser(); + +// TUILogin.login(getBaseContext(), CommonAppContext.getInstance().getCurrentEnvironment().getSdkAppId(), "u"+userBean.getUser_id(), userBean.getTencent_im(), new TUICallback() { +// @Override +// public void onError(final int code, final String desc) { +// LogUtils.e("@@@",code,"描述:",desc); +// } +// @Override +// public void onSuccess() { +// LogUtils.e("@@@","成功"); +// +// } +// }); + if (userBean.getSex() == 0) { + Intent intent = new Intent(this, ImproveInfoActivity.class); + Bundle bundle = new Bundle(); + bundle.putSerializable("userBean", userBean); + intent.putExtras(bundle); + startActivity(intent); + finish(); + } else { + EventBus.getDefault().post(userBean); + startActivity(new Intent(this, MainActivity.class)); + finish(); + } +// finish(); + } + } + + private void doOnePass() { + AuthUIConfig authUIConfig = new AuthUIConfig.Builder() + //导航栏 + .setNavColor(Color.TRANSPARENT) + .setNavReturnHidden(true) + .setNavHidden(true) + .setNavText("") + .setNavTextColor(Color.BLACK) + .setWebNavColor(Color.TRANSPARENT) + .setWebNavTextColor(Color.BLACK) + .setWebNavReturnImgPath("ic_topbar_back_dark") + //状态栏区 + .setStatusBarColor(Color.TRANSPARENT) + .setLightColor(false) + .setWebViewStatusBarColor(Color.TRANSPARENT) + .setStatusBarUIFlag(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) + //logo区 + .setLogoImgPath("login_log") + .setLogoWidth(142) + .setLogoHeight(142) + .setLogoOffsetY(54) + .setLogoHidden(false) + .setLogoScaleType(ImageView.ScaleType.FIT_XY) + //Slogan + .setSloganText("本机号码") + .setSloganTextColor(Color.parseColor("#A8A8A8")) + .setSloganTextSize(12) + .setSloganOffsetY(236) + //掩码栏 + .setNumberColor(Color.BLACK) + .setNumberSize(30) + .setNumFieldOffsetY(263) + .setNumberLayoutGravity(Gravity.CENTER_HORIZONTAL) + //登录按钮 + .setLogBtnText("一键登录") + .setLogBtnWidth(300) + .setLogBtnHeight(42) + .setLogBtnOffsetY(325) + .setLogBtnTextSize(14) + .setLogBtnTextColor(getResources().getColor(R.color.white)) +// .setLogBtnBackgroundPath("theme_bg") + .setLogBtnBackgroundDrawable(getResources().getDrawable(com.xscm.moduleutil.R.mipmap.login_btn_bg)) + //切换到其他方式 + .setSwitchAccText("其他登录方式") + .setSwitchAccTextColor(Color.parseColor("#333333")) + .setSwitchAccTextSize(12) + .setSwitchOffsetY(390) + //协议栏 + .setAppPrivacyOne("《用户协议》", CommonAppContext.getInstance().getCurrentEnvironment().getServerUrl()+"/api/Page/page_show?id=6") + .setAppPrivacyTwo("《隐私协议》", CommonAppContext.getInstance().getCurrentEnvironment().getServerUrl()+"/api/Page/page_show?id=4") + .setAppPrivacyColor(Color.parseColor("#000000"), Color.parseColor("#22BB79")) + .setPrivacyBefore("登录即代表同意") + .setPrivacyEnd("并授权获得号码") + .setPrivacyTextSize(11) + .setPrivacyAlertContentVerticalMargin(20) + .setPrivacyMargin(39) + .setPrivacyState(true) + .setCheckboxHidden(false) + .setCheckedImgPath("ic_agreement_selected") + .setUncheckedImgPath("ic_agreement_unselect") + .setPrivacyOffsetX(2) + .setVendorPrivacyPrefix("《") + .setVendorPrivacySuffix("》") + .setProtocolAction("com.qxcm.qxlive.PROTOCOL_WEBVIEW")//跳转到自定义的页面展示隐私协议 + .setPackageName("com.qxcm.qxlive") + //全页面属性 + .setAuthPageActIn("in_activity", "out_activity") + .setAuthPageActOut("in_activity", "out_activity") +// .setPageBackgroundPath("log_bj") + .setPageBackgroundDrawable(getResources().getDrawable(com.xscm.moduleutil.R.mipmap.log_bj)) + .create(); + phoneNumberAuthHelper.setAuthUIConfig(authUIConfig); + phoneNumberAuthHelper.getLoginToken(getApplicationContext(), 5000); + } + + @Override + protected LoginPresenter bindPresenter() { + return new LoginPresenter(this, this); + } + + + + @Override + public void showLoadings() { + showLoading(); + } + + @Override + public void disLoadings() { + disLoading(); + } + + private void setUpLoginBtn() { + String text = mBinding.edPhone.getText().toString(); + if (text.length() == 11) { + mBinding.flLogin.setEnabled(true); + mBinding.ivLoginBg.setAlpha(1f); + } else { + mBinding.ivLoginBg.setAlpha(0.3f); + mBinding.flLogin.setEnabled(false); + } + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.tv_code_text) { +// Intent intent = new Intent(this, LoginActivity.class); +// intent.putExtra("mobile", mBinding.edPhone.getText().toString()); +// startActivity(intent); +// finish(); + + if (mBinding.tvCodeText.getText().equals("切换密码登录")){ + mBinding.rlPassCode.setVisibility(VISIBLE); + mBinding.rlCode.setVisibility(View.GONE); + mBinding.tvCodeText.setText("切换验证码登录"); + mBinding.tvLoginText.setText("密码登录"); + type=2; + }else { + mBinding.rlPassCode.setVisibility(View.GONE); + mBinding.rlCode.setVisibility(VISIBLE); + mBinding.tvCodeText.setText("切换密码登录"); + mBinding.tvLoginText.setText("验证码登录"); + type=1; + } + + + } + else if (id == R.id.fl_login) { + if (!mBinding.cbPrivacy.isChecked()) { + ToastUtils.show("请先勾选服务条款"); + return; + } + String phone = mBinding.edPhone.getText().toString().trim(); + if (TextUtils.isEmpty(phone)) { + com.blankj.utilcode.util.ToastUtils.showShort("请输入手机号"); + return; + } + if (type==1) { + String code = mBinding.edPassword.getText().toString().trim(); + if (TextUtils.isEmpty(code)) { + com.blankj.utilcode.util.ToastUtils.showShort("请输入验证码"); + return; + } + MvpPre.login(phone, "", code, 1); + }else if (type==2) { + String password = mBinding.edPasswordCode.getText().toString().trim(); + if (TextUtils.isEmpty(password)) { + com.blankj.utilcode.util.ToastUtils.showShort("请输入密码"); + return; + } + MvpPre.login(phone, password, "", 2); + } + + } else if (id == R.id.tv_yhxy) { + MvpPre.ysxl(); + } else if (id == R.id.tv_ysxy) { + MvpPre.yhxy(); + } else if (id == R.id.iv_zfb) { + if (!mBinding.cbPrivacy.isChecked()) { + ToastUtils.show("请先勾选服务条款"); + return; + } + MvpPre.authorization("zfb"); +// MvpPre.authorization(SHARE_MEDIA.QQ); + } else if (id == R.id.iv_weixin) { + if (!mBinding.cbPrivacy.isChecked()) { + ToastUtils.show("请先勾选服务条款"); + return; + } +// MvpPre.authorization("wx"); + wcLogin(); + } else if (id == R.id.tv_send_code) { + String phone = mBinding.edPhone.getText().toString().trim(); + if (TextUtils.isEmpty(phone)) { + com.blankj.utilcode.util.ToastUtils.showShort("请输入手机号"); + return; + } + sendCodeSuccess(phone); + MvpPre.sendCode(phone, 1); + }else if (id == R.id.iv_eye) { + + if (!isPasswordVisible) { + mBinding.edPassword.setInputType(android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD); + mBinding.ivEye.setImageResource(com.xscm.moduleutil.R.mipmap.eye_visible); // 设置按钮文本为隐藏密码 + } else { + mBinding.edPassword.setInputType(android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD); + mBinding.edPassword.setTransformationMethod(PasswordTransformationMethod.getInstance()); + mBinding.ivEye.setImageResource(com.xscm.moduleutil.R.mipmap.eye_close); // 设置按钮文本为显示密码 + } + mBinding.edPassword.setSelection(mBinding.edPassword.getText().length()); // 将光标移动到文字末尾 + isPasswordVisible = !isPasswordVisible; // 切换状态 + } + } + private void wcLogin() { + //发起登陆请求前先注册微信api + IWXAPI api = WXAPIFactory.createWXAPI(this,CommonAppContext.getInstance().getCurrentEnvironment().getWxAppId(),true); + api.registerApp(CommonAppContext.getInstance().getCurrentEnvironment().getWxAppId()); + if (!api.isWXAppInstalled()){ + //todo 提醒未安装微信 + com.blankj.utilcode.util.ToastUtils.showShort("请安装微信客户端"); + return; + } + //开始发起登陆请求 + final SendAuth.Req req = new SendAuth.Req(); + req.scope = "snsapi_userinfo"; + req.state = "wechat_sdk_demo_test"; + api.sendReq(req); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void loginEvent(BaseResp event) { + if (event.errCode ==BaseResp.ErrCode.ERR_OK){ + SendAuth.Resp authResp = (SendAuth.Resp)event; + LogUtils.e("@@@",authResp.code); + MvpPre.oauthLogin(authResp.code,1); + } + } + private void releaseTimer() { + if (mTimer != null) { + mTimer.cancel(); + mTimer = null; + } + } + + public void sendCodeSuccess(String phoneNumber) { + com.blankj.utilcode.util.ToastUtils.showShort("短信验证码发送成功请注意查收"); + mBinding.tvSendCode.setEnabled(false); + mBinding.tvSendCode.setAlpha(0.5f); + releaseTimer(); + if (mTimer != null) { + mTimer.cancel(); + } + mTimer = new CountDownTimer(60000L, 1000L) { + @Override + public void onTick(long millisUntilFinished) { + if (mBinding.tvSendCode != null) { + mBinding.tvSendCode.setText(String.format("重新发送(%s)", millisUntilFinished / 1000)); + } + } + + @Override + public void onFinish() { + mBinding.tvSendCode.setAlpha(1f); + mBinding.tvSendCode.setEnabled(true); + mBinding.tvSendCode.setText("重新发送"); + } + }; + mTimer.start(); + } + + @Override + public void sendCodeSuccess1(String s) { + LogUtils.e(s); + } + + @Override + public void loginSuccess(UserBean userBean) { + + } + + @Override + public void authorizationSuccess(String s) { + zfbLogin(s); + } + + @Override + public void ysxlSuccess(String s) { + + } + + @Override + public void getThemeData(ThemeBean themeBean) { + + } + + private void zfbLogin(String s) { + LogUtils.e("@@@",s); + CommonAppContext.getInstance(); + if (!CommonAppContext.isAlipayInstalled(this)){ + com.blankj.utilcode.util.ToastUtils.showShort("请安装支付宝客户端"); + return; + } + String authInfo = s; +// String authInfo = "apiname=com.alipay.account.auth&app_id=2021005152631691&app_name=yusheng&auth_type=AUTHACCOUNT&biz_type=openservice&method=alipay.open.auth.sdk.code.get&pid=2088170624624316&product_id=APP_FAST_LOGIN&scope=kuaijie&sign_type=RSA2&target_id=20141225xxxx&sign=fMcp4GtiM6rxSIeFnJCVePJKV43eXrUP86CQgiLhDHH2u%2FdN75eEvmywc2ulkm7qKRetkU9fbVZtJIqFdMJcJ9Yp%2BJI%2FF%2FpESafFR6rB2fRjiQQLGXvxmDGVMjPSxHxVtIqpZy5FDoKUSjQ2%2FILDKpu3%2F%2BtAtm2jRw1rUoMhgt0%3D"; + Runnable authRunnable = new Runnable() { + + @Override + public void run() { + // 构造AuthTask 对象 + AuthTask authTask = new AuthTask(PasswordLoginActivity.this); + // 调用授权接口,获取授权结果 + Map result = authTask.authV2(authInfo, true); + LogUtils.e(result); + if (result.get("resultStatus").equals("9000")){ + Pattern pattern = Pattern.compile("auth_code=([^&]*)"); + Matcher matcher = pattern.matcher(result.get("result")); + + if (matcher.find()) { + String authCode = matcher.group(1); + LogUtils.e("AuthCode", authCode); + MvpPre.oauthLogin(authCode,2); + } + } + } + }; + Thread authThread = new Thread(authRunnable); + authThread.start(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/qxcm/qxlive/presenter/BasePresenter.java b/app/src/main/java/com/qxcm/qxlive/presenter/BasePresenter.java new file mode 100644 index 00000000..4155ddf4 --- /dev/null +++ b/app/src/main/java/com/qxcm/qxlive/presenter/BasePresenter.java @@ -0,0 +1,110 @@ +package com.xscm.midi.presenter; + + +import android.content.Context; + + +import com.xscm.moduleutil.activity.IPresenter; +import com.xscm.moduleutil.activity.IView; + +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; + +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; + +public abstract class BasePresenter implements IPresenter { + protected CompositeDisposable mDisposables = new CompositeDisposable(); +// private RemoteDataSource api; + protected Reference MvpRef; + protected Context mContext; + + @Deprecated + public BasePresenter(V view) { + attachView(view); + } + + public BasePresenter(V view, Context context) { + attachView(view); + mContext = context; + } + + private void attachView(V view) { + MvpRef = new WeakReference(view); + } + + protected V getView() { + if (MvpRef != null) { + return MvpRef.get(); + } + return null; + } + +// protected RemoteDataSource getApi() { +// if (api == null) { +// api = RemoteDataSource.getInstance(); +// } +// return api; +// } + + /** + * 主要用于判断IView的生命周期是否结束,防止出现内存泄露状况 + * + * @return + */ + public boolean isViewAttach() { + return MvpRef != null && MvpRef.get() != null; + } + + @Override + public void detachView() { + cancelRequest(); + if (MvpRef != null) { + MvpRef.clear(); + MvpRef = null; + } +// if (api != null) { +// api = null; +// } + unBindView(); + } + + + public void unBindView() { + if (MvpRef != null) { + MvpRef.clear(); + } + mContext=null; + } + + /** + * 加入订阅对象 + * + * @param disposable + */ + public void addDisposable(Disposable disposable) { + mDisposables.add(disposable); + } + + /** + * 移除订阅对象 + * + * @param disposable + */ + public void removeDisposable(Disposable disposable) { + mDisposables.remove(disposable); + } + + /** + * 取消所有请求 + */ + public void cancelRequest() { + if (mDisposables != null) { + mDisposables.clear(); // clear时网络请求会随即cancel + mDisposables = null; + } + } + + + +} diff --git a/app/src/main/java/com/qxcm/qxlive/wxapi/WXEntryActivity.java b/app/src/main/java/com/qxcm/qxlive/wxapi/WXEntryActivity.java new file mode 100644 index 00000000..bad7147b --- /dev/null +++ b/app/src/main/java/com/qxcm/qxlive/wxapi/WXEntryActivity.java @@ -0,0 +1,233 @@ +package com.xscm.midi.wxapi; + +import android.app.Activity; +import android.os.Bundle; + +import com.blankj.utilcode.util.ToastUtils; +import com.xscm.moduleutil.base.CommonAppContext; +import com.tencent.mm.opensdk.modelbase.BaseReq; +import com.tencent.mm.opensdk.modelbase.BaseResp; +import com.tencent.mm.opensdk.openapi.IWXAPI; +import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler; +import com.tencent.mm.opensdk.openapi.WXAPIFactory; + +import org.greenrobot.eventbus.EventBus; + +public class WXEntryActivity extends Activity implements IWXAPIEventHandler{ +// private static String TAG = "MicroMsg.WXEntryActivity"; +// +// private IWXAPI api; +// private MyHandler handler; +// +// private static class MyHandler extends Handler { +// private final WeakReference wxEntryActivityWeakReference; +// +// public MyHandler(WXEntryActivity wxEntryActivity){ +// wxEntryActivityWeakReference = new WeakReference(wxEntryActivity); +// } +// +// @Override +// public void handleMessage(Message msg) { +// int tag = msg.what; +// switch (tag) { +// case 0: { +// Bundle data = msg.getData(); +// JSONObject json = null; +// try { +// json = new JSONObject(data.getString("result")); +// String openId, accessToken, refreshToken, scope; +// openId = json.getString("openid"); +// accessToken = json.getString("access_token"); +// refreshToken = json.getString("refresh_token"); +// scope = json.getString("scope"); +//// Intent intent = new Intent(wxEntryActivityWeakReference.get(), SendToWXActivity.class); +//// intent.putExtra("openId", openId); +//// intent.putExtra("accessToken", accessToken); +//// intent.putExtra("refreshToken", refreshToken); +//// intent.putExtra("scope", scope); +//// wxEntryActivityWeakReference.get().startActivity(intent); +// } catch (JSONException e) { +// Log.e(TAG, e.getMessage()); +// } +// } +// } +// } +// } +// +// @Override +// public void onCreate(Bundle savedInstanceState) { +// super.onCreate(savedInstanceState); +// +// api = WXAPIFactory.createWXAPI(this, CommonAppContext.getInstance().getCurrentEnvironment().getWxAppId(), false); +// handler = new MyHandler(this); +// +// try { +// Intent intent = getIntent(); +// api.handleIntent(intent, this); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } +// +// @Override +// protected void onNewIntent(Intent intent) { +// super.onNewIntent(intent); +// +// setIntent(intent); +// api.handleIntent(intent, this); +// } +// +// @Override +// public void onReq(BaseReq req) { +// switch (req.getType()) { +// case ConstantsAPI.COMMAND_GETMESSAGE_FROM_WX: +//// goToGetMsg(); +// break; +// case ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX: +//// goToShowMsg((ShowMessageFromWX.Req) req); +// break; +// default: +// break; +// } +// finish(); +// } +// +// @Override +// public void onResp(BaseResp resp) { +// int result = 0; +// +// switch (resp.errCode) { +// case BaseResp.ErrCode.ERR_OK: +//// result = com.qxcm.moduleutil.R.string.errcode_success; +// break; +// case BaseResp.ErrCode.ERR_USER_CANCEL: +//// result = R.string.errcode_cancel; +// break; +// case BaseResp.ErrCode.ERR_AUTH_DENIED: +//// result = R.string.errcode_deny; +// break; +// case BaseResp.ErrCode.ERR_UNSUPPORT: +//// result = R.string.errcode_unsupported; +// break; +// default: +//// result = R.string.errcode_unknown; +// break; +// } +// +// Toast.makeText(this, getString(result) + ", type=" + resp.getType(), Toast.LENGTH_SHORT).show(); +// +// +// if (resp.getType() == ConstantsAPI.COMMAND_SUBSCRIBE_MESSAGE) { +// SubscribeMessage.Resp subscribeMsgResp = (SubscribeMessage.Resp) resp; +// String text = String.format("openid=%s\ntemplate_id=%s\nscene=%d\naction=%s\nreserved=%s", +// subscribeMsgResp.openId, subscribeMsgResp.templateID, subscribeMsgResp.scene, subscribeMsgResp.action, subscribeMsgResp.reserved); +// +// Toast.makeText(this, text, Toast.LENGTH_LONG).show(); +// } +// +// if (resp.getType() == ConstantsAPI.COMMAND_LAUNCH_WX_MINIPROGRAM) { +// WXLaunchMiniProgram.Resp launchMiniProgramResp = (WXLaunchMiniProgram.Resp) resp; +// String text = String.format("openid=%s\nextMsg=%s\nerrStr=%s", +// launchMiniProgramResp.openId, launchMiniProgramResp.extMsg,launchMiniProgramResp.errStr); +// +// Toast.makeText(this, text, Toast.LENGTH_LONG).show(); +// } +// +// if (resp.getType() == ConstantsAPI.COMMAND_OPEN_BUSINESS_VIEW) { +// WXOpenBusinessView.Resp launchMiniProgramResp = (WXOpenBusinessView.Resp) resp; +// String text = String.format("openid=%s\nextMsg=%s\nerrStr=%s\nbusinessType=%s", +// launchMiniProgramResp.openId, launchMiniProgramResp.extMsg,launchMiniProgramResp.errStr,launchMiniProgramResp.businessType); +// +// Toast.makeText(this, text, Toast.LENGTH_LONG).show(); +// } +// +// if (resp.getType() == ConstantsAPI.COMMAND_OPEN_BUSINESS_WEBVIEW) { +// WXOpenBusinessWebview.Resp response = (WXOpenBusinessWebview.Resp) resp; +// String text = String.format("businessType=%d\nresultInfo=%s\nret=%d",response.businessType,response.resultInfo,response.errCode); +// +// Toast.makeText(this, text, Toast.LENGTH_LONG).show(); +// } +// +// if (resp.getType() == ConstantsAPI.COMMAND_SENDAUTH) { +// SendAuth.Resp authResp = (SendAuth.Resp)resp; +// final String code = authResp.code; +//// NetworkUtil.sendWxAPI(handler, String.format("https://api.weixin.qq.com/sns/oauth2/access_token?" + +//// "appid=%s&secret=%s&code=%s&grant_type=authorization_code", "wxd930ea5d5a258f4f", +//// "1d6d1d57a3dd063b36d917bc0b44d964", code), NetworkUtil.GET_TOKEN); +// } +// finish(); +// } +// +//// private void goToGetMsg() { +//// Intent intent = new Intent(this, GetFromWXActivity.class); +//// intent.putExtras(getIntent()); +//// startActivity(intent); +//// finish(); +//// } +//// +//// private void goToShowMsg(ShowMessageFromWX.Req showReq) { +//// WXMediaMessage wxMsg = showReq.message; +//// WXAppExtendObject obj = (WXAppExtendObject) wxMsg.mediaObject; +//// +//// StringBuffer msg = new StringBuffer(); +//// msg.append("description: "); +//// msg.append(wxMsg.description); +//// msg.append("\n"); +//// msg.append("extInfo: "); +//// msg.append(obj.extInfo); +//// msg.append("\n"); +//// msg.append("filePath: "); +//// msg.append(obj.filePath); +//// +//// Intent intent = new Intent(this, ShowFromWXActivity.class); +//// intent.putExtra(Constants.ShowMsgActivity.STitle, wxMsg.title); +//// intent.putExtra(Constants.ShowMsgActivity.SMessage, msg.toString()); +//// intent.putExtra(Constants.ShowMsgActivity.BAThumbData, wxMsg.thumbData); +//// startActivity(intent); +//// finish(); +//// } + + + private final String TAG = this.getClass().getSimpleName(); + public static final String APP_ID = CommonAppContext.getInstance().getCurrentEnvironment().getWxAppId(); + public static final String APP_SECRET = "请自己填写"; + private IWXAPI mApi; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mApi = WXAPIFactory.createWXAPI(this, APP_ID, true); + mApi.handleIntent(this.getIntent(), this); + } + + //微信发送的请求将回调到onReq方法 + @Override + public void onReq(BaseReq baseReq) { + } + + //发送到微信请求的响应结果 + @Override + public void onResp(BaseResp resp) { + switch (resp.errCode) { + case BaseResp.ErrCode.ERR_OK: + //发送成功 + ToastUtils.showShort("发送成功",resp.transaction); + EventBus.getDefault().post(resp); + break; + case BaseResp.ErrCode.ERR_USER_CANCEL: + //发送取消 + ToastUtils.showShort("发送取消",resp); + break; + case BaseResp.ErrCode.ERR_AUTH_DENIED: + ToastUtils.showShort("发送被拒绝",resp); + //发送被拒绝 + break; + default: + //发送返回 + break; + } + finish(); + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/qxcm/qxlive/wxapi/WXPayEntryActivity.java b/app/src/main/java/com/qxcm/qxlive/wxapi/WXPayEntryActivity.java new file mode 100644 index 00000000..d12a12e2 --- /dev/null +++ b/app/src/main/java/com/qxcm/qxlive/wxapi/WXPayEntryActivity.java @@ -0,0 +1,71 @@ +package com.xscm.midi.wxapi; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +import com.blankj.utilcode.util.ToastUtils; +import com.tencent.mm.opensdk.constants.ConstantsAPI; +import com.tencent.mm.opensdk.modelbase.BaseReq; +import com.tencent.mm.opensdk.modelbase.BaseResp; +import com.tencent.mm.opensdk.openapi.IWXAPI; +import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler; +import com.tencent.mm.opensdk.openapi.WXAPIFactory; +import com.xscm.moduleutil.base.CommonAppContext; +import com.xscm.moduleutil.event.PayEvent; + +import org.greenrobot.eventbus.EventBus; + +public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler { + private IWXAPI api; + public static final String APP_ID = CommonAppContext.getInstance().getCurrentEnvironment().getWxAppId(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + api = WXAPIFactory.createWXAPI(this, APP_ID); + api.handleIntent(getIntent(), this); // 必须调用,否则无法接收回调 + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + api.handleIntent(intent, this); + } + + @Override + public void onReq(BaseReq baseReq) { + + } + + @Override + public void onResp(BaseResp resp) { + // 支付结果回调(resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) + if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) { + switch (resp.errCode) { + case BaseResp.ErrCode.ERR_OK: + // 支付成功:这里需要调用后台接口确认支付状态(避免本地判断不可靠) + + break; + case BaseResp.ErrCode.ERR_USER_CANCEL: + checkPayResultFromServer(); + break; + default: + // 支付失败 + checkPayResultFromServer(); + break; + } + finish(); // 处理完后关闭页面 + } + } + + // 关键:必须从后台确认支付状态(不能仅依赖前端回调) + private void checkPayResultFromServer() { + // 调用后台接口,传入订单号查询实际支付状态 + // 用户取消支付 + ToastUtils.showShort("支付取消"); + PayEvent messageEvent = new PayEvent(-2, "支付取消"); + EventBus.getDefault().post(messageEvent); + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_launcher_ad_tip.xml b/app/src/main/res/drawable/bg_launcher_ad_tip.xml new file mode 100644 index 00000000..92970da0 --- /dev/null +++ b/app/src/main/res/drawable/bg_launcher_ad_tip.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_launcher_skip.xml b/app/src/main/res/drawable/bg_launcher_skip.xml new file mode 100644 index 00000000..456bd4be --- /dev/null +++ b/app/src/main/res/drawable/bg_launcher_skip.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_launcher_skip_2.xml b/app/src/main/res/drawable/bg_launcher_skip_2.xml new file mode 100644 index 00000000..411b0805 --- /dev/null +++ b/app/src/main/res/drawable/bg_launcher_skip_2.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_topbar_back_dark.png b/app/src/main/res/drawable/ic_topbar_back_dark.png new file mode 100644 index 00000000..f574ca9a Binary files /dev/null and b/app/src/main/res/drawable/ic_topbar_back_dark.png differ diff --git a/app/src/main/res/drawable/login_log.webp b/app/src/main/res/drawable/login_log.webp new file mode 100644 index 00000000..efe68f9f Binary files /dev/null and b/app/src/main/res/drawable/login_log.webp differ diff --git a/app/src/main/res/layout/activity_launch_page.xml b/app/src/main/res/layout/activity_launch_page.xml new file mode 100644 index 00000000..76372c38 --- /dev/null +++ b/app/src/main/res/layout/activity_launch_page.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_password_login.xml b/app/src/main/res/layout/activity_password_login.xml new file mode 100644 index 00000000..0c7b2f3b --- /dev/null +++ b/app/src/main/res/layout/activity_password_login.xml @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..036d09bc --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round1.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round1.xml new file mode 100644 index 00000000..036d09bc --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round1.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 00000000..61399802 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_app.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_app.webp new file mode 100644 index 00000000..61399802 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_app.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..f4b0153d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 00000000..b1273dbf Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 00000000..82f36a48 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_app.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_app.webp new file mode 100644 index 00000000..82f36a48 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_app.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..e9e8c861 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 00000000..732051d4 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 00000000..c09ebc05 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_app.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_app.webp new file mode 100644 index 00000000..c09ebc05 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_app.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..09bd91c1 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 00000000..936c27cc Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/screen.webp b/app/src/main/res/mipmap-xhdpi/screen.webp new file mode 100644 index 00000000..68135279 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/screen.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 00000000..7849d4b3 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_app.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_app.webp new file mode 100644 index 00000000..7849d4b3 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_app.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..82939eb7 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 00000000..8cceef70 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/screen.webp b/app/src/main/res/mipmap-xxhdpi/screen.webp new file mode 100644 index 00000000..68135279 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/screen.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 00000000..c0315c91 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_app.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_app.webp new file mode 100644 index 00000000..c0315c91 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_app.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..efe68f9f Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 00000000..da87c1ed Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/screen.webp b/app/src/main/res/mipmap-xxxhdpi/screen.webp new file mode 100644 index 00000000..68135279 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/screen.webp differ diff --git a/app/src/main/res/values-en-rUs/strings.xml b/app/src/main/res/values-en-rUs/strings.xml new file mode 100644 index 00000000..ec3d88e6 --- /dev/null +++ b/app/src/main/res/values-en-rUs/strings.xml @@ -0,0 +1,5 @@ + + + Skip + Click to jump to third-party applications + \ No newline at end of file diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100644 index 00000000..1c850379 --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..104ef913 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,32 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + + #ff5878 + @color/gray2 + #00000000 + #282828 + #969696 + #f5f5f5 + #c8c8c8 + #B4B4B4 + #dcdcdc + #fffa37 + #f0cd08 + #FFF34D + #ffdd00 + #646464 + #ff0000 + #FF205E + #169AFF + #e6323232 + #1FC8F8 + #4998F7 + #32A0FF + \ No newline at end of file diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 00000000..c5d5899f --- /dev/null +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..b26f9828 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + + 跳过 + 点击跳转第三方应用 + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 00000000..bcb7b148 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 00000000..fa0f996d --- /dev/null +++ b/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 00000000..9ee9997b --- /dev/null +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/lombok.config b/lombok.config new file mode 100644 index 00000000..81022eac --- /dev/null +++ b/lombok.config @@ -0,0 +1 @@ +lombok.anyConstructor.suppressConstructorProperties=true \ No newline at end of file diff --git a/moduleUtil/src/main/assets/draw_music.mp3 b/moduleUtil/src/main/assets/draw_music.mp3 new file mode 100644 index 00000000..3fe540f5 Binary files /dev/null and b/moduleUtil/src/main/assets/draw_music.mp3 differ diff --git a/moduleUtil/src/main/assets/heart_line_31.svga b/moduleUtil/src/main/assets/heart_line_31.svga new file mode 100644 index 00000000..e0fe8988 Binary files /dev/null and b/moduleUtil/src/main/assets/heart_line_31.svga differ diff --git a/moduleUtil/src/main/assets/xuanz.mp3 b/moduleUtil/src/main/assets/xuanz.mp3 new file mode 100644 index 00000000..448b70e2 Binary files /dev/null and b/moduleUtil/src/main/assets/xuanz.mp3 differ diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/base/AppStateListener.java b/moduleUtil/src/main/java/com/xscm/moduleutil/base/AppStateListener.java new file mode 100644 index 00000000..7c7dc16b --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/base/AppStateListener.java @@ -0,0 +1,24 @@ +package com.xscm.moduleutil.base; + +import android.app.Activity; + +/** + *@author qx + *@data 2025/9/20 + *@description: 模块之间的通讯接口 + */ +public interface AppStateListener { + void onAppForeground(); + void onAppBackground(); + void onRoomActivityCreated(Activity roomActivity); + void onRoomActivityDestroyed(); + boolean isRoomActivityActive(); + void setFloatingWindowVisible(boolean visible); + boolean isFloatingWindowVisible(); + + // 新增方法 + boolean shouldShowSplash(); + void setShouldShowSplash(boolean shouldShow); + boolean isAppInBackground(); + void setAppInBackground(boolean inBackground); +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/base/AppStateManager.java b/moduleUtil/src/main/java/com/xscm/moduleutil/base/AppStateManager.java new file mode 100644 index 00000000..799b2add --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/base/AppStateManager.java @@ -0,0 +1,112 @@ +package com.xscm.moduleutil.base; + +import android.app.Activity; + +import com.xscm.moduleutil.bean.room.RoomInfoResp; + +import java.lang.ref.WeakReference; +/** + *@author qx + *@data 2025/9/20 + *@description: 应用状态管理的单例类 + */ +// 在 common 模块中 +public class AppStateManager implements AppStateListener { + private static AppStateManager instance; + private boolean isAppInBackground = true; + private boolean shouldShowSplash = true; + private WeakReference roomActivityRef; + private boolean isFloatingWindowVisible = false; + private boolean isRoomActivityMinimized = false; + private AppStateManager() { + // 私有构造函数 + } + + public static synchronized AppStateManager getInstance() { + if (instance == null) { + instance = new AppStateManager(); + } + return instance; + } + + @Override + public boolean shouldShowSplash() { + return shouldShowSplash; + } + + @Override + public void setShouldShowSplash(boolean shouldShow) { + this.shouldShowSplash = shouldShow; + } + + @Override + public boolean isAppInBackground() { + return isAppInBackground; + } + + @Override + public void setAppInBackground(boolean inBackground) { + this.isAppInBackground = inBackground; + } + + @Override + public void onRoomActivityCreated(Activity roomActivity) { + roomActivityRef = new WeakReference<>(roomActivity); + } + + @Override + public void onRoomActivityDestroyed() { + roomActivityRef = null; + } + + @Override + public boolean isRoomActivityActive() { + Activity activity = getRoomActivity(); + return activity != null && !activity.isFinishing(); + } + + private Activity getRoomActivity() { + return roomActivityRef != null ? roomActivityRef.get() : null; + } + + @Override + public void setFloatingWindowVisible(boolean visible) { + this.isFloatingWindowVisible = visible; + } + + @Override + public boolean isFloatingWindowVisible() { + return isFloatingWindowVisible; + } + + @Override + public void onAppForeground() { + // 应用进入前台时的处理 + setAppInBackground(false); + } + + @Override + public void onAppBackground() { + // 应用进入后台时的处理 + setAppInBackground(true); + } + + // 新增方法:设置RoomActivity为最小化状态 + public void setRoomActivityMinimized(boolean minimized) { + this.isRoomActivityMinimized = minimized; + } + + // 新增方法:检查RoomActivity是否处于最小化状态 + public boolean isRoomActivityMinimized() { + return isRoomActivityMinimized; + } + private RoomInfoResp roomInfoResp; + public void setRoomInfo(RoomInfoResp roomInfoResp) { + // 处理RoomInfoResp对象 + this.roomInfoResp = roomInfoResp; + } + + public RoomInfoResp getRoomInfo() { + return roomInfoResp; + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/base/RoomManager.java b/moduleUtil/src/main/java/com/xscm/moduleutil/base/RoomManager.java new file mode 100644 index 00000000..ce121943 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/base/RoomManager.java @@ -0,0 +1,543 @@ +package com.xscm.moduleutil.base; + +import static android.app.PendingIntent.getActivity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; + +import com.alibaba.android.arouter.launcher.ARouter; +import com.blankj.utilcode.util.ActivityUtils; +import com.blankj.utilcode.util.LogUtils; +import com.blankj.utilcode.util.ToastUtils; +import com.xscm.moduleutil.bean.room.RoomInfoResp; +import com.xscm.moduleutil.bean.room.RoomOnline; +import com.xscm.moduleutil.bean.room.RoomOnlineBean; +import com.xscm.moduleutil.event.RoomOutEvent; +import com.xscm.moduleutil.http.BaseObserver; +import com.xscm.moduleutil.http.RetrofitClient; +import com.xscm.moduleutil.listener.MessageListenerSingleton; +import com.xscm.moduleutil.rtc.AgoraManager; +import com.xscm.moduleutil.utils.ARouteConstants; +import com.xscm.moduleutil.utils.SpUtil; +import com.xscm.moduleutil.utils.logger.Logger; + +import org.greenrobot.eventbus.EventBus; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import io.reactivex.disposables.Disposable; + +/** + * 房间管理器 + * 统一处理房间数据获取、进入房间和退出房间的逻辑 + */ +public class RoomManager { + private static final String TAG = "RoomManager"; + + private static RoomManager instance; + + // 房间数据缓存 + private Map roomDataCache = new ConcurrentHashMap<>(); + private Map cacheTimestamps = new ConcurrentHashMap<>(); + + // 缓存有效期(5分钟) + private static final long CACHE_DURATION = 5 * 60 * 1000; + + private RoomManager() { + } + + public static synchronized RoomManager getInstance() { + if (instance == null) { + instance = new RoomManager(); + } + return instance; + } + + /** + * 进入房间 - 自动获取房间数据 + * + * @param context 上下文 + * @param roomId 房间ID + */ + public void enterRoom(Context context, String roomId) { + enterRoom(context, roomId, null, null); + } + + /** + * 进入房间 - 使用密码 + * + * @param context 上下文 + * @param roomId 房间ID + * @param password 房间密码 + */ + public void enterRoom(Context context, String roomId, String password) { + enterRoom(context, roomId, password, null); + } + + /** + * 进入房间 - 使用缓存数据 + * + * @param context 上下文 + * @param roomId 房间ID + * @param password 房间密码 + * @param cachedData 缓存的房间数据 + */ + public void enterRoom(Context context, String roomId, String password, RoomInfoResp cachedData) { + if (TextUtils.isEmpty(roomId)) { + ToastUtils.showShort("房间ID不能为空"); + return; + } + + // 检查是否有有效的缓存数据 + RoomInfoResp roomInfo = cachedData != null ? cachedData : getCachedRoomData(roomId); + + if (roomInfo != null) { + // 使用缓存数据直接进入房间 + navigateToRoom(context, roomId, password, roomInfo, false); + } else { + // 获取房间数据后进入房间 + fetchRoomDataAndEnter(context, roomId, password); + } + } + + /** + * 获取房间数据并进入房间 + * + * @param context 上下文 + * @param roomId 房间ID + * @param password 房间密码 + */ + public void fetchRoomDataAndEnter(Context context, String roomId, String password) { + // 显示加载提示 + // 这里可以根据需要添加加载对话框 + if (CommonAppContext.getInstance().isRoomJoininj){ + return; + } + CommonAppContext.getInstance().isRoomJoininj=true; + // 检查是否有有效的缓存数据 +// RoomInfoResp roomInfo = getCachedRoomData(roomId); + // 检查是否是当前房间且用户在线 +// boolean isCurrentRoom = isCurrentRoom(roomId); + if (CommonAppContext.getInstance().playId == null) { + fetchAndJoinRoom(context, roomId, password); + } else { + if (!CommonAppContext.getInstance().playId.equals(roomId)) { + MessageListenerSingleton.getInstance().joinGroup(roomId); + exitRoom(CommonAppContext.getInstance().playId); + CommonAppContext.getInstance().isShow = false; + CommonAppContext.getInstance().isPlaying = false; + CommonAppContext.getInstance().isRoomJoininj=false; + EventBus.getDefault().post(new RoomOutEvent()); + } else if (CommonAppContext.getInstance().lable_id.equals("6")) { + upInfo(context, roomId, password, true, null, true); + return; + } + isUserOnline(context, roomId, password, null); + + } + +// try { +// Thread.sleep(1000); +// } catch (InterruptedException e) { +// Thread.currentThread().interrupt(); +// } + + // 如果是当前房间且用户在线,直接跳转到房间页面,仅更新数据 + + +// // 获取房间数据 +// MessageListenerSingleton.getInstance().joinGroup(roomId); +// // 等待一段时间确保退出完成 +// try { +// Thread.sleep(500); +// } catch (InterruptedException e) { +// Thread.currentThread().interrupt(); +// } +// RetrofitClient.getInstance().roomGetIn(roomId, password, new BaseObserver() { +// +// @Override +// public void onSubscribe(Disposable d) { +// } +// +// @Override +// public void onNext(RoomInfoResp resp) { +// String appId = CommonAppContext.getInstance().getCurrentEnvironment().getSwSdkAppId(); +// String token = resp.getUser_info().getAgora_token(); // 如果启用了鉴权才需要 +// String roomId = resp.getRoom_info().getRoom_id(); // 房间 ID +// String rtm_token=resp.getUser_info().getAgora_rtm_token(); +// SpUtil.setRtmToken(rtm_token); +// int uid = SpUtil.getUserId(); // 0 表示由 Agora 自动生成 UID +// boolean enableMic = false; // 是否开启麦克风 +// boolean enableJs=false; // 是否开启角色 +// if (resp.getUser_info().getPit_number()!=0){ +// enableJs=true; +// } +// LogUtils.e("token",token); +// LogUtils.e("roomId:",roomId); +//// 初始化 Agora 并加入房间 +// AgoraManager.getInstance(context) +// .joinRoom(token, roomId, uid, enableMic,enableJs); +// cacheRoomData(roomId, resp); +// navigateToRoom(context, roomId, password, resp); +// } +// }); + + // 临时实现 - 直接跳转(因为缺少具体的网络请求代码) +// navigateToRoom(context, roomId, password, null); + } + + private void upInfo(Context context, String roomId, String password, boolean isOnline, RoomInfoResp roomInfo, boolean isCurrentRoom) { + + + if (isOnline) { + navigateToRoom(context, roomId, password, roomInfo, isOnline); + } else { +// CommonAppContext.getInstance().isShow = false; +// CommonAppContext.getInstance().isPlaying = false; +// EventBus.getDefault().post(new RoomOutEvent()); +// try { +// Thread.sleep(300); +// } catch (InterruptedException e) { +// Thread.currentThread().interrupt(); +// } + fetchAndJoinRoom(context, roomId, password); + } + + +// if (isCurrentRoom&& isOnline) { +// if (roomInfo != null) { +// navigateToRoom(context, roomId, password, roomInfo); +// } else { +// // 即使在线,如果没有缓存数据,也需要获取数据 +// fetchAndJoinRoom(context, roomId, password); +// } +// return; +// } + + + // 如果有缓存数据且用户在线,使用缓存数据进入房间 +// if (roomInfo != null && isOnline) { +// RetrofitClient.getInstance().postRoomInfo(roomId, new BaseObserver() { +// +// @Override +// public void onSubscribe(Disposable d) { +// +// } +// +// @Override +// public void onNext(RoomInfoResp roomInfoResp) { +//// cacheRoomData(roomId, roomInfo); +// navigateToRoom(context, roomId, password, roomInfoResp); +// } +// }); + +// cacheRoomData(roomId, roomInfo); +// navigateToRoom(context, roomId, password, roomInfo); + return; +// } + + // 其他情况,获取新的房间数据并加入房间 +// fetchAndJoinRoom(context, roomId, password); + } + + /** + * 获取新的房间数据并加入房间 + * + * @param context 上下文 + * @param roomId 房间ID + * @param password 房间密码 + */ + private void fetchAndJoinRoom(Context context, String roomId, String password) { + // 获取房间数据 + + // 等待一段时间确保退出完成 + try { + Thread.sleep(300); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + navigateToRoom(context, roomId, password, null, false); + +// RetrofitClient.getInstance().roomGetIn(roomId, password, new BaseObserver() { +// +// @Override +// public void onSubscribe(Disposable d) { +// } +// +// @Override +// public void onNext(RoomInfoResp resp) { +// String appId = CommonAppContext.getInstance().getCurrentEnvironment().getSwSdkAppId(); +// String token = resp.getUser_info().getAgora_token(); // 如果启用了鉴权才需要 +// String roomId = resp.getRoom_info().getRoom_id(); // 房间 ID +// String rtm_token=resp.getUser_info().getAgora_rtm_token(); +// SpUtil.setRtmToken(rtm_token); +// int uid = SpUtil.getUserId(); // 0 表示由 Agora 自动生成 UID +// boolean enableMic = false; // 是否开启麦克风 +// boolean enableJs=false; // 是否开启角色 +// if (resp.getUser_info().getPit_number()!=0){ +// enableJs=true; +// } +// LogUtils.e("token",token); +// LogUtils.e("roomId:",roomId); +//// 初始化 Agora 并加入房间 +// AgoraManager.getInstance(context) +// .joinRoom(token, roomId, uid, enableMic,enableJs); +// cacheRoomData(roomId, resp); +// navigateToRoom(context, roomId, password, resp); +// } +// }); + } + + /** + * 检查是否是当前房间 + * + * @param roomId 房间ID + * @return true表示是当前房间,false表示不是 + */ + private boolean isCurrentRoom(String roomId) { + // 这里应该实现检查是否是当前房间的逻辑 + // 可以通过检查当前Activity或者通过全局变量等方式实现 + // 目前返回false,需要根据实际需求实现具体逻辑 + + RoomInfoResp roomInfo = getCachedRoomData(roomId); + if (roomInfo != null) { + if (roomInfo.getRoom_info().getRoom_id().equals(roomId)) { + return true; + } else { + return false; + } + } + + return false; + } + + /** + * 跳转到房间页面 + * + * @param context 上下文 + * @param roomId 房间ID + * @param password 房间密码 + * @param roomInfo 房间信息 + */ + private void navigateToRoom(Context context, String roomId, String password, RoomInfoResp roomInfo, boolean isOnline) { + try { + // 构建跳转参数 + Bundle bundle = new Bundle(); + bundle.putString("roomId", roomId); + bundle.putBoolean("isOnline", isOnline); + + if (!TextUtils.isEmpty(password)) { + bundle.putString("password", password); + } + + if (roomInfo != null) { +// bundle.putSerializable("roomInfo", roomInfo); + } + + // 使用ARouter跳转到房间页面 + ARouter.getInstance() + .build(ARouteConstants.ROOM_DETAILS) + .with(bundle) + .navigation(context); + + } catch (Exception e) { + Logger.e(TAG, "跳转房间页面失败: " + e.getMessage()); + } + } + + /** + * 缓存房间数据 + * + * @param roomId 房间ID + * @param roomInfo 房间信息 + */ + public void cacheRoomData(String roomId, RoomInfoResp roomInfo) { + + if (TextUtils.isEmpty(roomId) || roomInfo == null) { + return; + } + // 清除所有现有的缓存数据 + roomDataCache.clear(); + cacheTimestamps.clear(); + roomDataCache.put(roomId, roomInfo); + cacheTimestamps.put(roomId, System.currentTimeMillis()); + } + + /** + * 获取缓存的房间数据 + * + * @param roomId 房间ID + * @return 房间信息,如果缓存无效则返回null + */ + public RoomInfoResp getCachedRoomData(String roomId) { + if (TextUtils.isEmpty(roomId)) { + return null; + } + + Long timestamp = cacheTimestamps.get(roomId); + if (timestamp == null) { + return null; + } + + // 检查缓存是否过期 + if (System.currentTimeMillis() - timestamp > CACHE_DURATION) { + // 缓存过期,清除数据 + roomDataCache.remove(roomId); + cacheTimestamps.remove(roomId); + return null; + } + + return roomDataCache.get(roomId); + } + + /** + * 检查用户是否在线 + * + * @param roomId 房间ID + * @return true表示用户在线,false表示不在线 + */ + private boolean isUserOnline(Context context, String roomId, String password, RoomInfoResp roomInfo) { + // 这里应该实现检查用户是否在线的逻辑 + // 可以通过检查Agora是否还在房间中,或者通过服务端接口查询用户状态等方式实现 + // 目前返回false,需要根据实际需求实现具体逻辑 +// boolean isCurrentRoom=isCurrentRoom(roomId); +// try { +// Thread.sleep(300); +// } catch (InterruptedException e) { +// Thread.currentThread().interrupt(); +// } + final boolean[] isOnline = {false}; + RetrofitClient.getInstance().getRoomOnline(roomId, "1", "50", new BaseObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(RoomOnline roomOnline) { + try { + if (roomOnline != null) { + if (roomOnline.getOn_pit() != null) { + for (RoomOnlineBean roomOnlineBean : roomOnline.getOn_pit()) { + if (roomOnlineBean.getUser_id() == SpUtil.getUserId()) { + isOnline[0] = true; + break; + } + } + } + if (roomOnline.getOff_pit() != null) { + for (RoomOnlineBean roomOnlineBean : roomOnline.getOff_pit()) { + if (roomOnlineBean.getUser_id() == SpUtil.getUserId()) { + isOnline[0] = true; + break; + } + } + } + upInfo(context, roomId, password, isOnline[0], roomInfo, true); + } else { + isOnline[0] = false; + } + } catch (Exception e) { + // 捕获所有可能的异常,避免崩溃 + e.printStackTrace(); + isOnline[0] = false; + // 即使出现异常也继续执行 + upInfo(context, roomId, password, isOnline[0], roomInfo, true); + } + } + }); + return isOnline[0]; + } + + /** + * 清除指定房间的缓存数据 + * + * @param roomId 房间ID + */ + public void clearRoomCache(String roomId) { + if (!TextUtils.isEmpty(roomId)) { + roomDataCache.remove(roomId); + cacheTimestamps.remove(roomId); + } + } + + /** + * 清除所有房间缓存数据 + */ + public void clearAllRoomCache() { + roomDataCache.clear(); + cacheTimestamps.clear(); + } + + /** + * 退出房间 + * + * @param roomId 房间ID + */ + public void exitRoom(String roomId) { + // 清除该房间的缓存数据 + clearRoomCache(roomId); + + // 可以在这里添加其他退出房间的逻辑 + // 例如:通知服务器用户已退出、清理房间相关资源等 + + RetrofitClient.getInstance().quitRoom(roomId, SpUtil.getUserId() + "", new BaseObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(String s) { + + } + }); + + Logger.d(TAG, "退出房间: " + roomId); + } + + /** + * 批量退出房间 + * + * @param roomIds 房间ID列表 + */ + public void exitRooms(String... roomIds) { + if (roomIds != null) { + for (String roomId : roomIds) { + exitRoom(roomId); + } + } + } + + /** + * 获取房间缓存状态 + * + * @param roomId 房间ID + * @return 缓存状态信息 + */ + public String getRoomCacheStatus(String roomId) { + if (TextUtils.isEmpty(roomId)) { + return "无效的房间ID"; + } + + Long timestamp = cacheTimestamps.get(roomId); + if (timestamp == null) { + return "未缓存"; + } + + long elapsed = System.currentTimeMillis() - timestamp; + if (elapsed > CACHE_DURATION) { + return "缓存已过期"; + } + + RoomInfoResp data = roomDataCache.get(roomId); + if (data == null) { + return "缓存数据为空"; + } + + return String.format("已缓存 (%d秒前)", elapsed / 1000); + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/ActivitiesPermission.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/ActivitiesPermission.java new file mode 100644 index 00000000..b613ef5c --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/ActivitiesPermission.java @@ -0,0 +1,14 @@ +package com.xscm.moduleutil.bean; + +import lombok.Data; +/** + * @Description: 首页活动弹窗权限 + * @Author: xscm + * @Date: 2021/9/27 14:05 + */ +@Data +public class ActivitiesPermission { + private int first_charge_permission;//首充权限 1:有 0:无 + private int day_drop_permission;//天降好礼权限 1:有 0:无 + private int n_people_permission;//新人好礼权限 1:有 0:无 +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/BindDetail.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/BindDetail.java new file mode 100644 index 00000000..5810b82b --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/BindDetail.java @@ -0,0 +1,22 @@ +package com.xscm.moduleutil.bean; + +import lombok.Data; +/** + *@author qx + *@data 2025/9/25 + *@description: 绑定详情 + */ +@Data +public class BindDetail { + + private String id; + private String alipay_name;//支付宝姓名 + private String alipay_account;//支付宝账户 + + private String bank_card_number;//银行卡号 + + private String bank_user_name;//姓名 + private String bank_card;//所属行 + private String open_bank;//开户行 + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/GiftAvatarBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/GiftAvatarBean.java new file mode 100644 index 00000000..849f5faf --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/GiftAvatarBean.java @@ -0,0 +1,4 @@ +package com.xscm.moduleutil.bean; + +public class GiftAvatarBean { +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/GiftPackEvent.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/GiftPackEvent.java new file mode 100644 index 00000000..203208c6 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/GiftPackEvent.java @@ -0,0 +1,8 @@ +package com.xscm.moduleutil.bean; + +import lombok.Data; + +@Data +public class GiftPackEvent { + private String bdid; +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/GiftPackListCount.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/GiftPackListCount.java new file mode 100644 index 00000000..51ff27d8 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/GiftPackListCount.java @@ -0,0 +1,13 @@ +package com.xscm.moduleutil.bean; + +import lombok.Data; + +/** + *@author qx + *@data 2025/9/15 + *@description: 背包礼物总价值 + */ +@Data +public class GiftPackListCount { + private String count; +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/MqttXlhEnd.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/MqttXlhEnd.java new file mode 100644 index 00000000..0d32949a --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/MqttXlhEnd.java @@ -0,0 +1,11 @@ +package com.xscm.moduleutil.bean; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class MqttXlhEnd implements Serializable { + private static final long serialVersionUID = 1L; + private String message; +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/PermissionPicBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/PermissionPicBean.java new file mode 100644 index 00000000..d1156ab3 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/PermissionPicBean.java @@ -0,0 +1,17 @@ +package com.xscm.moduleutil.bean; + +import com.stx.xhb.xbanner.entity.SimpleBannerInfo; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class PermissionPicBean extends SimpleBannerInfo { + private int picId; + private int type;//类型 1:首充、2:天降 ;3:新人 + + @Override + public Object getXBannerUrl() { + return picId; + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/RedPackGrab.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/RedPackGrab.java new file mode 100644 index 00000000..4d9807c7 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/RedPackGrab.java @@ -0,0 +1,8 @@ +package com.xscm.moduleutil.bean; + +import lombok.Data; + +@Data +public class RedPackGrab { + private int code;//1:正常抢 2:已经抢过了 3:手慢了 +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/RedPacketInfo.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/RedPacketInfo.java new file mode 100644 index 00000000..9c4bd95e --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/RedPacketInfo.java @@ -0,0 +1,52 @@ +package com.xscm.moduleutil.bean; + +import lombok.Data; + +/** + * 红包推送的对象 + */ +@Data +public class RedPacketInfo { + private int id; + private String remark;// 备注 + private String password;// 口令 + private int countdown;//0:立即开抢,其他:倒计时抢 + private String conditions;//条件 + private String total_amount;//红包总金额 + private int room_id;//房间ID + private int type;//红包类型 + private int total_count;//红包数量 + private int coin_type;//币种 + private int user_id;//用户ID + private String nickname;// 昵称 + private String redpacket_id;//红包ID + + private String avatar;//头像 + private String redpacket_time;//红包消失的时间 + private long start_time; + + private boolean isAvailable;//是否可以领取 + + private String left_amount;//33.00", + private int left_count; + private long end_time; + private long createtime; + private String updatetime; + private int is_qiang; + + // 获取剩余时间 + public long remainingTime() { + long needTime = 0; + // 获取当前时间戳(毫秒) + long currentTimeMillis = System.currentTimeMillis() / 1000; + // 计算剩余时间 + needTime = start_time - currentTimeMillis; + return needTime; + } + + // 判断红包是否可以领取 + public boolean canOpenNow() { + return remainingTime() <= 0; + } + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/RedpacketDetail.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/RedpacketDetail.java new file mode 100644 index 00000000..d4a4645c --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/RedpacketDetail.java @@ -0,0 +1,35 @@ +package com.xscm.moduleutil.bean; + +import lombok.Data; + +import java.util.List; + +@Data +public class RedpacketDetail { + private RedPacketInfo redpacket_info; + + private List records; + private MyRecord my_record; + private boolean has_grabbed; + @Data + public static class Records { + private int id; + private int redpacket_id; + private int user_id; + private String nickname; + private String avatar; + private String amount; + private String createtime; + } + + @Data + public static class MyRecord { + private int id; + private int redpacket_id; + private String nickname; + private String user_id; + private String avatar; + private String amount; + private String createtime; + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/RoomUserCharmListBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/RoomUserCharmListBean.java new file mode 100644 index 00000000..7fc4fa72 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/RoomUserCharmListBean.java @@ -0,0 +1,21 @@ +package com.xscm.moduleutil.bean; + +import java.util.List; + +import lombok.Data; + +/** + *@author qx + *@data 2025/9/10 + *@description: 魅力详情列表 + */ +@Data +public class RoomUserCharmListBean { + private int user_id; + private String total_price; + private String nickname; + private String avatar; + private String user_code; + private int charm; + private List icon ; +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/SearchAll.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/SearchAll.java new file mode 100644 index 00000000..8e0ec093 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/SearchAll.java @@ -0,0 +1,11 @@ +package com.xscm.moduleutil.bean; + +import java.util.List; + +import lombok.Data; + +@Data +public class SearchAll { + private List rooms; + private List users; +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/XLHBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/XLHBean.java new file mode 100644 index 00000000..896c9af7 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/XLHBean.java @@ -0,0 +1,26 @@ +package com.xscm.moduleutil.bean; + +import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean; +import lombok.Data; + +import java.io.Serializable; + +/** + *@author qx + *@data 2025/9/2 + *@description: 巡乐会开始后推送的信息 + */ +@Data +public class XLHBean implements Serializable { + private static final long serialVersionUID = 1L; + private String text; + private String room_id; + + private int from_type ;//100:巡乐会进度更新 101:巡乐会即将开始 102:巡乐会已经开始 103:巡乐会有人锁定了礼物 104:巡乐会结束落包 + private BlindBoxBean.XlhData xlh_data; + private UserInfo FromUserInfo; + private String end_time; + private BlindBoxBean.xlhUser room_user; + private String gift_num; + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/blindboxwheel/BlindBoxBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/blindboxwheel/BlindBoxBean.java new file mode 100644 index 00000000..ec7b2885 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/blindboxwheel/BlindBoxBean.java @@ -0,0 +1,164 @@ +package com.xscm.moduleutil.bean.blindboxwheel; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.xscm.moduleutil.bean.GiftBean; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import lombok.Data; + +/** + *@author qx + *@data 2025/8/27 + *@description: 获取活动礼物列表 + */ +@Data +public class BlindBoxBean { + private String title; + private String rule_url; + private String rule; + private int box_price ;///每一次抽奖的价格 + private String xlh_end_time;///巡乐会结束时间 + private int is_xlh; ///是否开启巡乐会 0 关闭 1 开启 + private Object xlh_data; + private List gift_list; + private String end_time;//巡乐会结束时间 + + private GiveGift give_homeowner_gift;//房主礼物 + private GiveGift locking_gift;//锁定礼物 + + + private xlhUser xlh_user;//巡乐会中奖用户 + private xlhUser homeowner_user;//房主信息 + + public boolean isXlhDataArray() { + return xlh_data instanceof JsonArray || xlh_data instanceof List; + } + + public boolean isXlhDataObject() { + return xlh_data instanceof JsonObject || xlh_data instanceof Map || xlh_data instanceof XlhData; + } + + public List getXlhDataAsList() { + if (isXlhDataArray()) { + // 转换为List + return (List) xlh_data; + } + return new ArrayList<>(); + } + + public XlhData getXlhDataAsObject() { + if (isXlhDataObject()) { + // 如果已经是XlhData类型,直接返回 + if (xlh_data instanceof XlhData) { + return (XlhData) xlh_data; + } + // 如果是Map类型(Gson解析后的LinkedTreeMap),手动转换 + else if (xlh_data instanceof Map) { + Map map = (Map) xlh_data; + XlhData xlhData = new XlhData(); + + // 安全地转换各个字段 + Object waitingStartNum = map.get("waiting_start_num"); + if (waitingStartNum != null) { + xlhData.setWaiting_start_num(waitingStartNum.toString()); + } + + Object startNum = map.get("start_num"); + if (startNum != null) { + xlhData.setStart_num(startNum.toString()); + } + + Object currentNum = map.get("current_num"); + if (currentNum != null) { + if (currentNum instanceof Number) { + xlhData.setCurrent_num(((Number) currentNum).intValue()); + } else { + try { + xlhData.setCurrent_num(Integer.parseInt(currentNum.toString())); + } catch (NumberFormatException e) { + xlhData.setCurrent_num(0); + } + } + } + + Object status = map.get("status"); + if (status != null) { + if (status instanceof Number) { + xlhData.setStatus(((Number) status).intValue()); + } else { + try { + xlhData.setStatus(Integer.parseInt(status.toString())); + } catch (NumberFormatException e) { + xlhData.setStatus(0); + } + } + } + Object endTime = map.get("end_time"); + if (endTime != null) { + if (endTime instanceof String){ + xlhData.setEnd_time(endTime.toString()); + }else { + xlhData.setEnd_time(endTime.toString()); + } + } + + return xlhData; + } + // 如果是JsonObject,也需要转换 + else if (xlh_data instanceof JsonObject) { + JsonObject jsonObject = (JsonObject) xlh_data; + XlhData xlhData = new XlhData(); + + if (jsonObject.has("waiting_start_num")) { + xlhData.setWaiting_start_num(jsonObject.get("waiting_start_num").getAsString()); + } + + if (jsonObject.has("start_num")) { + xlhData.setStart_num(jsonObject.get("start_num").getAsString()); + } + + if (jsonObject.has("current_num")) { + xlhData.setCurrent_num(jsonObject.get("current_num").getAsInt()); + } + + if (jsonObject.has("status")) { + xlhData.setStatus(jsonObject.get("status").getAsInt()); + } + if (jsonObject.has("end_time")){ + xlhData.setEnd_time(jsonObject.get("end_time").getAsString()); + } + + return xlhData; + } + } + return null; + } + @Data + public static class XlhData { + private String waiting_start_num;//等待开始需要达到的次数 + private String start_num;//巡乐会开启需要达到的次数 + private int current_num;//当前已抽奖次数 + private int status; + private String end_time; + } + @Data + public static class GiveGift { + private int gift_id; + private String gift_name; + private String base_image; + private String gift_num; + private String gift_price; + } + + @Data + public static class xlhUser { + private String user_id; + private String nickname; + private String avatar; + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/blindboxwheel/BlindReslutBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/blindboxwheel/BlindReslutBean.java new file mode 100644 index 00000000..f59d4877 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/blindboxwheel/BlindReslutBean.java @@ -0,0 +1,23 @@ +package com.xscm.moduleutil.bean.blindboxwheel; + +import java.util.List; + +import lombok.Data; + +/** + * @author qx + * @data 2025/8/27 + * @description: 礼物抽奖结果 + */ +@Data +public class BlindReslutBean { + private String blind_box_turntable_id;//本次抽奖标识 Id 效果完成后用这个值推送发放 + private List reslut_list; + + @Data + public class ReslutList { + private int gift_id;//中奖礼物Id + private int count;//中奖礼物数量 + } + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/blindboxwheel/XlhDrawBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/blindboxwheel/XlhDrawBean.java new file mode 100644 index 00000000..b17cde40 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/blindboxwheel/XlhDrawBean.java @@ -0,0 +1,16 @@ +package com.xscm.moduleutil.bean.blindboxwheel; + +import lombok.Data; +/** + *@author qx + *@data 2025/9/4 + *@description: 巡乐会抽奖 + */ +@Data +public class XlhDrawBean { + private int gift_id; + private String gift_name; + private String base_image; + private String gift_price; + private int count ; +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/CloseBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/CloseBean.java new file mode 100644 index 00000000..686d013f --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/CloseBean.java @@ -0,0 +1,19 @@ +package com.xscm.moduleutil.bean.room; + +import lombok.Data; + +// TODO: 2025/3/10 亲密关系 +@Data +public class CloseBean { + private String id;//关系id + private String user_id;//用户id + private String head_picture; //用户头像 + private String nickname;//用户昵称 + private String sex;//性别 + private String contact_end_time;//剩余天数 + private String heart_value;//心动值 + private String friend_config_id;//关系类型id + private String relationship_icon ;//关系类型图标 + + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/Emotion.kt b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/Emotion.kt new file mode 100644 index 00000000..baee14b0 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/Emotion.kt @@ -0,0 +1,6 @@ +package com.xscm.moduleutil.bean.room + +class Emotion { + var type_name: String? = "" + var id: Int? = 0 +} \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/EmotionDeatils.kt b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/EmotionDeatils.kt new file mode 100644 index 00000000..a2007b0c --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/EmotionDeatils.kt @@ -0,0 +1,20 @@ +package com.xscm.moduleutil.bean.room + +data class EmotionDeatils( + var id: Int? = 0, + var pid: Int? = 0, + var type_id: Int? = 0, + var name: String? = "", + var image: String? = "", + var animate_image : String? = "", + var children: List? =ArrayList (), +) + +data class Children( + var id: Int? = 0, + var pid: Int? = 0, + var type_id: Int? = 0, + var name: String? = "", + var image: String? = "", + var animate_image : String? = "", +) \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/FriendUserBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/FriendUserBean.java new file mode 100644 index 00000000..7d1729bd --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/FriendUserBean.java @@ -0,0 +1,27 @@ +package com.xscm.moduleutil.bean.room; + +import java.io.Serializable; + +import lombok.Data; + +/** + *@author qx + *@data 2025/8/24 + *@description: 结束后返回的关系数据, + */ +@Data +public class FriendUserBean implements Serializable { + private int is_cp;//1:卡关系 0:不卡关系 + private String user1_id;//王者位用户1id + private String user1_avatar;//王者位用户1头像 + private String user1_nickname;//王者位用户1昵称 + private String user2_id;//王者位用户2id + private String user2_avatar;//王者位用户2头像 + private String user2_nickname;//王者位用户2昵称 + + private String heart_value;//连线值 + + private String heart_id;//连线值ID + private String relation_name;//什么关系 + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/RedResultBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/RedResultBean.java new file mode 100644 index 00000000..2370c455 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/RedResultBean.java @@ -0,0 +1,27 @@ +package com.xscm.moduleutil.bean.room; + +import lombok.Data; + +import java.util.List; + +/** + * 红包的结果集 + */ +@Data +public class RedResultBean { + private String redUserName;//发布红包的用户名称 + private String redUserAvatar;//发布红包的用户头像 + private String redTitle;//发布红包的备注 + private String redJb;//中奖的金币 + private String redyl;//已经领取的个数 + + private List redList; + + @Data + public static class RedBean { + private String redUserName; + private String redUserAvatar; + private String redNum; + private String redTime; + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/RoomConcernDean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/RoomConcernDean.java new file mode 100644 index 00000000..5a34226b --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/RoomConcernDean.java @@ -0,0 +1,12 @@ +package com.xscm.moduleutil.bean.room; + +import lombok.Data; + +// TODO: 2025/3/12 关系表 +@Data +public class RoomConcernDean { + + private String concernName; + private String concernType; + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/RoomHourBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/RoomHourBean.java new file mode 100644 index 00000000..9c7b0a26 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/bean/room/RoomHourBean.java @@ -0,0 +1,28 @@ +package com.xscm.moduleutil.bean.room; + +import lombok.Data; + +import java.util.List; +/** + *@author qx + *@data 2025/9/29 + *@description:小时榜实体类 + */ +@Data +public class RoomHourBean { + private String time_range; + private List lists; + + @Data + public class RoomListBean { + private String room_id; + private String room_name; + private int label_id; + private String room_cover; + private int total_price; + private String label_icon; + private int xlh_status; + private int redpacket_status;// >0 有红包,=0 没有红包 + } + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/LotteryFragment.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/LotteryFragment.java new file mode 100644 index 00000000..5f8ff0d3 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/LotteryFragment.java @@ -0,0 +1,130 @@ +package com.xscm.moduleutil.dialog; + +import android.os.Bundle; +import android.view.Choreographer; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.scwang.smartrefresh.layout.api.RefreshLayout; +import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.base.BaseMvpDialogFragment; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.bean.WalletBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindReslutBean; +import com.xscm.moduleutil.bean.blindboxwheel.XlhDrawBean; +import com.xscm.moduleutil.databinding.DialogNewRankingXlhFragmentBinding; +import com.xscm.moduleutil.databinding.FframentDataBinding; +import com.xscm.moduleutil.dialog.giftLottery.GiftLotteryContacts; +import com.xscm.moduleutil.dialog.giftLottery.GiftLotteryPresenter; +import com.xscm.moduleutil.dialog.giftLottery.GiftRecordAdapte; +import com.xscm.moduleutil.dialog.giftLottery.NewGiftRecordAdapte; + +import java.util.List; + +public class LotteryFragment extends BaseMvpDialogFragment implements GiftLotteryContacts.View { + private int page=1; + private String roomId; + private int type=-1; + private GiftRecordAdapte giftRecordAdapte; + + @Override + protected GiftLotteryPresenter bindPresenter() { + return new GiftLotteryPresenter(this,getSelfActivity()); + } + public static LotteryFragment newInstance(String giftBagId,int type) { + Bundle args = new Bundle(); + LotteryFragment fragment = new LotteryFragment(); + args.putString("roomId", giftBagId); + args.putInt("type",type); + fragment.setArguments(args); + return fragment; + } + + @Override + protected void initData() { + roomId = getArguments().getString("roomId"); + type = getArguments().getInt("type"); + MvpPre.xlhAllRecord(roomId, "1", "20",type); + } + + @Override + protected void initView() { + + mBinding.smartRefreshLayout.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onRefresh(@NonNull RefreshLayout refreshLayout) { + page = 1; + MvpPre.xlhAllRecord(roomId, page+"", "20",type); + + } + + @Override + public void onLoadMore(@NonNull RefreshLayout refreshLayout) { + page++; + MvpPre.xlhAllRecord(roomId, page+"", "20",type); + } + }); + + + giftRecordAdapte=new GiftRecordAdapte(); + mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false)); + mBinding.recyclerView.setAdapter(giftRecordAdapte); + } + + + @Override + protected int getLayoutId() { + return R.layout.fframent_data; + } + + @Override + public void getGiftListSuccess(BlindBoxBean blindBoxBean) { + + } + + @Override + public void drawGiftListSuccess(BlindReslutBean blindReslutBean) { + + } + + @Override + public void getMyRecordSuccess(List data) { + + } + + @Override + public void getAllRecordSuccess(List data) { + + if (data != null){ + if (page==1){ + giftRecordAdapte.setNewData(data); + }else { + giftRecordAdapte.addData(data); + } + }else { + if (page == 1) { + giftRecordAdapte.setNewData(null); + } + } + } + + + @Override + public void finishRefreshLoadMore() { + mBinding.smartRefreshLayout.finishRefresh(); + mBinding.smartRefreshLayout.finishLoadMore(); + } + + @Override + public void wallet(WalletBean walletBean) { + + } + + @Override + public void xlhChouSuccess(List data) { + + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/NewPeopleDialog.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/NewPeopleDialog.java new file mode 100644 index 00000000..f05bebaf --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/NewPeopleDialog.java @@ -0,0 +1,368 @@ +package com.xscm.moduleutil.dialog; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Paint; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import com.blankj.utilcode.util.ScreenUtils; +import com.blankj.utilcode.util.ToastUtils; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.adapter.HeavenGiftAdapter; +import com.xscm.moduleutil.bean.BaseListData; +import com.xscm.moduleutil.bean.FirstChargeGiftBean; +import com.xscm.moduleutil.bean.RoonGiftModel; +import com.xscm.moduleutil.color.ThemeableDrawableUtils; +import com.xscm.moduleutil.databinding.DialogNewPeopleBinding; +import com.xscm.moduleutil.http.BaseObserver; +import com.xscm.moduleutil.http.RetrofitClient; +import com.xscm.moduleutil.utils.ColorManager; +import com.xscm.moduleutil.widget.dialog.BaseDialog; +import com.zhpan.bannerview.indicator.DrawableIndicator; +import com.zhpan.indicator.base.IIndicator; +import com.zhpan.indicator.enums.IndicatorSlideMode; + +import io.reactivex.disposables.Disposable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author + * @data + * @description: 新人好礼 + */ +public class NewPeopleDialog extends BaseDialog { + + HeavenGiftAdapter heavenGiftAdapter; + FirstChargeGiftBean firstChargeGiftBean; + private int type; + + public NewPeopleDialog(@NonNull Context context) { + super(context, R.style.BaseDialogStyleH); + } + + @Override + public int getLayoutId() { + return R.layout.dialog_new_people; + } + + @Override + public void initView() { + setCancelable(false); + setCanceledOnTouchOutside(false); + Window window = getWindow(); + window.setLayout((int) (ScreenUtils.getScreenWidth() * 375.f / 375), WindowManager.LayoutParams.WRAP_CONTENT); + mBinding.ivClose.setOnClickListener(v -> dismiss()); + + heavenGiftAdapter = new HeavenGiftAdapter(); + mBinding.bannerViewPager + .setPageMargin(15) + .setAutoPlay(false) + .setRevealWidth(0, 0) + .setIndicatorVisibility(View.VISIBLE) + .setIndicatorView(getVectorDrawableIndicator()) + .setIndicatorSlideMode(IndicatorSlideMode.NORMAL) + .setAdapter(heavenGiftAdapter) + .create(); + + mBinding.rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup radioGroup, int i) { + if (firstChargeGiftBean == null || firstChargeGiftBean.getGift_bag().size() == 0) { + ToastUtils.showShort("暂无礼包"); + return; + } + + if (i == R.id.btn_0) { + List list = new ArrayList<>(); + if (firstChargeGiftBean.getGift_bag().size() > 1) { + mBinding.tvTitle1.setText(firstChargeGiftBean.getGift_bag().get(0).getTitle1()); + mBinding.tvTitle2.setText(firstChargeGiftBean.getGift_bag().get(0).getTitle2()); + mBinding.tvTitle2.setPaintFlags(Paint.STRIKE_THRU_TEXT_FLAG); + mBinding.btn0.setText(firstChargeGiftBean.getGift_bag().get(0).getName()); + list.addAll(firstChargeGiftBean.getGift_bag().get(0).getGift_list()); + mBinding.bannerViewPager.create(baseListData(list, 4)); + } + type = 1; + } else if (i == R.id.btn_1) { + List list = new ArrayList<>(); + if (firstChargeGiftBean.getGift_bag().size() > 2) { + mBinding.tvTitle1.setText(firstChargeGiftBean.getGift_bag().get(1).getTitle1()); + mBinding.tvTitle2.setText(firstChargeGiftBean.getGift_bag().get(1).getTitle2()); + mBinding.tvTitle2.setPaintFlags(Paint.STRIKE_THRU_TEXT_FLAG); + mBinding.btn1.setText(firstChargeGiftBean.getGift_bag().get(1).getName()); + list.addAll(firstChargeGiftBean.getGift_bag().get(1).getGift_list()); + mBinding.bannerViewPager.create(baseListData(list, 4)); + } + type = 2; + } else if (i == R.id.btn_2) { + List list = new ArrayList<>(); + if (firstChargeGiftBean.getGift_bag().size() > 3) { + if (firstChargeGiftBean.getGift_bag().get(2) != null) { + mBinding.tvTitle1.setText(firstChargeGiftBean.getGift_bag().get(2).getTitle1()); + mBinding.tvTitle2.setText(firstChargeGiftBean.getGift_bag().get(2).getTitle2()); + mBinding.tvTitle2.setPaintFlags(Paint.STRIKE_THRU_TEXT_FLAG); + mBinding.btn2.setText(firstChargeGiftBean.getGift_bag().get(2).getName()); + list.addAll(firstChargeGiftBean.getGift_bag().get(2).getGift_list()); + mBinding.bannerViewPager.create(baseListData(list, 4)); + type = 3; + } + } + } else if (i == R.id.btn_3) { + List list = new ArrayList<>(); + if (firstChargeGiftBean.getGift_bag().size() >= 4) { + mBinding.tvTitle1.setText(firstChargeGiftBean.getGift_bag().get(3).getTitle1()); + mBinding.tvTitle2.setText(firstChargeGiftBean.getGift_bag().get(3).getTitle2()); + mBinding.btn3.setText(firstChargeGiftBean.getGift_bag().get(3).getName()); + mBinding.tvTitle2.setPaintFlags(0); // 清除所有绘制标志 + list.addAll(firstChargeGiftBean.getGift_bag().get(3).getGift_list()); + mBinding.bannerViewPager.create(baseListData(list, 4)); + type = 4; + } + } + + } + }); + mBinding.rg.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + + return false; + } + }); + + mBinding.tvInvite.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { +// RechargeDialogFragment.show(roomId, getSupportFragmentManager()); + if (listener != null) { + listener.onFirstChargeConfirmed(firstChargeGiftBean, type); + } + + } + }); + + + } + + public interface OnFirstChargeListener { + void onFirstChargeConfirmed(FirstChargeGiftBean giftBean, int type); + + void onFirstChargeCancelled(); + } + + private OnFirstChargeListener listener; + + // 设置监听器的方法 + public void setOnFirstChargeListener(OnFirstChargeListener listener) { + this.listener = listener; + } + + @Override + public void initData() { + RetrofitClient.getInstance().getNewChargeGift(new BaseObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(FirstChargeGiftBean firstChargeGiftBean) { + if (firstChargeGiftBean != null) { + showGift(firstChargeGiftBean); + } + } + }); + + } + + private List> baseListData(List list, int chunkSize) { + List> baseListData = new ArrayList<>(); + for (int i = 0; i < list.size(); i += chunkSize) { + BaseListData baseListData1 = new BaseListData<>(); + baseListData1.setData(list.subList(i, Math.min(i + chunkSize, list.size()))); + baseListData.add(baseListData1); + } + return baseListData; + } + + private IIndicator getVectorDrawableIndicator() { + int dp6 = getResources().getDimensionPixelOffset(com.xscm.moduleutil.R.dimen.dp_6); + return new DrawableIndicator(getContext()) + .setIndicatorGap(getResources().getDimensionPixelOffset(com.xscm.moduleutil.R.dimen.dp_2_5)) + .setIndicatorDrawable(com.xscm.moduleutil.R.drawable.banner_indicator_nornal, com.xscm.moduleutil.R.drawable.banner_indicator_focus) + .setIndicatorSize(getResources().getDimensionPixelOffset(com.xscm.moduleutil.R.dimen.dp_13), dp6, getResources().getDimensionPixelOffset(com.xscm.moduleutil.R.dimen.dp_13), dp6); + } + + private Resources getResources() { + return getContext().getResources(); + } + + public void showGift(FirstChargeGiftBean firstChargeGiftBean) { + this.firstChargeGiftBean = firstChargeGiftBean; + mBinding.rg.check(R.id.btn_0); + if (firstChargeGiftBean.getGift_bag() != null && firstChargeGiftBean.getGift_bag().size() > 0) { + if (firstChargeGiftBean.getGift_bag().size() >= 0) { + type = 1; + List list = new ArrayList<>(); + mBinding.tvTitle1.setText(firstChargeGiftBean.getGift_bag().get(0).getTitle1()); + mBinding.tvTitle2.setText(firstChargeGiftBean.getGift_bag().get(0).getTitle2()); + mBinding.btn0.setText(firstChargeGiftBean.getGift_bag().get(0).getName()); + list.addAll(firstChargeGiftBean.getGift_bag().get(0).getGift_list()); + mBinding.bannerViewPager.create(baseListData(list, 4)); + + + mBinding.btn1.setText(firstChargeGiftBean.getGift_bag().get(1).getName()); + mBinding.btn2.setText(firstChargeGiftBean.getGift_bag().get(2).getName()); + mBinding.btn3.setText(firstChargeGiftBean.getGift_bag().get(3).getName()); + + initGiftBagButtonStatus(firstChargeGiftBean); + } else if (firstChargeGiftBean.getGift_bag().size() == 2) { +// mBinding.rg.check(R.id.btn_0); +// mBinding.btn1.setVisibility(View.VISIBLE); +// mBinding.btn2.setVisibility(View.INVISIBLE); + } else if (firstChargeGiftBean.getGift_bag().size() == 3) { +// mBinding.rg.check(R.id.btn_0); +// mBinding.btn1.setVisibility(View.VISIBLE); +// mBinding.btn2.setVisibility(View.VISIBLE); + } +// mBinding.rg.check(R.id.btn_0); + } + + } + + private boolean isstatus = true; + + private void initGiftBagButtonStatus(FirstChargeGiftBean firstChargeGiftBean) { + // 1. 准备按钮列表:顺序与gift_bag中的元素顺序一一对应 + List buttonList = Arrays.asList( + mBinding.btn0, + mBinding.btn1, + mBinding.btn2 + // 未来加按钮:mBinding.btn3, mBinding.btn4... + ); + + // 2. 空安全检查:先判断核心对象/列表非空 + if (firstChargeGiftBean != null && firstChargeGiftBean.getGift_bag() != null) { + List giftBagList = firstChargeGiftBean.getGift_bag(); + + // 3. 循环处理每个按钮 + for (int i = 0; i < buttonList.size(); i++) { + RadioButton currentBtn = buttonList.get(i); + // 4. 索引防护:若gift_bag列表长度不足,默认按status=0处理 + int status = (i < giftBagList.size()) ? giftBagList.get(i).getStatus() : 0; + // 检查是否有status=0的情况,如果有则将isStatus设为false + if (status == 0) { + isstatus = false; + } + setButtonStatus(currentBtn, status, i); // 增加索引参数 + } + updateRechargeTextViewStatus(isstatus, 0); + + + } else { + // 5. 兜底逻辑:数据为空时,所有按钮按status=0处理 + for (int i = 0; i < buttonList.size(); i++) { + setButtonStatus(buttonList.get(i), 0, i); + } + } + + } + + /** + * 工具方法:统一设置单个按钮的状态 + * + * @param button 要设置的RadioButton + * @param status 状态值 + * @param index 按钮索引,用于标识不同按钮 + */ + private void setButtonStatus(RadioButton button, int status, int index) { + if (button == null) return; + + // 移除之前的点击监听器,避免重复设置 + button.setOnClickListener(null); + + if (status == 1) { + // 可用状态 + button.setEnabled(true); + // button.setChecked(true); + + // 恢复充值按钮状态 + updateRechargeTextViewStatus(true, index); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + updateRechargeTextViewStatus(true, index); + } + }); + + } else { + // status=0和其他状态:特殊处理 + button.setEnabled(true); // 保持可点击以响应交互 + // button.setChecked(false); + // 设置特殊背景(根据需求修改为你的资源) + button.setBackground(getResources().getDrawable(R.drawable.bf_e9)); + button.setTextColor(getResources().getColor(R.color.colorBlack65)); + updateRechargeTextViewStatus(false, index); + // 添加点击事件 + button.setOnClickListener(v -> { + // 点击时再次确认是status=0状态才处理 + button.setBackground(getResources().getDrawable(R.drawable.banner_indicator_focus)); + // 更新充值按钮状态为不可点击 + updateRechargeTextViewStatus(false, index); + }); + } + } + + + /** + * 检查是否至少有一个元素达标(status == 1) + */ + public static boolean hasAnyQualified(List giftBagList) { + // 空列表处理 + 任意匹配检查 + return giftBagList != null && !giftBagList.isEmpty() + && giftBagList.stream() + .anyMatch(gift -> gift.getStatus() == 1); + } + + /** + * 更新充值TextView的状态 + * + * @param enabled 是否可点击 + * @param index 关联的按钮索引 + */ + private void updateRechargeTextViewStatus(boolean enabled, int index) { + TextView rechargeTv = mBinding.tvInvite; // 假设充值按钮的id是tvRecharge + if (rechargeTv == null) return; + + // 设置是否可点击 + rechargeTv.setEnabled(enabled); + + // 根据状态和索引设置不同背景 + if (enabled) { + ThemeableDrawableUtils.setThemeableRoundedBackground(mBinding.tvInvite, ColorManager.getInstance().getPrimaryColorInt(), 53); + mBinding.tvInvite.setTextColor(ColorManager.getInstance().getButtonColorInt()); + + } else { + + + // 不可点击状态的背景 + ThemeableDrawableUtils.setThemeableRoundedBackground(mBinding.tvInvite, ColorManager.getInstance().getButtonColorInt(), 53); + mBinding.tvInvite.setTextColor(getResources().getColor(R.color.colorBlack65)); + + } + } + +} \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/RoomAuctionWebViewDialog.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/RoomAuctionWebViewDialog.java new file mode 100644 index 00000000..ed1ff088 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/RoomAuctionWebViewDialog.java @@ -0,0 +1,228 @@ +package com.xscm.moduleutil.dialog; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.Color; +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.webkit.JavascriptInterface; +import android.webkit.WebSettings; +import android.webkit.WebViewClient; +import android.widget.Toast; + +import androidx.annotation.NonNull; + +import com.alibaba.android.arouter.launcher.ARouter; +import com.blankj.utilcode.util.LogUtils; +import com.blankj.utilcode.util.ScreenUtils; +import com.tencent.imsdk.v2.V2TIMConversation; +import com.tencent.mm.opensdk.modelbiz.WXOpenCustomerServiceChat; +import com.tencent.mm.opensdk.openapi.IWXAPI; +import com.tencent.mm.opensdk.openapi.WXAPIFactory; +import com.tencent.qcloud.tuicore.TUIConstants; +import com.tencent.qcloud.tuikit.tuichat.classicui.page.TUIC2CChatActivity; +import com.tencent.qcloud.tuikit.tuichat.classicui.page.TUIGroupChatActivity; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.base.CommonAppContext; +import com.xscm.moduleutil.base.RoomManager; +import com.xscm.moduleutil.databinding.DialogRoomAuctionWebviewBinding; +import com.xscm.moduleutil.databinding.WebViewDialogBinding; +import com.xscm.moduleutil.utils.ARouteConstants; +import com.xscm.moduleutil.widget.dialog.BaseDialog; +/** + *@author qx + *@data 2025/9/24 + *@description: 这是拍卖房的规则界面 + */ +public class RoomAuctionWebViewDialog extends BaseDialog { + + String mUrl; + int type;//10:天空之境 11:岁月之城 12:时空之巅 + + public RoomAuctionWebViewDialog(@NonNull Context context, Bundle args) { + super(context, R.style.BaseDialogStyleH); + this.mUrl = args.getString("url"); + this.type = args.getInt("type"); + initData1(); + } + @Override + public void onStart() { + super.onStart(); + if (getWindow() != null) { + // 获取屏幕尺寸 + android.util.DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics(); + // 设置高度为屏幕高度的80% + android.view.WindowManager.LayoutParams params = getWindow().getAttributes(); + params.height = (int) (displayMetrics.heightPixels * 0.9); + params.width = android.view.ViewGroup.LayoutParams.MATCH_PARENT; + getWindow().setAttributes(params); + } + } + @Override + public int getLayoutId() { + return R.layout.dialog_room_auction_webview; + } + + @Override + public void initView() { + setCancelable(true); + setCanceledOnTouchOutside(true); + Window window = getWindow(); + assert window != null; + window.setGravity(Gravity.BOTTOM); + window.setLayout((int) (ScreenUtils.getScreenWidth() * 320.f / 375), WindowManager.LayoutParams.MATCH_PARENT); + mBinding.topBar.setTitle("规则"); + mBinding.topBar.getIvBack().setOnClickListener(v -> dismiss()); + + } + + @Override + public void initData() { + + } + + + public void initData1() { +// WebSettings webSettings = mBinding.webView.getSettings(); +// webSettings.setUseWideViewPort(true); +// webSettings.setLoadWithOverviewMode(true); +// webSettings.setJavaScriptEnabled(true); +// webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); //关闭webview中缓存 +// //增加JSBridge +// mBinding.webView.addJavascriptInterface(new WebAppInterface(getContext()), "Android"); +//// mBinding.webView.addJavascriptInterface(new WebViewBridgeConfig(title), WebViewBridgeConfig.NAME); +// webSettings.setBuiltInZoomControls(false); +// webSettings.setSupportZoom(false); +// webSettings.setDomStorageEnabled(true); +// webSettings.setBlockNetworkImage(false);//解决图片不显示 +// // 启用 WebView 内容的滚动 +// mBinding.webView.setVerticalScrollBarEnabled(true); +// mBinding.webView.setScrollbarFadingEnabled(true); +// webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); +// webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); +// mBinding.webView.setHorizontalScrollBarEnabled(false);//水平不显示 +// mBinding.webView.setVerticalScrollBarEnabled(false); //垂直不显示 +// mBinding.webView.setWebViewClient(new WebViewClient()); +// mBinding.webView.setBackgroundColor(Color.TRANSPARENT); +// mBinding.webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); +// +// mBinding.webView.requestFocus(); +// mBinding.webView.loadUrl(mUrl); + + WebSettings webSettings = mBinding.webView.getSettings(); + webSettings.setUseWideViewPort(true); + webSettings.setLoadWithOverviewMode(true); + webSettings.setJavaScriptEnabled(true); + webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); //关闭webview中缓存 + //增加JSBridge + mBinding.webView.addJavascriptInterface(new WebAppInterface(getContext()), "Android"); +// mBinding.webView.addJavascriptInterface(new WebViewBridgeConfig(title), WebViewBridgeConfig.NAME); + webSettings.setBuiltInZoomControls(false); + webSettings.setSupportZoom(false); + webSettings.setDomStorageEnabled(true); + webSettings.setBlockNetworkImage(false);//解决图片不显示 + webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); + webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); + // 启用 WebView 内容的滚动,但隐藏滚动条 + mBinding.webView.setHorizontalScrollBarEnabled(false);//水平不显示 + mBinding.webView.setVerticalScrollBarEnabled(false); //垂直不显示滚动条 + mBinding.webView.setWebViewClient(new WebViewClient()); + mBinding.webView.setBackgroundColor(Color.TRANSPARENT); + mBinding.webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + + // 确保内容可以滚动 + webSettings.setDomStorageEnabled(true); + + mBinding.webView.requestFocus(); + mBinding.webView.loadUrl(mUrl); + } + + private Resources getResources() { + return getContext().getResources(); + } + + public class WebAppInterface { + Context mContext; + + WebAppInterface(Context c) { + mContext = c; + } + + // 被 H5 调用的方法 + @JavascriptInterface + public void showToast(String toast) { + Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show(); + } + + @JavascriptInterface + public void closeWeb() { + LogUtils.e("value: "); + dismiss(); + } + + @JavascriptInterface + public void customerService() { + String appId = CommonAppContext.getInstance().getCurrentEnvironment().getWxAppId(); // 填移动应用(App)的 AppId + IWXAPI api = WXAPIFactory.createWXAPI(mContext, appId); + +// 判断当前版本是否支持拉起客服会话 + WXOpenCustomerServiceChat.Req req = new WXOpenCustomerServiceChat.Req(); + req.corpId = "ww1de4300858c0b461"; // 企业ID + req.url = "https://work.weixin.qq.com/kfid/kfcb3d23a59c188a0e7"; // 客服URL + api.sendReq(req); + } + + @JavascriptInterface + public void jumpRoomPage(String room_id) { + RoomManager.getInstance().fetchRoomDataAndEnter(getContext(), room_id,""); + +// ARouter.getInstance().build(ARouteConstants.ROOM_DETAILS).withString("form", "首页").withString("roomId", room_id).navigation(); + } + @JavascriptInterface + public void jumpWebPage(String objects) { +// ARouter.getInstance().build(ARouteConstants.USER_HOME_PAGE).navigation(); + ARouter.getInstance().build(ARouteConstants.USER_HOME_PAGE).withString("userId", objects).navigation(); + } + + @JavascriptInterface + public void enterGroupChat(String group_id,String cover,String guild_name) { + Intent intent = new Intent(mContext, TUIGroupChatActivity.class); + intent.putExtra(TUIConstants.TUIChat.CHAT_ID, group_id); + intent.putExtra(TUIConstants.TUIChat.CHAT_TYPE, V2TIMConversation.V2TIM_GROUP); + mContext.startActivity(intent); + } + + @JavascriptInterface + public void chatWithUser(String user_id,String nickname) { + Intent intent = new Intent(mContext, TUIC2CChatActivity.class); + intent.putExtra(TUIConstants.TUIChat.CHAT_ID, user_id); + intent.putExtra(TUIConstants.TUIChat.CHAT_TYPE, V2TIMConversation.V2TIM_C2C); + mContext.startActivity(intent); + } + @JavascriptInterface + public void exchange(){ + ARouter.getInstance().build(ARouteConstants.CURRENCY).navigation(); + + } + + @JavascriptInterface + public void Withdrawal() { + ARouter.getInstance().build(ARouteConstants.WITHDRAWAL_ACTIVITY).navigation(); + } + + @JavascriptInterface + public void enterAuthent() {//实名认证 + ARouter.getInstance().build(ARouteConstants.REAL_NAME_ACTIVITY2).navigation(); + } + + @JavascriptInterface + public void Recharge(){ + ARouter.getInstance().build(ARouteConstants.RECHARGE_ACTIVITY).navigation(); + } + } + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftItemAdapter.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftItemAdapter.java new file mode 100644 index 00000000..c46b15d7 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftItemAdapter.java @@ -0,0 +1,22 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.bean.blindboxwheel.XlhDrawBean; +import com.xscm.moduleutil.utils.ImageUtils; + +public class GiftItemAdapter extends BaseQuickAdapter { + public GiftItemAdapter() { + super(R.layout.item_xlh_gift); + } + + @Override + protected void convert(BaseViewHolder helper, XlhDrawBean item) { + + helper.setText(R.id.tv_gift_name, item.getGift_name()+"x"+item.getCount()); + ImageUtils.loadHeadCC(item.getBase_image(),helper.getView(R.id.gift_img)); + helper.setText(R.id.tv_gift_num, item.getGift_price()); + + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftLottery.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftLottery.java new file mode 100644 index 00000000..7240b6d6 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftLottery.java @@ -0,0 +1,27 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import lombok.Data; + +/** + *@author qx + *@data 2025/8/25 + *@description: 盲盒抽奖的实体类 + */ +@Data +public class GiftLottery { + private String id; + private String icon; + private String number; + private String name; + private String price; + private boolean isSelected; + + public GiftLottery(String id, String icon, String number, String name, String price, boolean isSelected) { + this.id = id; + this.icon = icon; + this.number = number; + this.name = name; + this.price = price; + this.isSelected = isSelected; + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftLotteryAdapter.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftLotteryAdapter.java new file mode 100644 index 00000000..fb0db0b3 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftLotteryAdapter.java @@ -0,0 +1,88 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.os.Handler; +import android.os.Looper; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.Animation; +import android.view.animation.ScaleAnimation; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.bean.GiftBoxBean; +import com.xscm.moduleutil.utils.ImageUtils; + +import java.util.List; +import java.util.Random; + +/** + * @author qx + * @data 2025/8/25 + * @description: 盲盒抽奖展示的视图 + */ +// GiftLotteryAdapter.java +public class GiftLotteryAdapter extends BaseQuickAdapter { + + + public GiftLotteryAdapter() { + super(R.layout.item_gift_lottery); + } + + @Override + protected void convert(BaseViewHolder helper, GiftBean item) { + helper.setText(R.id.tv_gift_time, item.getCreatetime()); + ImageUtils.loadHeadCC(item.getBase_image(),helper.getView(R.id.iv_gift_image)); + // 使用 SpannableString 给 "x4" 设置不同颜色 + TextView giftNameTextView = helper.getView(R.id.gift_name); + TextView nickNameTextView = helper.getView(R.id.tv_user_name); + if (giftNameTextView != null) { + String baseName = item.getGift_name(); + String countText = "x"+item.getCount(); + String fullText = baseName + countText; + + SpannableStringBuilder spannable = new SpannableStringBuilder(fullText); + + // 给 "x4" 部分设置颜色 + spannable.setSpan( + new ForegroundColorSpan(mContext.getResources().getColor(R.color.color_C7BF62)), // 替换为实际颜色 + baseName.length(), + fullText.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ); + + giftNameTextView.setText(spannable); + } + + if (nickNameTextView!=null){ + nickNameTextView.setText(item.getNickname()); + String nickName = "赠予"; + String fullText = nickName + " " + item.getNickname(); + SpannableStringBuilder spannable = new SpannableStringBuilder(fullText); + + // 给 "x4" 部分设置颜色 + spannable.setSpan( + new ForegroundColorSpan(mContext.getResources().getColor(R.color.color_C7BF62)), // 替换为实际颜色 + 0, + nickName.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ); + + nickNameTextView.setText(spannable); + } + + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftLotteryDialogFragment.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftLotteryDialogFragment.java new file mode 100644 index 00000000..20ea95dd --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftLotteryDialogFragment.java @@ -0,0 +1,253 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.scwang.smartrefresh.layout.api.RefreshLayout; +import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.base.BaseMvpDialogFragment; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.bean.WalletBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindReslutBean; +import com.xscm.moduleutil.bean.blindboxwheel.XlhDrawBean; +import com.xscm.moduleutil.databinding.DialogGiftLotteryFragmentBinding; +import com.xscm.moduleutil.widget.pagerecyclerview.PagerGridSnapHelper; + +import java.util.ArrayList; +import java.util.List; + +/** + *@author qx + *@data 2025/8/28 + *@description: 盲盒转盘中奖记录 + */ +public class GiftLotteryDialogFragment extends BaseMvpDialogFragment implements GiftLotteryContacts.View{ + + private int page=1; + private String giftBagId; + private int type=1; + private GiftLotteryAdapter adapter; + private GiftRecordAdapte giftRecordAdapte; + private List data=new ArrayList<>(); + + @Override + protected GiftLotteryPresenter bindPresenter() { + return new GiftLotteryPresenter(this,getSelfActivity()); + } + + public static GiftLotteryDialogFragment newInstance(String giftBagId) { + Bundle args = new Bundle(); + GiftLotteryDialogFragment fragment = new GiftLotteryDialogFragment(); + args.putString("giftBagId", giftBagId); + fragment.setArguments(args); + return fragment; + } + @Nullable + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + dialog.setCancelable(true); + return dialog; + } + + @Override + public void onStart() { + super.onStart(); + Window window = getDialog().getWindow(); + if (window != null) { + // 获取屏幕高度 + android.util.DisplayMetrics displayMetrics = new android.util.DisplayMetrics(); + requireActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + int screenHeight = displayMetrics.heightPixels; + // 设置高度为屏幕高度的100%(全屏) + int heightInPx = (int) (screenHeight * 0.8);; + window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, heightInPx); + window.setBackgroundDrawableResource(android.R.color.transparent); + + // 可选:设置动画样式(从底部弹出) + window.setWindowAnimations(R.style.CommonShowDialogBottom); + } + } + + @Override + protected void initDialogStyle(Window window) { + super.initDialogStyle(window); + window.setGravity(Gravity.BOTTOM); + } + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + giftBagId = getArguments().getString("giftBagId"); + + } + + @Override + protected void initData() { + MvpPre.getMyRecord(giftBagId, "1", "20",type); + + } + + + @Override + protected void initView() { + + if (giftBagId.equals("10")){ + mBinding.clRoot.setBackgroundResource(R.mipmap.tkzj); + mBinding.imJc.setImageResource(R.mipmap.jilu); + }else if (giftBagId.equals("11")){ + mBinding.clRoot.setBackgroundResource(R.mipmap.syzc); + mBinding.imJc.setImageResource(R.mipmap.syzc_jl); + }else if (giftBagId.equals("12")){ + mBinding.clRoot.setBackgroundResource(R.mipmap.skzj); + mBinding.imJc.setImageResource(R.mipmap.skzl_jl); + } + + mBinding.smartRefreshLayout.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onRefresh(@NonNull RefreshLayout refreshLayout) { + page = 1; + MvpPre.getMyRecord(giftBagId, page+"", "20",type); + + } + + @Override + public void onLoadMore(@NonNull RefreshLayout refreshLayout) { + page++; + MvpPre.getMyRecord(giftBagId, page+"", "20",type); + } + }); + + mBinding.textView1.setOnClickListener(this::onClick); + mBinding.textView2.setOnClickListener(this::onClick); + + adapter=new GiftLotteryAdapter(); + giftRecordAdapte=new GiftRecordAdapte(); + +// PagerGridLayoutManager layoutManager = new PagerGridLayoutManager(rows, columns, PagerGridLayoutManager.VERTICAL); + + dianj(1); + } + + private void onClick(View view) { + int id = view.getId(); + if (id==R.id.textView1){ + dianj(1); + }else if (id==R.id.textView2){ + dianj(2); + } + } + public void dianj(int type1){ + if (type1==1) { + GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 3); + + mBinding.recyclerView.setLayoutManager(layoutManager); + mBinding.recyclerView.setOnFlingListener(null); + // 设置滚动辅助工具 + PagerGridSnapHelper pageSnapHelper = new PagerGridSnapHelper(); + pageSnapHelper.attachToRecyclerView(mBinding.recyclerView); + mBinding.recyclerView.setAdapter(adapter); + type=1; + setTextViewStyle(mBinding.textView2, false); + setTextViewStyle(mBinding.textView1, true); + }else if (type1==2){ + mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false)); + mBinding.recyclerView.setAdapter(giftRecordAdapte); + type=2; + setTextViewStyle(mBinding.textView2, true); + setTextViewStyle(mBinding.textView1, false); + } + page=1; + data.clear(); + MvpPre.getMyRecord(giftBagId, page+"", "20",type); + } + + private void setTextViewStyle(TextView textView, boolean isSelected) { + if (isSelected) { + textView.setTextColor(getResources().getColor(R.color.white)); + textView.setTextSize(16); + textView.setBackground(getResources().getDrawable(R.mipmap.tab_dy)); + } else { + textView.setTextColor(getResources().getColor(R.color.color_5B5B5B)); + textView.setTextSize(14); + textView.setBackgroundColor(getResources().getColor(R.color.transparent)); + } + } + + + @Override + protected int getLayoutId() { + return R.layout.dialog_gift_lottery_fragment; + } + + @Override + public void getGiftListSuccess(BlindBoxBean blindBoxBean) { + + } + + @Override + public void drawGiftListSuccess(BlindReslutBean blindReslutBean) { + + } + + @Override + public void getMyRecordSuccess(List data) { + if (data != null){ + if (page==1){ + adapter.setNewData(data); + }else { + adapter.addData(data); + } + }else { + if (page == 1) { + adapter.setNewData(null); + } + } + } + + @Override + public void getAllRecordSuccess(List data) { + + if (data != null){ + if (page==1){ + giftRecordAdapte.setNewData(data); + }else { + giftRecordAdapte.addData(data); + } + }else { + if (page == 1) { + giftRecordAdapte.setNewData(null); + } + } + } + + @Override + public void finishRefreshLoadMore() { + mBinding.smartRefreshLayout.finishRefresh(); + mBinding.smartRefreshLayout.finishLoadMore(); + } + + @Override + public void wallet(WalletBean walletBean) { + + } + + @Override + public void xlhChouSuccess(List data) { + + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftRecordAdapte.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftRecordAdapte.java new file mode 100644 index 00000000..e3a93675 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftRecordAdapte.java @@ -0,0 +1,23 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.utils.ImageUtils; + +public class GiftRecordAdapte extends BaseQuickAdapter { + public GiftRecordAdapte() { + super(R.layout.item_gift_record); + } + + @Override + protected void convert(BaseViewHolder helper, GiftBean item) { + + helper.setText(R.id.tv_user_name, item.getNickname()); + helper.setText(R.id.tv_gift_count_name,"x"+item.getCount()+" "+ item.getGift_name()); + helper.setText(R.id.tv_time, item.getCreatetime()); + ImageUtils.loadHeadCC(item.getBase_image(),helper.getView(R.id.iv_gift_icon)); + + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftRecordAdapter.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftRecordAdapter.java new file mode 100644 index 00000000..4fdef4a5 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftRecordAdapter.java @@ -0,0 +1,46 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import android.widget.TextView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.utils.ImageUtils; + +public class GiftRecordAdapter extends BaseQuickAdapter { + + + public GiftRecordAdapter() { + super(R.layout.item_my_record); + } + + @Override + protected void convert(BaseViewHolder helper, GiftBean item) { + helper.setText(R.id.tv_gift_time, item.getCreatetime()); + ImageUtils.loadHeadCC(item.getBase_image(),helper.getView(R.id.iv_gift_image)); + // 使用 SpannableString 给 "x4" 设置不同颜色 + TextView giftNameTextView = helper.getView(R.id.tv_gift_name); + if (giftNameTextView != null) { + String baseName = item.getGift_name(); + String countText = "x"+item.getCount(); + String fullText = baseName + countText; + + SpannableStringBuilder spannable = new SpannableStringBuilder(fullText); + + // 给 "x4" 部分设置颜色 + spannable.setSpan( + new ForegroundColorSpan(mContext.getResources().getColor(R.color.color_C7BF62)), // 替换为实际颜色 + baseName.length(), + fullText.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ); + + giftNameTextView.setText(spannable); + } + + } +} \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftXlhChouAdapter.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftXlhChouAdapter.java new file mode 100644 index 00000000..6dbaec3a --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/GiftXlhChouAdapter.java @@ -0,0 +1,150 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import android.view.View; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.utils.ImageUtils; + +import java.util.ArrayList; +import java.util.List; + +import lombok.Getter; + +@Getter +public class GiftXlhChouAdapter extends BaseQuickAdapter { + private List giftLists = new ArrayList<>(); + private int selectedPosition = -1; + private static final int LOOP_COUNT = 8; // 循环倍数 + + + public GiftXlhChouAdapter() { + super(R.layout.item_xlh); + } + // 设置数据时创建循环数据 + @Override + public void setNewData(List data) { + this.giftLists = data != null ? data : new ArrayList<>(); + super.setNewData(createLoopData()); + } + + /** + * 创建循环数据 + * @return 循环数据列表 + */ + private List createLoopData() { + List loopData = new ArrayList<>(); + if (giftLists.isEmpty()) { + return loopData; + } + + // 创建足够多的循环数据以实现循环效果 + for (int i = 0; i < LOOP_COUNT; i++) { + loopData.addAll(giftLists); + } + return loopData; + } + + @Override + public int getItemCount() { + // 如果原始数据为空,返回0 + if (giftLists.isEmpty()) { + return 0; + } + // 返回循环数据的数量 + return super.getItemCount(); + } + /** + * 获取实际位置(将循环位置映射到原始数据位置) + * @param position 循环列表中的位置 + * @return 原始数据中的实际位置 + */ + private int getActualPosition(int position) { + if (giftLists.isEmpty()) { + return 0; + } + return position % giftLists.size(); + } + @Override + protected void convert(BaseViewHolder helper, GiftBean item) { + // 获取实际位置 + int actualPosition = getActualPosition(helper.getAdapterPosition()); + GiftBean actualItem = giftLists.get(actualPosition); + + helper.setText(R.id.tv_gift_name, actualItem.getGift_name()); + helper.setText(R.id.tv_gift_pic, actualItem.getGift_price()); + ImageUtils.loadHeadCC(actualItem.getBase_image(), helper.getView(R.id.iv_gift_image)); + // 处理选中状态 + View selectedIcon = helper.getView(R.id.selected_icon); + // 处理选中状态 + if (selectedIcon != null) { + // 检查当前item是否为选中位置 + if (actualPosition == selectedPosition) { + selectedIcon.setVisibility(View.GONE); + helper.setBackgroundRes(R.id.ll_bg,R.mipmap.ke_bg); + + } else { + helper.setBackgroundRes(R.id.ll_bg,R.mipmap.xlh_cj_item); + selectedIcon.setVisibility(View.GONE); + } + } + } + /** + * 设置选中位置并更新UI + * @param position 选中的位置 + */ + public void setSelectedPosition(int position) { + int previousPosition = selectedPosition; + selectedPosition = position; + + if (previousPosition >= 0) { + notifyItemsByActualPosition(previousPosition, false); + } + + if (selectedPosition >= 0) { + notifyItemsByActualPosition(selectedPosition, true); + } + } + /** + * 根据实际位置通知所有匹配的item更新 + * @param actualPosition 原始数据中的位置 + * @param isSelected 是否选中 + */ + private void notifyItemsByActualPosition(int actualPosition, boolean isSelected) { + if (giftLists.isEmpty() || actualPosition >= giftLists.size()) { + return; + } + + // 通知所有匹配该实际位置的item更新 + for (int i = 0; i < getItemCount(); i++) { + if (getActualPosition(i) == actualPosition) { + notifyItemChanged(i); + } + } + } + /** + * 清除选中状态 + */ + public void clearSelection() { + int previousPosition = selectedPosition; + selectedPosition = -1; + + if (previousPosition >= 0) { + notifyItemsByActualPosition(previousPosition, false); + } + } + + /** + * 获取原始数据大小 + * @return 原始数据大小 + */ + public int getOriginalDataSize() { + List loopData = new ArrayList<>(); + for (int i = 0; i < LOOP_COUNT; i++) { + loopData.addAll(giftLists); + } + return loopData.size(); + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/LuckyFragment.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/LuckyFragment.java new file mode 100644 index 00000000..cc40a300 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/LuckyFragment.java @@ -0,0 +1,124 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.scwang.smartrefresh.layout.api.RefreshLayout; +import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.base.BaseMvpDialogFragment; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.bean.WalletBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindReslutBean; +import com.xscm.moduleutil.bean.blindboxwheel.XlhDrawBean; +import com.xscm.moduleutil.databinding.FframentDataBinding; + +import java.util.List; + +public class LuckyFragment extends BaseMvpDialogFragment implements GiftLotteryContacts.View { + private int page=1; + private String roomId; + private int type=-1; + private NewGiftRecordAdapte giftRecordAdapte; + + @Override + protected GiftLotteryPresenter bindPresenter() { + return new GiftLotteryPresenter(this,getSelfActivity()); + } + public static LuckyFragment newInstance(String giftBagId, int type) { + Bundle args = new Bundle(); + LuckyFragment fragment = new LuckyFragment(); + args.putString("roomId", giftBagId); + args.putInt("type",type); + fragment.setArguments(args); + return fragment; + } + + @Override + protected void initData() { + roomId = getArguments().getString("roomId"); + type = getArguments().getInt("type"); + MvpPre.xlhAllRecord(roomId, "1", "20",type); + } + + @Override + protected void initView() { + + mBinding.smartRefreshLayout.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onRefresh(@NonNull RefreshLayout refreshLayout) { + page = 1; + MvpPre.xlhAllRecord(roomId, page+"", "20",type); + + } + + @Override + public void onLoadMore(@NonNull RefreshLayout refreshLayout) { + page++; + MvpPre.xlhAllRecord(roomId, page+"", "20",type); + } + }); + + + giftRecordAdapte=new NewGiftRecordAdapte(); + mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false)); + mBinding.recyclerView.setAdapter(giftRecordAdapte); + } + + + @Override + protected int getLayoutId() { + return R.layout.fframent_data; + } + + @Override + public void getGiftListSuccess(BlindBoxBean blindBoxBean) { + + } + + @Override + public void drawGiftListSuccess(BlindReslutBean blindReslutBean) { + + } + + @Override + public void getMyRecordSuccess(List data) { + + } + + @Override + public void getAllRecordSuccess(List data) { + + if (data != null){ + if (page==1){ + giftRecordAdapte.setNewData(data); + }else { + giftRecordAdapte.addData(data); + } + }else { + if (page == 1) { + giftRecordAdapte.setNewData(null); + } + } + } + + + @Override + public void finishRefreshLoadMore() { + mBinding.smartRefreshLayout.finishRefresh(); + mBinding.smartRefreshLayout.finishLoadMore(); + } + + @Override + public void wallet(WalletBean walletBean) { + + } + + @Override + public void xlhChouSuccess(List data) { + + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/NewGiftRecordAdapte.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/NewGiftRecordAdapte.java new file mode 100644 index 00000000..72138f93 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/NewGiftRecordAdapte.java @@ -0,0 +1,23 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.utils.ImageUtils; + +public class NewGiftRecordAdapte extends BaseQuickAdapter { + public NewGiftRecordAdapte() { + super(R.layout.item_gift_record_new); + } + + @Override + protected void convert(BaseViewHolder helper, GiftBean item) { + helper.setText(R.id.tv_issue,item.getPeriods()); + helper.setText(R.id.tv_user_name, item.getNickname()); + helper.setText(R.id.tv_gift_count_name, item.getGift_name()); + helper.setText(R.id.tv_time, item.getCreatetime()); + ImageUtils.loadHeadCC(item.getBase_image(),helper.getView(R.id.iv_gift_icon)); + + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/NewXlhRankingDialog.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/NewXlhRankingDialog.java new file mode 100644 index 00000000..c698d1bf --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/NewXlhRankingDialog.java @@ -0,0 +1,174 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.view.Gravity; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.RadioGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; + +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.adapter.MyPagerAdapter; +import com.xscm.moduleutil.base.BaseMvpDialogFragment; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.bean.WalletBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindReslutBean; +import com.xscm.moduleutil.bean.blindboxwheel.XlhDrawBean; +import com.xscm.moduleutil.databinding.DialogNewRankingXlhFragmentBinding; +import com.xscm.moduleutil.dialog.LotteryFragment; + +import java.util.ArrayList; +import java.util.List; + +/** + *@author qx + *@data 2025/9/4 + *@description:巡乐会榜单 + */ + public class NewXlhRankingDialog extends BaseMvpDialogFragment implements GiftLotteryContacts.View{ + private String roomId; + + private MyPagerAdapter pagerAdapter; + private List fragmentList; + private List titleList = new ArrayList(); + + @Override + protected GiftLotteryPresenter bindPresenter() { + return new GiftLotteryPresenter(this,getSelfActivity()); + } + + public static NewXlhRankingDialog newInstance(String giftBagId) { + Bundle args = new Bundle(); + NewXlhRankingDialog fragment = new NewXlhRankingDialog(); + args.putString("roomId", giftBagId); + fragment.setArguments(args); + return fragment; + } + @Nullable + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + dialog.setCancelable(true); + return dialog; + } + + @Override + public void onStart() { + super.onStart(); + Window window = getDialog().getWindow(); + if (window != null) { + // 获取屏幕高度 + android.util.DisplayMetrics displayMetrics = new android.util.DisplayMetrics(); + requireActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + int screenHeight = displayMetrics.heightPixels; + // 设置高度为屏幕高度的100%(全屏) + int heightInPx = (int) (screenHeight * 0.8);; + window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, heightInPx); + window.setBackgroundDrawableResource(android.R.color.transparent); + + // 可选:设置动画样式(从底部弹出) + window.setWindowAnimations(R.style.CommonShowDialogBottom); + } + } + + @Override + protected void initDialogStyle(Window window) { + super.initDialogStyle(window); + window.setGravity(Gravity.BOTTOM); + } + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + + + } + + @Override + protected void initData() { + roomId = getArguments().getString("roomId"); + // MvpPre.xlhAllRecord(roomId, "1", "20"); + // 初始化Fragment列表 + initFragments(); + initViewPager(); + } + + // 初始化Fragment列表 + private void initFragments() { + fragmentList = new ArrayList<>(); + fragmentList.add(new LotteryFragment().newInstance(roomId,1)); // 第1页:抽奖榜单 + fragmentList.add(new LuckyFragment().newInstance(roomId,2)); // 第1页:抽奖榜单 + + } + + // 初始化ViewPager + private void initViewPager() { + titleList.add(""); + titleList.add(""); + FragmentManager childFragmentManager = getChildFragmentManager(); + pagerAdapter = new MyPagerAdapter(childFragmentManager, fragmentList,titleList ); + mBinding.ivViewPager.setAdapter(pagerAdapter); + mBinding.ivViewPager.setCurrentItem(0); // 默认显示第1页 + } + @Override + protected void initView() { + mBinding.rbBtn.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + if (checkedId==R.id.radio_all){ + mBinding.ivViewPager.setCurrentItem(0); + }else { + mBinding.ivViewPager.setCurrentItem(1); + } + } + }); + } + + + @Override + protected int getLayoutId() { + return R.layout.dialog_new_ranking_xlh_fragment; + } + + @Override + public void getGiftListSuccess(BlindBoxBean blindBoxBean) { + + } + + @Override + public void drawGiftListSuccess(BlindReslutBean blindReslutBean) { + + } + + @Override + public void getMyRecordSuccess(List data) { + } + + @Override + public void getAllRecordSuccess(List data) { + + + } + + @Override + public void finishRefreshLoadMore() { + + } + + @Override + public void wallet(WalletBean walletBean) { + + } + + @Override + public void xlhChouSuccess(List data) { + + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/PrizePoolAdapter.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/PrizePoolAdapter.java new file mode 100644 index 00000000..c3333398 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/PrizePoolAdapter.java @@ -0,0 +1,61 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import android.content.Context; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.adapter.MyBaseAdapter; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.utils.ImageUtils; +/** + *@author qx + *@data 2025/8/28 + *@description: 盲盒转盘的奖池适配器 + */ +public class PrizePoolAdapter extends BaseQuickAdapter { + private Context context; + private int type; + + public PrizePoolAdapter(int type) { + super(R.layout.item_prize_pool); + this.type = type; + } + + + + + @Override + protected void convert(BaseViewHolder helper, GiftBean item) { + + if (type == 10 || type == 12){ + helper.setImageResource(R.id.iv_prize_pool,R.mipmap.tkzj_z); + }else { + helper.setImageResource(R.id.iv_prize_pool,R.mipmap.xlh_hd); + } + + helper.setText(R.id.tv_gift_name, item.getGift_name()); + helper.setText(R.id.tv_gift_pic, item.getGift_price()); + ImageUtils.loadHeadCC(item.getBase_image(),helper.getView(R.id.iv_gift_image)); + } + + + public static class ViewHolder { + private ImageView imGiftImage; + private TextView tv_gift_name; + private TextView tv_gift_price; + + public ViewHolder(View convertView) { + imGiftImage = convertView.findViewById(R.id.iv_gift_image); + tv_gift_name = convertView.findViewById(R.id.tv_gift_name); + tv_gift_price = convertView.findViewById(R.id.tv_gift_pic); + + } + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/PrizePoolDialog.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/PrizePoolDialog.java new file mode 100644 index 00000000..aff88a46 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/PrizePoolDialog.java @@ -0,0 +1,117 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; + +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.databinding.DialogPrizePoolBinding; +import com.xscm.moduleutil.widget.dialog.BaseDialog; + +import java.util.List; + +/** + * @author qx + * @data 2025/8/28 + * @description: 盲盒转盘奖池弹窗 + */ +public class PrizePoolDialog extends BaseDialog { + private Context mContext; + private List gift_list; + private int type; + + public PrizePoolDialog(@NonNull Context context) { + super(context); + this.mContext = context; + // 设置对话框从底部弹出并紧贴底部 + if (getWindow() != null) { + getWindow().setGravity(android.view.Gravity.BOTTOM); + } + } + + @Override + public void onStart() { + super.onStart(); + if (getWindow() != null) { + // 获取屏幕尺寸 + android.util.DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics(); + // 设置高度为屏幕高度的80% + android.view.WindowManager.LayoutParams params = getWindow().getAttributes(); + params.height = (int) (displayMetrics.heightPixels * 0.7); + params.width = android.view.ViewGroup.LayoutParams.MATCH_PARENT; + getWindow().setAttributes(params); + } + } + + + @Override + public int getLayoutId() { + return R.layout.dialog_prize_pool; + } + + @Override + public void initView() { + } + + + @Override + public void initData() { + + } + + private void showEmptyState() { + // 显示空状态或加载中提示 + // mBinding.tvEmpty.setVisibility(View.VISIBLE); + // mBinding.tvEmpty.setText("暂无奖池数据"); + } + + // 提供更新数据的方法 + public void updateData(List newData, int type) { + if (type == 10) { + mBinding.clPrize.setBackgroundResource(R.mipmap.tkzj); + mBinding.imJc.setImageResource(R.mipmap.jiangc); + } else if (type == 11) { + mBinding.clPrize.setBackgroundResource(R.mipmap.syzc); + mBinding.imJc.setImageResource(R.mipmap.syzc_jc); + } else if (type == 12) { + mBinding.clPrize.setBackgroundResource(R.mipmap.skzj); + mBinding.imJc.setImageResource(R.mipmap.skzl_jc); + }else if (type == 13){ + mBinding.clPrize.setBackgroundResource(R.mipmap.xlh); + mBinding.imJc.setImageResource(R.mipmap.xlh_jc); + } + + // 根据屏幕密度调整行数和列数 + int rows, columns; + float density = mContext.getResources().getDisplayMetrics().density; + + if (density <= 2.0) { // 低密度屏幕(如mdpi, hdpi) + rows = 4; + columns = 3; + } else if (density <= 3.0) { // 中密度屏幕(如xhdpi) + rows = 4; + columns = 3; + } else { // 高密度屏幕(如xxhdpi, xxxhdpi) + rows = 4; + columns = 3; + } + + if (newData != null && !newData.isEmpty()) { + this.gift_list = newData; + if (mBinding != null && mContext != null) { + PrizePoolAdapter prizePoolAdapter = new PrizePoolAdapter(type); + GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 3); +// PagerGridLayoutManager layoutManager = new PagerGridLayoutManager(rows, columns, PagerGridLayoutManager.VERTICAL); + mBinding.gvGift.setLayoutManager(layoutManager); +// mBinding.gvGift.setOnFlingListener(null); + // 设置滚动辅助工具 +// PagerGridSnapHelper pageSnapHelper = new PagerGridSnapHelper(); +// pageSnapHelper.attachToRecyclerView(mBinding.gvGift); + mBinding.gvGift.setAdapter(prizePoolAdapter); + prizePoolAdapter.setNewData(gift_list); + } + } + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/TourClubDialogFragment.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/TourClubDialogFragment.java new file mode 100644 index 00000000..0872f8bf --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/TourClubDialogFragment.java @@ -0,0 +1,1116 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Typeface; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.Handler; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSnapHelper; +import androidx.recyclerview.widget.RecyclerView; + +import com.alibaba.android.arouter.launcher.ARouter; +import com.blankj.utilcode.util.GsonUtils; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.base.BaseMvpDialogFragment; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.bean.MqttXlhEnd; +import com.xscm.moduleutil.bean.RoomMessageEvent; +import com.xscm.moduleutil.bean.WalletBean; +import com.xscm.moduleutil.bean.XLHBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindReslutBean; +import com.xscm.moduleutil.bean.blindboxwheel.XlhDrawBean; +import com.xscm.moduleutil.databinding.FragmentTourClubDialogBinding; +import com.xscm.moduleutil.dialog.RechargeDialogFragment; +import com.xscm.moduleutil.dialog.WebViewDialog; +import com.xscm.moduleutil.event.MqttBean; +import com.xscm.moduleutil.utils.ARouteConstants; +import com.xscm.moduleutil.utils.ImageUtils; +import com.xscm.moduleutil.widget.CenterScrollHelper; +import com.xscm.moduleutil.widget.EqualSpaceItemDecoration; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author qx + * @data 2025/9/15 + * @description: 玄镜之旅 + */ +public class TourClubDialogFragment extends BaseMvpDialogFragment implements GiftLotteryContacts.View { + private String roomId; + private List giftLists = new ArrayList<>(); + private String getRule_url; + private CountDownTimer mCountDownTimer; + private long endTime; // 服务器返回的结束时间戳 + private String num; + private NewXlhRankingDialog newXlhRankingDialog; + private XlhRecordDialog xlhRecordDialog; + private XlhObtainDialog xlhObtainDialog; + + private GiftXlhChouAdapter giftXlhChouAdapter; + private CenterScrollHelper scrollHelper; + + private static final int ITEM_COUNT = 24; + private static final int ROTATION_COUNT = 3; + + + private Handler handler = new Handler(); + private boolean isLotteryRunning = false; + private int scrollSpeed = 10; // 滚动速度 + private int totalScrollTime = 5000; // 总滚动时间,单位:毫秒 + private int targetPosition; + + private boolean isDrawing;//是否正在抽奖 + + + // 添加自动滚动相关的成员变量 + private Handler autoScrollHandler = new Handler(); + private Runnable autoScrollRunnable; + private boolean isAutoScrolling = false; + private static final int AUTO_SCROLL_DELAY = 1000; // 1秒滚动一个item + private boolean vCheckbox=false; + + @Override + protected GiftLotteryPresenter bindPresenter() { + return new GiftLotteryPresenter(this, getActivity()); + } + + public static TourClubDialogFragment newInstance(String roomId) { + TourClubDialogFragment dialog = new TourClubDialogFragment(); + Bundle args = new Bundle(); + args.putString("roomId", roomId); + dialog.setArguments(args); + return dialog; + } + + @Nullable + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + dialog.setCancelable(true); + if (!EventBus.getDefault().isRegistered(this)) + EventBus.getDefault().register(this); + return dialog; + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + roomId = getArguments().getString("roomId"); + } + + @Override + protected void initData() { + MvpPre.xlh(roomId); + MvpPre.wallet(); + } + + @Override + protected void initDialogStyle(Window window) { + super.initDialogStyle(window); + window.setGravity(Gravity.BOTTOM); + } + + @Override + public void onStart() { + super.onStart(); + Window window = getDialog().getWindow(); + if (window != null) { + // 获取屏幕高度 + android.util.DisplayMetrics displayMetrics = new android.util.DisplayMetrics(); + requireActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + int screenHeight = displayMetrics.heightPixels; + // 设置高度为屏幕高度的100%(全屏) + int heightInPx = (int) (screenHeight * 0.85); + window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, heightInPx); + window.setBackgroundDrawableResource(android.R.color.transparent); + + // 可选:设置动画样式(从底部弹出) + window.setWindowAnimations(R.style.CommonShowDialogBottom); + } + } + + @Override + protected void initView() { + mBinding.tvJc.setOnClickListener(this::onClick); + mBinding.llOne.setOnClickListener(this::onClick); + mBinding.llTen.setOnClickListener(this::onClick); + mBinding.llHundred.setOnClickListener(this::onClick); + mBinding.tvGz.setOnClickListener(this::onClick); + mBinding.tvBd.setOnClickListener(this::onClick); + mBinding.tvJl.setOnClickListener(this::onClick); + mBinding.exchangeLayout.setOnClickListener(this::onClick); + mBinding.vCheckbox.setOnClickListener(this::onClick); + giftXlhChouAdapter = new GiftXlhChouAdapter(); + // 使用 LinearLayoutManager 横向滚动 + LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false); + mBinding.recycleView.setLayoutManager(layoutManager); + mBinding.recycleView.setOnFlingListener(null); + + // 设置滚动辅助工具 + LinearSnapHelper snapHelper = new LinearSnapHelper(); + snapHelper.attachToRecyclerView(mBinding.recycleView); + + // 添加 ItemDecoration 实现等宽分布 + int spacing = getResources().getDimensionPixelSize(R.dimen.dp_15); // 根据需要调整间距 + mBinding.recycleView.addItemDecoration(new EqualSpaceItemDecoration(3, spacing)); + + mBinding.recycleView.setAdapter(giftXlhChouAdapter); + // 初始化滚动帮助类 + scrollHelper = new CenterScrollHelper(mBinding.recycleView); + + // 初始化时滚动到中间位置,确保有足够的前后数据 + mBinding.recycleView.post(() -> { + if (giftXlhChouAdapter.getOriginalDataSize() > 0) { + int middlePosition = giftXlhChouAdapter.getItemCount() / 2; + mBinding.recycleView.scrollToPosition(middlePosition); + } + }); + mBinding.tvNumber.setText("x0"); + mBinding.tvNumber.setTypeface(android.graphics.Typeface.create("semibold", Typeface.NORMAL)); + } + + // 添加自动滚动相关的方法 + private void startAutoScroll() { + // 如果已经在自动滚动或数据为空,则不启动 + if (isAutoScrolling || giftLists == null || giftLists.isEmpty()) { + return; + } + + isAutoScrolling = true; + autoScrollRunnable = new Runnable() { + @Override + public void run() { + if (isAutoScrolling && mBinding != null && mBinding.recycleView != null) { + // 获取当前显示的第一个可见item位置 + LinearLayoutManager layoutManager = (LinearLayoutManager) mBinding.recycleView.getLayoutManager(); + if (layoutManager != null) { + int currentPosition = layoutManager.findFirstVisibleItemPosition(); + + // 如果没有完全可见的item,使用第一个可见item + if (currentPosition == RecyclerView.NO_POSITION) { + currentPosition = layoutManager.findFirstVisibleItemPosition(); + } + + // 如果还是没有有效的position,从0开始 + if (currentPosition == RecyclerView.NO_POSITION) { + currentPosition = 0; + } + // 计算下一个位置 + int nextPosition = currentPosition + 1; + + // 如果到达末尾,回到开始位置 + if (nextPosition >= giftXlhChouAdapter.getItemCount()) { + nextPosition = 0; + } + + // 平滑滚动到下一个位置 + mBinding.recycleView.smoothScrollToPosition(nextPosition); + } + + // 1秒后继续滚动 + autoScrollHandler.postDelayed(this, AUTO_SCROLL_DELAY); + } + } + }; + + // 开始自动滚动 + autoScrollHandler.postDelayed(autoScrollRunnable, AUTO_SCROLL_DELAY); + } + + private void stopAutoScroll() { + isAutoScrolling = false; + if (autoScrollRunnable != null) { + autoScrollHandler.removeCallbacks(autoScrollRunnable); + autoScrollRunnable = null; + } + } + + // 在抽奖结束后重新启动自动滚动 + private void resumeAutoScrollAfterLottery() { + // 延迟一段时间后再启动自动滚动,让用户看到抽奖结果 + mBinding.recycleView.postDelayed(() -> { + if (isVisible() && !isDrawing) { + startAutoScroll(); + } + }, 3000); // 3秒后重新开始自动滚动 + } + + + private void onClick(View view) { + int id = view.getId(); + if (id == R.id.tv_jc) { + if (giftLists != null && !giftLists.isEmpty()) { + PrizePoolDialog prizePoolDialog = new PrizePoolDialog(getActivity()); + prizePoolDialog.updateData(giftLists, 13); + prizePoolDialog.show(); + } else { + com.hjq.toast.ToastUtils.show("奖池数据加载中,请稍后再试"); + } + } else if (id == R.id.ll_one) { + if (!isDrawing) { + isDrawing = true; + prepareForNewLottery(); + num = "1"; + MvpPre.xlhChou(roomId, num); + } else { +// com.hjq.toast.ToastUtils.show("正在抽奖中..."); + } + + } else if (id == R.id.ll_ten) { + if (!isDrawing) { + isDrawing = true; + prepareForNewLottery(); + num = "10"; + MvpPre.xlhChou(roomId, num); + } else { +// com.hjq.toast.ToastUtils.show("正在抽奖中..."); + } + + } else if (id == R.id.ll_hundred) { + if (!isDrawing) { + isDrawing = true; + prepareForNewLottery(); + num = "100"; + MvpPre.xlhChou(roomId, num); + } else { +// com.hjq.toast.ToastUtils.show("正在抽奖中..."); + } + + } else if (id == R.id.tv_gz) { + Bundle bundle = new Bundle(); + bundle.putString("url", getRule_url); + bundle.putInt("type", 13); + WebViewDialog dialog = new WebViewDialog(getActivity(), bundle); + dialog.show(); + } else if (id == R.id.tv_bd) { + // 如果当前dialog存在且正在显示,先关闭 + if (newXlhRankingDialog != null && newXlhRankingDialog.isVisible()) { + newXlhRankingDialog.dismiss(); + } + + newXlhRankingDialog = NewXlhRankingDialog.newInstance(roomId); + newXlhRankingDialog.show(getChildFragmentManager(), "newXlhRankingDialog"); + } else if (id == R.id.tv_jl) { + // 如果当前dialog存在且正在显示,先关闭 + if (xlhRecordDialog != null && xlhRecordDialog.isVisible()) { + xlhRecordDialog.dismiss(); + } + + xlhRecordDialog = XlhRecordDialog.newInstance(roomId); + xlhRecordDialog.show(getChildFragmentManager(), "XlhRecordDialog"); + } else if (id == R.id.exchange_layout) {//钻石兑换 +// ARouter.getInstance().build(ARouteConstants.CURRENCY).navigation(); + RechargeDialogFragment.show(roomId, null, getActivity().getSupportFragmentManager(),"0","0"); + }else if (id==R.id.v_checkbox){ + mBinding.vCheckbox.setSelected(!mBinding.vCheckbox.isSelected()); + vCheckbox=mBinding.vCheckbox.isSelected(); + } + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_tour_club_dialog; + } + + @Override + public void getGiftListSuccess(BlindBoxBean blindBoxBean) { + if (blindBoxBean != null) { + + getRule_url = blindBoxBean.getRule_url(); + upTitle(blindBoxBean.getBox_price()); + giftLists = blindBoxBean.getGift_list(); +// 初始滚动到中间位置,避免边界问题 +// mBinding.recycleView.scrollToPosition(Integer.MAX_VALUE / 2 - (Integer.MAX_VALUE / 2) % giftLists.size()); + + // 获取结束时间并启动倒计时 + if (blindBoxBean.getXlh_end_time() != null && !blindBoxBean.getXlh_end_time().isEmpty()) { + try { + endTime = Long.parseLong(blindBoxBean.getXlh_end_time()); + mBinding.qxDjs.setEndTime(endTime); + // 假设 end_time 是时间戳字符串 +// startCountdown(); + } catch (NumberFormatException e) { + // 如果不是时间戳,可能是日期字符串,需要相应解析 + // 例如:2025-08-26 19:10:47 + // 可以使用 SimpleDateFormat 解析 + e.printStackTrace(); + } + } + + if (blindBoxBean.getGive_homeowner_gift() != null) { +// ImageUtils.loadHeadCC(blindBoxBean.getGive_homeowner_gift().getBase_image(), mBinding.giveIm); + mBinding.gvFzlw.setModel(blindBoxBean.getGive_homeowner_gift()); + } + if (blindBoxBean.getLocking_gift() != null) { +// ImageUtils.loadHeadCC(blindBoxBean.getLocking_gift().getBase_image(), mBinding.giftImg); +// mBinding.tvGiftName.setText(blindBoxBean.getLocking_gift().getGift_name()); +// mBinding.tvGiftPrice.setText(blindBoxBean.getLocking_gift().getGift_price()); +// mBinding.tvGiftCount.setText(blindBoxBean.getLocking_gift().getGift_num()); + mBinding.tvNumber.setText("x"+(blindBoxBean.getLocking_gift().getGift_num()!=null ?blindBoxBean.getLocking_gift().getGift_num():"0")); + mBinding.gvSdlw.setModel(blindBoxBean.getLocking_gift()); + mBinding.gvSdlw.setIsLockGift(true); + mBinding.gvSdlw.stopAnimation(); + mBinding.gvSdlw.startAnimation(); + } + + if (blindBoxBean.getXlh_user() != null) { +// ImageUtils.loadHeadCC(blindBoxBean.getXlh_user().getAvatar(), mBinding.userPic); +// mBinding.userName.setText(blindBoxBean.getXlh_user().getNickname()); + + mBinding.gvXyz.setModel(blindBoxBean.getXlh_user()); + } + mBinding.gvXyz.setIsLuckUser(true); + if (blindBoxBean.getHomeowner_user()!=null){ + mBinding.gvFz.setModel(blindBoxBean.getHomeowner_user()); + + } + mBinding.gvFz.setIsLuckUser(false); + giftXlhChouAdapter.setNewData(giftLists); +// // 数据加载完成后启动自动滚动 +// if (giftLists != null && !giftLists.isEmpty()) { +// mBinding.recycleView.post(() -> { +// // 确保在UI线程中启动自动滚动 +// startAutoScroll(); +// }); +// } + + }else { + isDrawing = false; + } + } + + int mboxPrice; + + // TODO: 2025/9/4 设置底部按钮文字 + private void upTitle(int boxPrice) { + this.mboxPrice = boxPrice; + mBinding.tvOne.setText(boxPrice + "币一次"); + mBinding.tvTen.setText((boxPrice * 10) + "币十次"); + mBinding.tvHundred.setText((boxPrice * 100) + "币百次"); + } + + // TODO: 2025/8/29 接收im推送过来的消息 +// @Subscribe(threadMode = ThreadMode.MAIN) + public void onMusicPlay(RoomMessageEvent message) { + if (message.getMsgType() == 1057) { +// UpView(message.getText().getXlh_data()); + endTime = Long.parseLong(message.getText().getEnd_time() != null ? message.getText().getEnd_time() : "0"); +// startCountdown(); +// mBinding.tvGiftCount.setText(message.getText().getGift_num() != null ? message.getText().getGift_num() : "0"); +// mBinding.userName.setText(message.getText().getFromUserInfo().getNickname() != null ? message.getText().getFromUserInfo().getNickname() : ""); +// ImageUtils.loadHeadCC(message.getText().getFromUserInfo().getAvatar(), mBinding.userPic); + BlindBoxBean.xlhUser xlhUser = new BlindBoxBean.xlhUser(); + xlhUser.setAvatar(message.getText().getFromUserInfo().getAvatar()); + xlhUser.setNickname(message.getText().getFromUserInfo().getNickname()); + mBinding.gvXyz.setModel(xlhUser); + mBinding.qxDjs.setEndTime(endTime); + mBinding.tvNumber.setText("x"+(message.getText().getGift_num() != null ? message.getText().getGift_num() : "0")); + isDrawing=false; + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageReceived(RoomMessageEvent event) { + onMusicPlay( event); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageReceived(MqttXlhEnd event) { + XLHBean xlhBean = GsonUtils.fromJson(event.getMessage(), XLHBean.class); + if (xlhBean.getFrom_type()==103){ + endTime = Long.parseLong(xlhBean.getEnd_time() != null ? xlhBean.getEnd_time() : "0"); + BlindBoxBean.xlhUser xlhUser = new BlindBoxBean.xlhUser(); + xlhUser.setAvatar(xlhBean.getFromUserInfo().getAvatar()); + xlhUser.setNickname(xlhBean.getFromUserInfo().getNickname()); + mBinding.gvXyz.setModel(xlhUser); + mBinding.qxDjs.setEndTime(endTime); + mBinding.tvNumber.setText("x"+(xlhBean.getGift_num() != null ? xlhBean.getGift_num() : "0")); + isDrawing=false; + if (xlhBean.getRoom_user()!=null){ + mBinding.gvFz.setModel(xlhBean.getRoom_user()); + } + mBinding.gvFz.setIsLuckUser(false); + }else if (xlhBean.getFrom_type()==104){ + dismiss(); + } + + } + + /** + * 启动倒计时 + */ + private void startCountdown() { + // 先释放之前的倒计时器 + releaseCountDownTimer(); + + // 获取当前时间 + long currentTime = System.currentTimeMillis() / 1000; // 转换为秒 + long countdownTime = endTime - currentTime; // 计算剩余时间(秒) + + // 如果倒计时时间已经结束,显示00:00 + if (countdownTime <= 0) { + updateCountdownDisplay(0, 0); + return; + } + + // 确保不超过最大时间59:59 (3599秒) + countdownTime = Math.min(countdownTime, 3599); + + mCountDownTimer = new CountDownTimer(countdownTime * 1000, 1000) { + @Override + public void onTick(long millisUntilFinished) { + long seconds = millisUntilFinished / 1000; + long minutes = seconds / 60; + long remainingSeconds = seconds % 60; + updateCountdownDisplay((int) minutes, (int) remainingSeconds); + } + + @Override + public void onFinish() { + updateCountdownDisplay(0, 0); + } + }; + + mCountDownTimer.start(); + } + + /** + * 更新倒计时显示 + * + * @param minutes 分钟数 + * @param seconds 秒数 + */ + private void updateCountdownDisplay(int minutes, int seconds) { + // 假设布局中有以下TextView: + // mBinding.tvMinutes 十位分钟 + // mBinding.tvMinutesUnit 个位分钟 + // mBinding.tvSeconds 十位秒数 + // mBinding.tvSecondsUnit 个位秒数 + + // 分解分钟数 + int minutesTens = minutes / 10; // 十位分钟 + int minutesUnits = minutes % 10; // 个位分钟 + + // 分解秒数 + int secondsTens = seconds / 10; // 十位秒数 + int secondsUnits = seconds % 10; // 个位秒数 + + // 更新UI显示(根据你的实际布局调整) + mBinding.tvTime1.setText(String.valueOf(minutesTens)); + mBinding.tvTime2.setText(String.valueOf(minutesUnits)); + mBinding.tvTime3.setText(String.valueOf(secondsTens)); + mBinding.tvTime4.setText(String.valueOf(secondsUnits)); + + // 或者如果是一个整体的显示: + // mBinding.tvCountdown.setText(String.format("%02d:%02d", minutes, seconds)); + } + + /** + * 释放倒计时器资源 + */ + private void releaseCountDownTimer() { + if (mCountDownTimer != null) { + mCountDownTimer.cancel(); + mCountDownTimer = null; + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + releaseCountDownTimer(); + // 清理所有待执行的任务 + clearPendingTasks(); + + // 清理滚动帮助类 + if (scrollHelper != null) { + scrollHelper = null; + } + + // 清理适配器引用 + if (giftXlhChouAdapter != null) { + giftXlhChouAdapter = null; + } + + if (EventBus.getDefault().isRegistered(this)) { + EventBus.getDefault().unregister(this); + } + + if (xlhRecordDialog != null && xlhRecordDialog.isVisible()) { + xlhRecordDialog.dismiss(); + } + + // 如果当前dialog存在且正在显示,先关闭 + if (newXlhRankingDialog != null && newXlhRankingDialog.isVisible()) { + newXlhRankingDialog.dismiss(); + } + + if (xlhObtainDialog != null && xlhObtainDialog.isShowing()) { + xlhObtainDialog.dismiss(); + } + + stopAutoScroll(); + autoScrollHandler.removeCallbacksAndMessages(null); + } + + + @Override + public void drawGiftListSuccess(BlindReslutBean blindReslutBean) { + + } + + @Override + public void getMyRecordSuccess(List data) { + + } + + @Override + public void getAllRecordSuccess(List data) { + + } + + @Override + public void finishRefreshLoadMore() { + + } + + private int icon; + + @Override + public void wallet(WalletBean walletBean) { + if (walletBean != null) { + icon = (int) Double.parseDouble( + (walletBean.getCoin() != null && !walletBean.getCoin().isEmpty()) + ? walletBean.getCoin() + : "0" + ); + mBinding.tvIcon.setText(walletBean.getCoin()!=null && !walletBean.getCoin().isEmpty() ?walletBean.getCoin():"0"); + showView(); + } + } + + private void showView() { + if (icon>=mboxPrice){ + mBinding.llOne.setClickable( true); + }else { + mBinding.llOne.setClickable( false); + } + + if (icon>=mboxPrice*10){ + mBinding.llTen.setClickable( true); + }else { + mBinding.llTen.setClickable( false); + } + if (icon>=mboxPrice*100){ + mBinding.llHundred.setClickable( true); + }else { + mBinding.llHundred.setClickable( false); + } + } + + private Runnable pendingLotteryRunnable; + private Runnable pendingCenteringRunnable; + + @Override + public void xlhChouSuccess(List data) { + if (data != null) { + if (vCheckbox){ + showResultDialog(data); + }else { +// showResultDialog(data); + +// 取消之前可能存在的任务 + clearPendingTasks(); + // 抽奖完成后执行动画滚动 + pendingLotteryRunnable = new Runnable() { + @Override + public void run() { + // 清理之前的状态 + if (giftXlhChouAdapter != null) { + giftXlhChouAdapter.clearSelection(); + } + int winningPosition = findHighestValueWinningPosition(data);//这是获取到的中奖位置下标 + if (winningPosition != -1) { + if (scrollHelper == null) { + scrollHelper = new CenterScrollHelper(mBinding.recycleView); + } + + // 计算在循环列表中的目标位置(滚动几圈后停在目标位置) + int loopCount = 4; // 滚动4圈 + int originalSize = giftLists.size();///这是列表的总大小 + // 计算目标在循环列表中的位置(确保在中间区域) + ///这是计算总圈数的大小 + int middleBaseIndex = (loopCount * originalSize); + ///这里是展示在中奖的位置,加上总圈数的大小, + int targetLoopIndex = middleBaseIndex + (winningPosition % originalSize); + + // 使用scrollWithCircles方法执行带动画的滚动(带完成回调) + scrollHelper.scrollWithCircles( + targetLoopIndex, // 在循环列表中的位置 + loopCount, // 滚动圈数 + 1000, // 每个item滚动时间200ms(控制速度) + originalSize, // 原始数据大小 + () -> { // 滚动完成回调 + // 滚动完成后更新选中状态(使用原始位置) + if (giftXlhChouAdapter != null) { + giftXlhChouAdapter.setSelectedPosition(winningPosition); + } + // 滚动完成后延迟一小段时间再居中,确保UI更新完成 + pendingCenteringRunnable = new Runnable() { + @Override + public void run() { + // 手动将选中项居中 + centerSelectedItem(winningPosition, originalSize); + + // 显示结果对话框 + getActivity().runOnUiThread(() -> { + scrollHelper = null; + showResultDialog(data); + // 抽奖结束后重新启动自动滚动 +// resumeAutoScrollAfterLottery(); + }); + } + }; + mBinding.recycleView.postDelayed(pendingCenteringRunnable, 1000); + } + ); + + } else { + // 如果没有找到中奖位置,直接显示对话框 + showResultDialog(data); + // 抽奖结束后重新启动自动滚动 +// resumeAutoScrollAfterLottery(); + } + } + }; + mBinding.recycleView.postDelayed(pendingLotteryRunnable, 1000); + + } + }else { + isDrawing=false; + // 抽奖失败也重新启动自动滚动 +// resumeAutoScrollAfterLottery(); + } + MvpPre.wallet(); + + } + + + /** + * 为新的抽奖做准备,清理之前的状态 + */ + private void prepareForNewLottery() { + + // 停止自动滚动 + stopAutoScroll(); + + // 取消之前可能存在的任务 + clearPendingTasks(); + + // 清除之前的选择状态 + if (giftXlhChouAdapter != null) { + giftXlhChouAdapter.clearSelection(); + } + + // 重置滚动帮助类 + if (scrollHelper != null) { + scrollHelper.reset(); + } + + // 停止可能正在进行的滚动 + mBinding.recycleView.stopScroll(); + + // 清理可能存在的回调 + if (mBinding.recycleView.getHandler() != null) { + mBinding.recycleView.getHandler().removeCallbacksAndMessages(null); + } + + // 重新初始化滚动帮助类 + scrollHelper = new CenterScrollHelper(mBinding.recycleView); + } + + /** + * 清除所有待执行的任务 + */ + private void clearPendingTasks() { + // 取消抽奖动画任务 + if (pendingLotteryRunnable != null) { + mBinding.recycleView.removeCallbacks(pendingLotteryRunnable); + pendingLotteryRunnable = null; + } + + // 取消居中任务 + if (pendingCenteringRunnable != null) { + mBinding.recycleView.removeCallbacks(pendingCenteringRunnable); + pendingCenteringRunnable = null; + } + + // 停止可能正在进行的滚动 + mBinding.recycleView.stopScroll(); + + // 清理handler中的所有消息 + if (mBinding.recycleView.getHandler() != null) { + mBinding.recycleView.getHandler().removeCallbacksAndMessages(null); + } + } + + private void startLotteryAnimation(int targetIndex) { + // 确保适配器有数据 + if (giftXlhChouAdapter == null || giftXlhChouAdapter.getOriginalDataSize() <= 0) { + showResultDialogWithoutAnimation(targetIndex); + return; + } + + LinearLayoutManager layoutManager = (LinearLayoutManager) mBinding.recycleView.getLayoutManager(); + if (layoutManager == null) { + showResultDialogWithoutAnimation(targetIndex); + return; + } + + // 获取当前第一个可见的item位置 + int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition(); + if (firstVisiblePosition == RecyclerView.NO_POSITION) { + firstVisiblePosition = 0; + } + + // 获取当前在原始数据中的实际位置 + int currentActualPosition = firstVisiblePosition % giftXlhChouAdapter.getOriginalDataSize(); + + // 计算需要滚动的总item数 + // 滚动指定圈数 + 从当前位置到目标位置的距离 + int itemsToScroll = ROTATION_COUNT * giftXlhChouAdapter.getOriginalDataSize() + + (targetIndex - currentActualPosition + giftXlhChouAdapter.getOriginalDataSize()) + % giftXlhChouAdapter.getOriginalDataSize(); + + // 计算目标位置 + int targetPosition = firstVisiblePosition + itemsToScroll; + + // 确保目标位置在合理范围内 + int maxPosition = giftXlhChouAdapter.getItemCount() - 1; + if (targetPosition > maxPosition) { + targetPosition = maxPosition; + } + + // 确保目标位置有效 + if (targetPosition >= 0) { + try { + SmoothScroller smoothScroller = new SmoothScroller(getActivity(), targetPosition); + layoutManager.startSmoothScroll(smoothScroller); + } catch (IllegalArgumentException e) { + // 如果仍然出现异常,使用备选方案 + showResultDialogWithoutAnimation(targetIndex); + } + } else { + showResultDialogWithoutAnimation(targetIndex); + } + } + + + private void showResultDialogWithoutAnimation(int targetIndex) { + // 直接设置选中状态 + if (giftXlhChouAdapter != null) { + giftXlhChouAdapter.setSelectedPosition(targetIndex); + } + + // 延迟显示结果对话框 + mBinding.recycleView.postDelayed(() -> { + // 创建假的XlhDrawBean数据用于显示结果 + List fakeData = new ArrayList<>(); + // 这里根据需要构造假数据 + showResultDialog(fakeData); + }, 300); + } + + + private class SmoothScroller extends androidx.recyclerview.widget.LinearSmoothScroller { + + private int targetPosition; + + public SmoothScroller(android.content.Context context, int targetPosition) { + super(context); + this.targetPosition = targetPosition; + } + + @Override + protected int calculateTimeForScrolling(int dx) { + // 自定义滚动时间,实现速度变化 + float distance = Math.abs(dx); + float speed = 1f; + if (distance < 100) { + speed = 0.3f; // 慢 + } else if (distance < 300) { + speed = 1f; // 快 + } else { + speed = 0.3f; // 慢 + } + return (int) (distance / speed); + } + + @Override + public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) { + // 将目标项移动到屏幕中心 + return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2); + } + + @Override + public int getTargetPosition() { + // 添加更严格的边界检查 + if (giftXlhChouAdapter != null && targetPosition >= 0 && targetPosition < giftXlhChouAdapter.getItemCount()) { + return targetPosition; + } + // 如果超出范围,返回一个安全的位置 + if (giftXlhChouAdapter != null && giftXlhChouAdapter.getItemCount() > 0) { + return Math.max(0, Math.min(targetPosition, giftXlhChouAdapter.getItemCount() - 1)); + } + return 0; // 返回默认位置 + } + } + + /** + * 将指定的原始位置item居中显示 + * + * @param originalPosition 原始数据中的位置 + * @param originalSize 原始数据大小 + */ + // 新增优化的居中方法 + private void centerSelectedItem(int originalPosition, int originalSize) { + LinearLayoutManager layoutManager = (LinearLayoutManager) mBinding.recycleView.getLayoutManager(); + if (layoutManager == null) return; + + // 计算出需要滚动到的目标位置(确保在中间可见区域) + int targetPosition = originalPosition + 4 * originalSize; + + // 先滚动到目标位置附近 + mBinding.recycleView.scrollToPosition(targetPosition); + + // 使用post确保布局完成后进行精确居中 + mBinding.recycleView.post(() -> { + View targetView = layoutManager.findViewByPosition(targetPosition); + if (targetView == null) { + // 如果目标view不可见,使用smoothScrollToPosition + mBinding.recycleView.smoothScrollToPosition(targetPosition); + // 再次尝试居中 + mBinding.recycleView.postDelayed(() -> { + View refreshedView = layoutManager.findViewByPosition(targetPosition); + if (refreshedView != null) { + performCentering(layoutManager, refreshedView); + } + }, 50); + return; + } + + performCentering(layoutManager, targetView); + }); + } + + // 执行实际的居中操作 + private void performCentering(LinearLayoutManager layoutManager, View targetView) { + // 计算RecyclerView的中心点 + int recyclerViewWidth = mBinding.recycleView.getWidth(); + int recyclerViewCenter = recyclerViewWidth / 2; + + // 计算目标view的中心点 + int targetViewLeft = targetView.getLeft(); + int targetViewWidth = targetView.getWidth(); + int targetViewCenter = targetViewLeft + targetViewWidth / 2; + + // 计算需要滚动的偏移量 + int offset = targetViewCenter - recyclerViewCenter; + + // 精确滚动使目标view居中 + mBinding.recycleView.scrollBy(offset, 0); + } + + /** + * 直接滚动到指定位置并居中 + * + * @param targetPosition 目标位置 + */ + private void directScrollToCenter(int targetPosition) { + if (mBinding.recycleView.getLayoutManager() == null) return; + + mBinding.recycleView.post(() -> { + int screenWidth = mBinding.recycleView.getWidth(); + if (screenWidth <= 0) return; + + // 计算item宽度 + int itemWidth = screenWidth / 3; + + // 计算目标位置的左边缘 + int targetLeft = targetPosition * itemWidth; + + // 计算使item居中需要滚动到的位置 + int targetScrollX = targetLeft - (screenWidth - itemWidth) / 2; + + // 直接滚动到目标位置 + mBinding.recycleView.scrollBy( + targetScrollX - mBinding.recycleView.computeHorizontalScrollOffset(), + 0 + ); + }); + } + + + /** + * 滚动到指定位置并使该位置的item居中显示 + * + * @param selectedPosition 选中的原始位置 + */ + private void scrollToCenterWithSelected(int selectedPosition) { + if (mBinding.recycleView.getLayoutManager() == null) return; + + int screenWidth = mBinding.recycleView.getWidth(); + if (screenWidth <= 0) return; + + // 计算item宽度 + int itemWidth = screenWidth / 3; + + // 计算要滚动到的中心位置(使selectedPosition的item居中) + int middlePositionInLoop = (giftXlhChouAdapter.getItemCount() / 2 / giftXlhChouAdapter.getOriginalDataSize()) + * giftXlhChouAdapter.getOriginalDataSize() + selectedPosition; + + // 滚动到目标位置 + mBinding.recycleView.smoothScrollToPosition(middlePositionInLoop); + + // 额外确保居中 + mBinding.recycleView.postDelayed(() -> { + if (scrollHelper != null) { + scrollHelper.scrollToCenter(middlePositionInLoop); + } + }, 300); + } + + /** + * 显示抽奖结果对话框 + * + * @param data 中奖数据 + */ + private void showResultDialog(List data) { + isDrawing = false; + // 创建并显示对话框 + // 关闭之前可能存在的对话框 +// if (xlhObtainDialog != null && xlhObtainDialog.isShowing()) { +// xlhObtainDialog.dismiss(); +// } + // 创建并显示对话框 + xlhObtainDialog = new XlhObtainDialog(getActivity()); + xlhObtainDialog.setOnGiftItemClickListener(new XlhObtainDialog.OnGiftItemClickListener() { + + @Override + public void onPlayAgainClick() { + isDrawing = true; + // 处理再玩一次点击事件 + MvpPre.xlhChou(roomId, num); + } + + @Override + public void onCloseClick() { + // 处理关闭点击事件 + if (xlhObtainDialog != null && xlhObtainDialog.isShowing()) { + isDrawing = false; + xlhObtainDialog.dismiss(); + } + xlhObtainDialog = null; + } + }); + + xlhObtainDialog.show(); + xlhObtainDialog.setGiftList(data); + } + + /** + * 根据中奖结果找到最高价值奖品在giftLists中的位置 + * + * @param data 中奖结果列表 + * @return 最高价值奖品在giftLists中的下标,如果没有找到则返回-1 + */ + private int findHighestValueWinningPosition(List data) { + if (data == null || data.isEmpty() || giftLists == null || giftLists.isEmpty()) { + return -1; + } + + int targetPosition = -1; + int highestPrice = -1; + + // 遍历giftLists查找中奖项目 + for (int i = 0; i < giftLists.size(); i++) { + GiftBean giftBean = giftLists.get(i); + + // 在中奖数据中查找匹配的礼品 + for (XlhDrawBean xlhDrawBean : data) { + // 比较gift_id是否匹配 + if (giftBean.getGift_id().equals(String.valueOf(xlhDrawBean.getGift_id()))) { + // 解析价格,处理可能的NumberFormatException + try { + int currentPrice = Integer.parseInt(giftBean.getGift_price()); + // 如果当前价格更高,则更新目标位置和最高价格 + if (currentPrice > highestPrice) { + highestPrice = currentPrice; + targetPosition = i; + } + } catch (NumberFormatException e) { + // 如果价格解析失败,使用默认值0进行比较 + if (highestPrice <= 0) { + highestPrice = 0; + targetPosition = i; + } + } + break; // 找到匹配项后跳出内层循环 + } + } + } + + return targetPosition; + } + + /** + * 精确将指定位置的item滚动到中心 + * + * @param position 目标位置 + */ + private void preciseScrollToCenter(int position) { + if (mBinding.recycleView.getLayoutManager() == null) return; + + int screenWidth = mBinding.recycleView.getWidth(); + if (screenWidth <= 0) return; + + // 计算item宽度 + int itemWidth = screenWidth / 3; + + // 计算屏幕中心位置 + int screenCenter = screenWidth / 2; + + // 计算目标item的中心位置(在当前可见区域中) + int targetItemCenter = (mBinding.recycleView.computeHorizontalScrollOffset() / itemWidth) * itemWidth + + position * itemWidth + itemWidth / 2; + + // 计算需要滚动的距离使目标item居中 + int scrollDistance = targetItemCenter - screenCenter; + + // 获取当前滚动位置 + int currentScrollX = mBinding.recycleView.computeHorizontalScrollOffset(); + + // 执行滚动使选中项居中 + mBinding.recycleView.smoothScrollBy(scrollDistance - currentScrollX, 0); + + } + + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/XlhObtainDialog.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/XlhObtainDialog.java new file mode 100644 index 00000000..9c5d8f31 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/XlhObtainDialog.java @@ -0,0 +1,109 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import android.content.Context; +import android.view.Gravity; +import android.view.Window; +import android.view.WindowManager; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; + +import com.blankj.utilcode.util.ScreenUtils; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.bean.blindboxwheel.XlhDrawBean; +import com.xscm.moduleutil.databinding.DialogHeavenGiftBinding; +import com.xscm.moduleutil.databinding.DialogXlhObtainBinding; +import com.xscm.moduleutil.widget.dialog.BaseDialog; + +import java.util.List; + +/** + * @author qx + * @data 2025/9/2 + * @description: 巡乐会恭喜或得礼弹窗 + */ +public class XlhObtainDialog extends BaseDialog { + + public interface OnGiftItemClickListener { + + void onPlayAgainClick(); + + void onCloseClick(); + } + + private GiftItemAdapter mAdapter; + private OnGiftItemClickListener mListener; + private List mGiftList; + + public XlhObtainDialog(@NonNull Context context) { + super(context, R.style.BaseDialogStyleH); + } + + public XlhObtainDialog(@NonNull Context context, List giftList) { + super(context, R.style.BaseDialogStyleH); + this.mGiftList = giftList; + } + + @Override + public int getLayoutId() { + return R.layout.dialog_xlh_obtain; + } + + @Override + public void initView() { + setCancelable(false); + setCanceledOnTouchOutside(false); + Window window = getWindow(); + // 设置对话框在屏幕中央显示 + window.setGravity(Gravity.CENTER); + // 去掉背景阴影 + window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); + + // 设置窗口背景为透明 + window.setBackgroundDrawableResource(android.R.color.transparent); + window.setLayout((int) (ScreenUtils.getScreenWidth() * 375.f / 375), WindowManager.LayoutParams.WRAP_CONTENT); + // 设置点击事件 + mBinding.xlhClose.setOnClickListener(v -> { + if (mListener != null) { + mListener.onCloseClick(); + } + dismiss(); + }); + + mBinding.ivAgain.setOnClickListener(v -> { + if (mListener != null) { + mListener.onPlayAgainClick(); + } + dismiss(); + }); + initRecyclerView(); + } + private void initRecyclerView() { + mAdapter = new GiftItemAdapter(); + mBinding.rvHead.setLayoutManager(new GridLayoutManager(getContext(), 3)); + mBinding.rvHead.setAdapter(mAdapter); + + } + + /** + * 设置礼物数据 + */ + public void setGiftList(List giftList) { + this.mGiftList = giftList; + if (mAdapter != null) { + mAdapter.setNewData(giftList); + } + } + + /** + * 设置点击回调监听器 + */ + public void setOnGiftItemClickListener(OnGiftItemClickListener listener) { + this.mListener = listener; + } + + @Override + public void initData() { + + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/XlhRankingDialog.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/XlhRankingDialog.java new file mode 100644 index 00000000..32bca684 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/XlhRankingDialog.java @@ -0,0 +1,176 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.scwang.smartrefresh.layout.api.RefreshLayout; +import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.base.BaseMvpDialogFragment; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.bean.WalletBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindReslutBean; +import com.xscm.moduleutil.bean.blindboxwheel.XlhDrawBean; +import com.xscm.moduleutil.databinding.DialogGiftLotteryFragmentBinding; +import com.xscm.moduleutil.databinding.DialogRankingXlhFragmentBinding; +import com.xscm.moduleutil.widget.pagerecyclerview.PagerGridSnapHelper; + +import java.util.ArrayList; +import java.util.List; +/** + *@author qx + *@data 2025/9/4 + *@description:巡乐会榜单 + */ +public class XlhRankingDialog extends BaseMvpDialogFragment implements GiftLotteryContacts.View{ + private int page=1; + private String roomId; + private GiftRecordAdapte giftRecordAdapte; + + @Override + protected GiftLotteryPresenter bindPresenter() { + return new GiftLotteryPresenter(this,getSelfActivity()); + } + + public static XlhRankingDialog newInstance(String giftBagId,int type) { + Bundle args = new Bundle(); + XlhRankingDialog fragment = new XlhRankingDialog(); + args.putString("roomId", giftBagId); + fragment.setArguments(args); + return fragment; + } + @Nullable + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + dialog.setCancelable(true); + return dialog; + } + + @Override + public void onStart() { + super.onStart(); + Window window = getDialog().getWindow(); + if (window != null) { + // 获取屏幕高度 + android.util.DisplayMetrics displayMetrics = new android.util.DisplayMetrics(); + requireActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + int screenHeight = displayMetrics.heightPixels; + // 设置高度为屏幕高度的100%(全屏) + int heightInPx = (int) (screenHeight * 0.8);; + window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, heightInPx); + window.setBackgroundDrawableResource(android.R.color.transparent); + + // 可选:设置动画样式(从底部弹出) + window.setWindowAnimations(R.style.CommonShowDialogBottom); + } + } + + @Override + protected void initDialogStyle(Window window) { + super.initDialogStyle(window); + window.setGravity(Gravity.BOTTOM); + } + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + roomId = getArguments().getString("roomId"); + + } + + @Override + protected void initData() { + MvpPre.xlhAllRecord(roomId, "1", "20",1); + + } + + + @Override + protected void initView() { + + mBinding.smartRefreshLayout.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onRefresh(@NonNull RefreshLayout refreshLayout) { + page = 1; + MvpPre.xlhAllRecord(roomId, page+"", "20",1); + + } + + @Override + public void onLoadMore(@NonNull RefreshLayout refreshLayout) { + page++; + MvpPre.xlhAllRecord(roomId, page+"", "20",1); + } + }); + + + giftRecordAdapte=new GiftRecordAdapte(); + mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false)); + mBinding.recyclerView.setAdapter(giftRecordAdapte); + } + + + @Override + protected int getLayoutId() { + return R.layout.dialog_ranking_xlh_fragment; + } + + @Override + public void getGiftListSuccess(BlindBoxBean blindBoxBean) { + + } + + @Override + public void drawGiftListSuccess(BlindReslutBean blindReslutBean) { + + } + + @Override + public void getMyRecordSuccess(List data) { + } + + @Override + public void getAllRecordSuccess(List data) { + + if (data != null){ + if (page==1){ + giftRecordAdapte.setNewData(data); + }else { + giftRecordAdapte.addData(data); + } + }else { + if (page == 1) { + giftRecordAdapte.setNewData(null); + } + } + } + + @Override + public void finishRefreshLoadMore() { + mBinding.smartRefreshLayout.finishRefresh(); + mBinding.smartRefreshLayout.finishLoadMore(); + } + + @Override + public void wallet(WalletBean walletBean) { + + } + + @Override + public void xlhChouSuccess(List data) { + + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/XlhRecordDialog.java b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/XlhRecordDialog.java new file mode 100644 index 00000000..9425492c --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/dialog/giftLottery/XlhRecordDialog.java @@ -0,0 +1,182 @@ +package com.xscm.moduleutil.dialog.giftLottery; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.scwang.smartrefresh.layout.api.RefreshLayout; +import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.base.BaseMvpDialogFragment; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.bean.WalletBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindReslutBean; +import com.xscm.moduleutil.bean.blindboxwheel.XlhDrawBean; +import com.xscm.moduleutil.databinding.DialogGiftLotteryFragmentBinding; +import com.xscm.moduleutil.databinding.DialogXlhRecordFragmentBinding; +import com.xscm.moduleutil.widget.pagerecyclerview.PagerGridSnapHelper; + +import java.util.ArrayList; +import java.util.List; +/** + *@author qx + *@data 2025/9/4 + *@description:巡乐会记录 + */ +public class XlhRecordDialog extends BaseMvpDialogFragment implements GiftLotteryContacts.View{ + + private int page=1; + private String roomId; + private GiftRecordAdapter adapter; + + @Override + protected GiftLotteryPresenter bindPresenter() { + return new GiftLotteryPresenter(this,getSelfActivity()); + } + + public static XlhRecordDialog newInstance(String roomId) { + Bundle args = new Bundle(); + XlhRecordDialog fragment = new XlhRecordDialog(); + args.putString("roomId", roomId); + fragment.setArguments(args); + return fragment; + } + @Nullable + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + dialog.setCancelable(true); + return dialog; + } + + @Override + public void onStart() { + super.onStart(); + Window window = getDialog().getWindow(); + if (window != null) { + // 获取屏幕高度 + android.util.DisplayMetrics displayMetrics = new android.util.DisplayMetrics(); + requireActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + int screenHeight = displayMetrics.heightPixels; + // 设置高度为屏幕高度的100%(全屏) + int heightInPx = (int) (screenHeight * 0.8);; + window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, heightInPx); + window.setBackgroundDrawableResource(android.R.color.transparent); + + // 可选:设置动画样式(从底部弹出) + window.setWindowAnimations(R.style.CommonShowDialogBottom); + } + } + + @Override + protected void initDialogStyle(Window window) { + super.initDialogStyle(window); + window.setGravity(Gravity.BOTTOM); + } + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + roomId = getArguments().getString("roomId"); + + } + + @Override + protected void initData() { + MvpPre.xlhMyRecord(roomId, "1", "20"); + + } + + + @Override + protected void initView() { + + + mBinding.smartRefreshLayout.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onRefresh(@NonNull RefreshLayout refreshLayout) { + page = 1; + MvpPre.xlhMyRecord(roomId, page+"", "20"); + + } + + @Override + public void onLoadMore(@NonNull RefreshLayout refreshLayout) { + page++; + MvpPre.xlhMyRecord(roomId, page+"", "20"); + } + }); + adapter=new GiftRecordAdapter(); + GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 3); + + mBinding.recyclerView.setLayoutManager(layoutManager); + mBinding.recyclerView.setOnFlingListener(null); + // 设置滚动辅助工具 + PagerGridSnapHelper pageSnapHelper = new PagerGridSnapHelper(); + pageSnapHelper.attachToRecyclerView(mBinding.recyclerView); + mBinding.recyclerView.setAdapter(adapter); + } + + + @Override + protected int getLayoutId() { + return R.layout.dialog_xlh_record_fragment; + } + + @Override + public void getGiftListSuccess(BlindBoxBean blindBoxBean) { + + } + + @Override + public void drawGiftListSuccess(BlindReslutBean blindReslutBean) { + + } + + @Override + public void getMyRecordSuccess(List data) { + if (data != null){ + if (page==1){ + adapter.setNewData(data); + }else { + adapter.addData(data); + } + }else { + if (page == 1) { + adapter.setNewData(null); + } + } + } + + @Override + public void getAllRecordSuccess(List data) { + + } + + @Override + public void finishRefreshLoadMore() { + mBinding.smartRefreshLayout.finishRefresh(); + mBinding.smartRefreshLayout.finishLoadMore(); + } + + @Override + public void wallet(WalletBean walletBean) { + + } + + @Override + public void xlhChouSuccess(List data) { + + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/event/FloatingScreenEvent.java b/moduleUtil/src/main/java/com/xscm/moduleutil/event/FloatingScreenEvent.java new file mode 100644 index 00000000..91ceb698 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/event/FloatingScreenEvent.java @@ -0,0 +1,17 @@ +package com.xscm.moduleutil.event; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + *@author qx + *@data 2025/9/22 + *@description: 关闭飘屏 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FloatingScreenEvent { + private boolean floatingScreen; +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/event/HourlyBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/event/HourlyBean.java new file mode 100644 index 00000000..8b9015c9 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/event/HourlyBean.java @@ -0,0 +1,17 @@ +package com.xscm.moduleutil.event; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 小时榜飘屏 + */ +@Data +public class HourlyBean implements Serializable { + private static final long serialVersionUID = 1L; + private String room_id; + private String room_name; + private String text; + private String rank_number; +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/event/LotteryEvent.java b/moduleUtil/src/main/java/com/xscm/moduleutil/event/LotteryEvent.java new file mode 100644 index 00000000..403733a2 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/event/LotteryEvent.java @@ -0,0 +1,37 @@ +package com.xscm.moduleutil.event; + +/** + *@author qx + *@data 2025/8/28 + *@description: 这是创建一枚举,根据类型的不同,创建不同的弹窗 + */ +public enum LotteryEvent { + + MIRROR_SKY("10"), // 天空之境 + CITY_TIME("11"), //岁月之城 + PINNACLE_TIME("12"); // 时光之巅 + + private final String type; + + LotteryEvent(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + // 根据giftBagId字符串判断类型 + public static LotteryEvent fromLotteryEvent(String giftBagId) { + if (giftBagId.equals("10")) { + return MIRROR_SKY; + } + if (giftBagId.equals("11")) { + return CITY_TIME; + } + if (giftBagId.equals("12")) { + return PINNACLE_TIME; + } + return MIRROR_SKY; + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/event/QXRoomSeatViewType.java b/moduleUtil/src/main/java/com/xscm/moduleutil/event/QXRoomSeatViewType.java new file mode 100644 index 00000000..376f4c7b --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/event/QXRoomSeatViewType.java @@ -0,0 +1,76 @@ +package com.xscm.moduleutil.event; + +public enum QXRoomSeatViewType { + /** + * 无类型 + */ + NONE(0, "无类型"), + + /** + * 普通麦位(二卡八麦) + */ + NORMAL(1, "点唱"), + + KTV(3,"K歌"), + + /** + * 拍卖麦位 + */ + AUCTION(2, "拍卖麦位"), + + + + /** + * 小黑屋麦位 + */ + CABIN(6, "小黑屋麦位"), + + /** + * 交友房麦位 + */ + FRIEND(7, "交友房麦位"); + + private final int value; + private final String description; + + QXRoomSeatViewType(int value, String description) { + this.value = value; + this.description = description; + } + + public int getValue() { + return value; + } + + public String getDescription() { + return description; + } + public static QXRoomSeatViewType fromLotteryEvent(int value) { + if (value==1) { + return NORMAL; + } + if (value==2) { + return AUCTION; + } + if (value==3) { + return KTV; + } + + if (value==6){ + return CABIN; + } + if (value==7){ + return FRIEND; + } + return NONE; + } + + @Override + public String toString() { + return "QXRoomSeatViewType{" + + "value=" + value + + ", description='" + description + '\'' + + '}'; + } + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/event/RedBean.java b/moduleUtil/src/main/java/com/xscm/moduleutil/event/RedBean.java new file mode 100644 index 00000000..aadd00ae --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/event/RedBean.java @@ -0,0 +1,14 @@ +package com.xscm.moduleutil.event; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class RedBean implements Serializable { + private static final long serialVersionUID = 1L; + private String room_id; + private String room_name; + private String text; + private String nickname; +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/event/RedEnvelopeStatus.java b/moduleUtil/src/main/java/com/xscm/moduleutil/event/RedEnvelopeStatus.java new file mode 100644 index 00000000..df40bce8 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/event/RedEnvelopeStatus.java @@ -0,0 +1,17 @@ +package com.xscm.moduleutil.event; +/** + * 红包打开状态 + */ +public enum RedEnvelopeStatus { + + /// 打开红包 + QXRedBagDrawTypeOpen, + /// 仅倒计时 + QXRedBagDrawTypeTimeDown, + /// 仅收藏房间 + QXRedBagDrawTypeCollect, + /// 手慢了被领完了 + QXRedBagDrawTypeFinished, + /// 发送评论领红包 + QXRedBagDrawTypePwdSend, +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/http/ApiResponseCallback.java b/moduleUtil/src/main/java/com/xscm/moduleutil/http/ApiResponseCallback.java new file mode 100644 index 00000000..4bb637ef --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/http/ApiResponseCallback.java @@ -0,0 +1,134 @@ +package com.xscm.moduleutil.http; + +import android.content.Context; +import android.widget.Toast; + +import com.blankj.utilcode.util.LogUtils; +import com.blankj.utilcode.util.ToastUtils; +import com.xscm.moduleutil.base.CommonAppContext; + +import org.greenrobot.eventbus.EventBus; + +import java.io.IOException; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * 通用的API响应处理回调类 + * 统一处理所有接口的响应和错误情况 + */ +public abstract class ApiResponseCallback implements Callback> { + private Context mContext; + + // 构造方法,传入上下文用于显示提示 + public ApiResponseCallback(Context context) { + this.mContext = context; + } + + @Override + public void onResponse(Call> call, Response> response) { + // 统一处理HTTP响应 + if (response.isSuccessful()) { + // 处理200-299范围内的HTTP状态码 + BaseModel body = response.body(); + + if (body != null) { + // 根据code值进行不同处理 + switch (body.getCode()) { + case 1: // 接口返回成功 + // 业务成功,回调给具体实现 + // 即使data为null也调用onSuccess,由具体实现决定如何处理null值 + onSuccess(body.getData()); + break; + case 0: // 接口请求成功但数据错误 + // 显示错误信息 +// String errorMsg = body.getMsg() != null ? body.getMsg() : "操作失败,请重试"; +// showToast(errorMsg); + onFailure(new Exception(body.getMsg())); + break; + case 301: // 登录失效 + // 显示错误信息并退出应用 +// String loginErrorMsg = body.getMsg() != null ? body.getMsg() : "登录已失效,请重新登录"; + showToast(body.getMsg()); + + try { + // 发送退出登录事件 +// EventBus.getDefault().post(new com.xscm.moduleutil.event.LogOutEvent()); + + // 清除登录信息 + CommonAppContext.getInstance().clearLoginInfo(); + + // 跳转到登录页面 +// android.content.Intent intent = new android.content.Intent(CommonAppContext.getInstance(), Class.forName("com.xscm.midi.LaunchPageActivity")); +// intent.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK | android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK); +// CommonAppContext.getInstance().startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + } + + onFailure(new Exception(body.getMsg())); + break; + default: + // 其他错误情况 + String defaultErrorMsg = body.getMsg() != null ? body.getMsg() : "未知错误"; + showToast(defaultErrorMsg); + onFailure(new Exception(defaultErrorMsg)); + break; + } + } else { + // 响应体为空的情况 + String errorMsg = "获取数据失败,请重试"; + showToast(errorMsg); + onFailure(new Exception(errorMsg)); + } + } else { + // 处理HTTP错误状态码 + String errorInfo; + try { + if (response.errorBody() != null) { + errorInfo = response.errorBody().string(); + // 可以在这里统一解析错误响应体 + } else { + errorInfo = "请求失败,状态码:" + response.code(); + } + } catch (IOException e) { + errorInfo = "请求失败,状态码:" + response.code(); + e.printStackTrace(); + } + showToast(""); + onFailure(new Exception(errorInfo)); + } + } + + @Override + public void onFailure(Call> call, Throwable t) { + // 统一处理网络异常 + String errorMsg; + if (t instanceof IOException) { +// errorMsg = "网络异常,请检查网络连接"; + } else { +// errorMsg = "请求处理失败,请重试"; + } + showToast(""); + // 回调给具体实现处理 + onFailure(t); + } + + // 显示提示信息 + private void showToast(String message) { + if (mContext != null) { + Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show(); + } + } + + // 业务成功时的回调,由具体接口实现 + public abstract void onSuccess(T data); + + // 错误时的回调,可选实现 + public void onFailure(Throwable t) { + // 可以留空,由子类选择性实现 + LogUtils.e("接口错误:",t); + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/http/BusinessAwareConverterFactory.java b/moduleUtil/src/main/java/com/xscm/moduleutil/http/BusinessAwareConverterFactory.java new file mode 100644 index 00000000..f41332de --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/http/BusinessAwareConverterFactory.java @@ -0,0 +1,74 @@ +package com.xscm.moduleutil.http; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; + +import com.blankj.utilcode.util.ToastUtils; +import com.xscm.moduleutil.base.CommonAppContext; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import okhttp3.ResponseBody; +import retrofit2.Converter; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +public class BusinessAwareConverterFactory extends Converter.Factory { + private final GsonConverterFactory originalFactory; + private final Context context; + + public BusinessAwareConverterFactory(Context context) { + this.context = context; + this.originalFactory = GsonConverterFactory.create(); + } + + @Override + public Converter responseBodyConverter(Type type, + Annotation[] annotations, + Retrofit retrofit) { + final Converter delegate = + originalFactory.responseBodyConverter(type, annotations, retrofit); + + return new Converter() { + @Override + public Object convert(ResponseBody value) throws IOException { + // 先读取响应字符串检查业务状态码 + String responseString = value.string(); + try { + JSONObject jsonObject = new JSONObject(responseString); + int code = jsonObject.getInt("code"); + String msg = jsonObject.getString("msg"); + + if (code == 301) { + handleForceLogout(); + ToastUtils.showShort(msg); + } + + // 重新构建 ResponseBody 供原始转换器使用 + ResponseBody newValue = ResponseBody.create(value.contentType(), responseString); + return delegate.convert(newValue); + + } catch (JSONException e) { + throw new IOException(""); + } + } + + private void handleForceLogout() { + new Handler(Looper.getMainLooper()).post(() -> { + try { + CommonAppContext.getInstance().clearLoginInfo(); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + + }); + } + }; + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/rtc/AgoraIsOPen.java b/moduleUtil/src/main/java/com/xscm/moduleutil/rtc/AgoraIsOPen.java new file mode 100644 index 00000000..ece2b682 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/rtc/AgoraIsOPen.java @@ -0,0 +1,13 @@ +package com.xscm.moduleutil.rtc; + +import lombok.Data; + +/** + *@author qx + *@data 2025/9/18 + *@description: 加入声网返回 + */ +@Data +public class AgoraIsOPen { + private boolean isOpen; +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/service/IMConnectionService.java b/moduleUtil/src/main/java/com/xscm/moduleutil/service/IMConnectionService.java new file mode 100644 index 00000000..c24d6b35 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/service/IMConnectionService.java @@ -0,0 +1,124 @@ +package com.xscm.moduleutil.service; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.Service; +import android.content.Intent; +import android.os.Build; +import android.os.IBinder; +import android.util.Log; + +import androidx.annotation.Nullable; + +import com.blankj.utilcode.util.LogUtils; +import com.blankj.utilcode.util.ToastUtils; +import com.tencent.imsdk.v2.V2TIMManager; +import com.tencent.imsdk.v2.V2TIMSDKListener; +import com.tencent.imsdk.v2.V2TIMUserFullInfo; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.base.CommonAppContext; +import com.xscm.moduleutil.http.RetrofitClient; + +public class IMConnectionService extends Service { + private static final String TAG = "IMConnectionService"; + private static final int NOTIFICATION_ID = 2; + private static final String CHANNEL_ID = "im_connection_channel"; + + private final V2TIMSDKListener imSdkListener = new V2TIMSDKListener() { + @Override + public void onConnecting() { + Log.d(TAG, "IM connecting..."); + } + + @Override + public void onConnectSuccess() {//重连成功 + Log.d(TAG, "IM connect success"); + if (CommonAppContext.getInstance().playId != null) { + LogUtils.e("@@@", ""+CommonAppContext.getInstance().playId); + RetrofitClient.getInstance().roomUserReconnect(CommonAppContext.getInstance().playId); + } + } + + @Override + public void onConnectFailed(int code, String error) { + Log.e(TAG, "IM connect failed, code: " + code + ", error: " + error); + } + + @Override + public void onKickedOffline() { + Log.w(TAG, "IM kicked offline"); + if (CommonAppContext.getInstance().playId != null) { + ToastUtils.showShort("您的账号已被挤下线"); + try { + CommonAppContext.getInstance().clearLoginInfo(); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + } + + + @Override + public void onUserSigExpired() { + Log.w(TAG, "IM user sig expired"); + } + + @Override + public void onSelfInfoUpdated(V2TIMUserFullInfo info) { + Log.d(TAG, "IM self info updated"); + } + + }; + + @Override + public void onCreate() { + super.onCreate(); + startForegroundService(); + V2TIMManager.getInstance().addIMSDKListener(imSdkListener); + Log.d(TAG, "IMConnectionService created and listener registered"); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return START_STICKY; // 服务被杀死后会自动重启 + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + private void startForegroundService() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // 创建通知渠道 + NotificationChannel channel = new NotificationChannel( + CHANNEL_ID, + "IM Connection Service", + NotificationManager.IMPORTANCE_LOW + ); + NotificationManager manager = getSystemService(NotificationManager.class); + if (manager != null) { + manager.createNotificationChannel(channel); + } + + // 创建通知 + Notification notification = new Notification.Builder(this, CHANNEL_ID) + .setContentTitle("IM连接服务") + .setContentText("保持IM连接活跃") + .setSmallIcon(R.mipmap.default_avatar) + .setOngoing(true) + .build(); + + startForeground(NOTIFICATION_ID, notification); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + V2TIMManager.getInstance().removeIMSDKListener(imSdkListener); + Log.d(TAG, "IMConnectionService destroyed and listener unregistered"); + } +} \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/service/MqttConnect.java b/moduleUtil/src/main/java/com/xscm/moduleutil/service/MqttConnect.java new file mode 100644 index 00000000..34427f00 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/service/MqttConnect.java @@ -0,0 +1,221 @@ +package com.xscm.moduleutil.service; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.widget.Toast; + +import com.blankj.utilcode.util.LogUtils; +import com.google.android.gms.common.api.Api; +import com.hjq.toast.ToastUtils; +import com.xscm.moduleutil.utils.logger.DataLogger; + +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.eclipse.paho.client.mqttv3.MqttTopic; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; + +import java.util.ArrayList; + +public class MqttConnect { + private String HOST; + private String Tag = "MQTT"; + private String clientId = ""; + private static MqttClient mqttClient = null; + private Context context; + + // 订阅主题 + public static String shutdown = ""; + public static String update_app = ""; + public static String qx_hour_ranking = ""; + + public static String qx_redpacket_arrive="";//红包飘屏的主题 + Handler handler = new Handler(Looper.getMainLooper()); + String[] topic; + int[] qos = {1,2,3,0,0,0,0,0,0,0,0,0,0}; // 消息质量 + private static MqttConnect instance; + + public MqttConnect(Context context, String host, String clientId) { + this.HOST = host; + this.context = context; + this.clientId = clientId; + + // 这里是你自己需要订阅的主题 + shutdown = "qx_room_topic"; // 关机 + update_app = "qx_xunlehui"; // 发送更新APP +// qx_hour_ranking = "qx_hour_ranking"; + qx_hour_ranking = "qx_hour_ranking"; + qx_redpacket_arrive="qx_redpacket_arrive"; + + ArrayList topicList = new ArrayList<>(); + topicList.add(shutdown); + topicList.add(update_app); + topicList.add(qx_hour_ranking); + topicList.add(qx_redpacket_arrive); + topic = topicList.toArray(new String[0]); + } + + /** + * 单列模式,只能实例化一次 + * @param context + * @param host + * @param clientId + * @return + */ + public static synchronized MqttConnect getInstance(Context context, String host, String clientId) { + if (instance == null) { + instance = new MqttConnect(context, host, clientId); + } + return instance; + } + + /** + * 客户端connect连接mqtt服务器 + **/ + public void mqttClient() + { +// close(); +// handler.postDelayed(new Runnable() { +// @Override +// public void run() { + try { +// uiTip("MQTT开始连接"); + MqttConnectOptions options = mqttConnectOptions(); + mqttClient.setCallback(new MqttInitCallback(context, HOST, clientId)); + mqttClient.connect(options); +// sub(topic,qos); + sub(shutdown); + sub(update_app); + sub(qx_hour_ranking); + sub(qx_redpacket_arrive); +// uiTip("MQTT连接成功"); + }catch (MqttException e){ +// uiTip("MQTT连接失败,准备重连。。。:"+e.getMessage()); + handler.postDelayed(new Runnable() { + @Override + public void run() { + Log.e(Tag,"开始重连。。。"); + mqttClient(); + } + },3000); + } +// } +// },200); + } + + /** + * 在主线程弹出消息 + * @param msg + */ + private void uiTip(String msg){ + Log.d(Tag,msg); + handler.post(new Runnable() { + @Override + public void run() { +// Toast.makeText(context.getApplicationContext(), msg, Toast.LENGTH_SHORT).show(); + LogUtils.e("mqtt","连接成功"); + ToastUtils.show(msg); + } + }); + } + + /** + * MQTT连接参数设置 + */ + private MqttConnectOptions mqttConnectOptions() + throws MqttException { + mqttClient = new MqttClient(HOST, clientId, new MemoryPersistence()); + MqttConnectOptions options = new MqttConnectOptions(); + options.setUserName("public"); + options.setConnectionTimeout(10); + options.setCleanSession(true); + options.setConnectionTimeout(10); + options.setKeepAliveInterval(10); + + return options; + } + + + /** + * 关闭MQTT连接 + */ + public void close(){ + if(mqttClient != null && mqttClient.isConnected()){ + try { + mqttClient.close(); + mqttClient.disconnect(); + mqttClient = null; + } catch (MqttException e) { + Log.e(Tag,"关闭MQTT连接报错:"+e.getMessage()); +// ToastUtils.show("关闭MQTT连接报错"); + } + }else { + Log.d(Tag,"Mqtt已关闭"); + } + } + + /** + * 向某个主题发布消息 默认qos:1 + */ + public static void pub(String topic, String msg) throws MqttException { + MqttMessage mqttMessage = new MqttMessage(); + mqttMessage.setPayload(msg.getBytes()); + MqttTopic mqttTopic = mqttClient.getTopic(topic); + MqttDeliveryToken token = mqttTopic.publish(mqttMessage); + token.waitForCompletion(); + } + + /** + * 向某个主题发布消息 + * + * @param topic: 发布的主题 + * @param msg: 发布的消息 + * @param qos: 消息质量 Qos:0、1、2 + */ + public void pub(String topic, String msg, int qos) throws MqttException { + MqttMessage mqttMessage = new MqttMessage(); + mqttMessage.setQos(qos); + mqttMessage.setPayload(msg.getBytes()); + MqttTopic mqttTopic = mqttClient.getTopic(topic); + MqttDeliveryToken token = mqttTopic.publish(mqttMessage); + token.waitForCompletion(); + } + + /** + * 订阅某一个主题 ,此方法默认的的Qos等级为:1 + * + * @param topic 主题 + */ + public void sub(String topic){ + try { + mqttClient.subscribe(topic); + } catch (MqttException e) { + Log.e(Tag,"MQTT主题订阅失败:" + e.getMessage()); +// uiTip("MQTT主题订阅失败"); + } + } + + /** + * 订阅某一个主题,可携带Qos + * + * @param topic 所要订阅的主题 + * @param qos + * 消息质量:0最多发送一次,不保证消息能够到达接收端,也不负责重发 + * 1至少发送一次,确保消息能够到达接收端,但可能会导致消息重复 + * 2确保消息恰好被接收一次 + */ + public void sub(String[] topic, int[] qos){ + try { + mqttClient.subscribe(topic, qos); + }catch (MqttException e){ + Log.e(Tag,"订阅主题失败:"+e.getMessage()); + } + } + + +// 原文链接:https://blog.csdn.net/Fyx1987496919/article/details/140516525 +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/service/MqttInitCallback.java b/moduleUtil/src/main/java/com/xscm/moduleutil/service/MqttInitCallback.java new file mode 100644 index 00000000..9db19811 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/service/MqttInitCallback.java @@ -0,0 +1,234 @@ +package com.xscm.moduleutil.service; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.blankj.utilcode.util.GsonUtils; +import com.blankj.utilcode.util.LogUtils; +import com.hjq.toast.ToastUtils; +import com.orhanobut.logger.Logger; +import com.xscm.moduleutil.bean.MqttXlhEnd; +import com.xscm.moduleutil.bean.XLHBean; +import com.xscm.moduleutil.event.HourlyBean; +import com.xscm.moduleutil.event.RedBean; +import com.xscm.moduleutil.event.RoomGiftRunable; +import com.xscm.moduleutil.utils.SpUtil; + +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallback; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.greenrobot.eventbus.EventBus; + +import java.util.List; + +public class MqttInitCallback implements MqttCallback { + private String Tag = "MqttInitCallback"; + private String HOST; + private String clientId = ""; + private MqttConnect mqttConnect = null; + private Context context = null; + + MqttInitCallback(Context context, String host, String clientId) { + this.context = context; + this.HOST = host; + this.clientId = clientId; + } + + /** + * 连接丢失 + */ + @Override + public void connectionLost(Throwable cause) { + Log.d(Tag, "mqtt连接断开,执行重连"); +// ToastUtils.show("mqtt连接断开,执行重连"); + mqttConnect = MqttConnect.getInstance(context, HOST, clientId); + mqttConnect.mqttClient(); + } + + /** + * subscribe订阅后得到的消息会执行到这里 + */ + @Override + public void messageArrived(String topic, MqttMessage message) { +// Log.d(Tag,"topic"); +// Log.d(Tag,topic); + + String messageStr = message.toString(); + Logger.e("MQTT", "收到的消息", "主题:" + topic + " 收到的消息:" + messageStr); + if (topic.equals("qx_room_topic")) { +// ToastUtils.show("收到礼物飘屏"); + receiveMessage(topic, messageStr); + } else if (topic.equals("qx_xunlehui")) { +// ToastUtils.show("收到轮盘飘屏"); + receiveXlhMessage(messageStr); + } else if (topic.equals("qx_hour_ranking")) { + receiveQXHourRanking(topic, messageStr); + } else if (topic.equals("qx_redpacket_arrive")) { + receiveRed(topic, messageStr); + } + } + + private void receiveRed(String topic, String messageStr) { + try { + JSONObject jsonObject = JSON.parseObject(messageStr); + String message = jsonObject.getString("msg"); + // 将事件处理放到主线程执行 + new Handler(Looper.getMainLooper()).post(() -> { + processRedMessage(topic, message); + }); + } catch (Exception e) { + Log.e("MQTT", "解析MQTT消息异常", e); + } + } + + private void processRedMessage(String topic, String message) { + try { + // 如果 data 是集合字符串 + // 解析为集合 + RedBean dataList = JSON.parseObject(message, RedBean.class); + + // 在主线程处理集合数据 + new Handler(Looper.getMainLooper()).post(() -> { + processDataRed(dataList); + }); + } catch (Exception e) { + Log.e("MQTT", "解析MQTT消息异常", e); + } + } + + private void processDataRed(RedBean dataList) { + // 遍历集合并发送每个元素 +// for (HourlyBean dataItem : dataList) { +// EventBus.getDefault().post(dataItem); +// } + + // 或者发送整个集合 + EventBus.getDefault().post(dataList); + } + + private void receiveQXHourRanking(String topic, String data) { + try { + JSONObject jsonObject = JSON.parseObject(data); + int type = jsonObject.getIntValue("type"); + String message = jsonObject.getString("msg"); + + // 将事件处理放到主线程执行 + new Handler(Looper.getMainLooper()).post(() -> { + processMessage(topic, message); + }); + } catch (Exception e) { + Log.e("MQTT", "解析MQTT消息异常", e); +// ToastUtils.show("收到礼物飘屏,解析异常"); + } + } + + private void processMessage(String topic, String data) { + try { + // 如果 data 是集合字符串 + if (isJsonArray(data)) { + // 解析为集合 + List dataList = JSON.parseArray(data, HourlyBean.class); + + // 在主线程处理集合数据 + new Handler(Looper.getMainLooper()).post(() -> { + processDataList(dataList); + }); + } + } catch (Exception e) { + Log.e("MQTT", "解析MQTT消息异常", e); + } + } + + // 处理集合数据 + private void processDataList(List dataList) { + // 遍历集合并发送每个元素 +// for (HourlyBean dataItem : dataList) { +// EventBus.getDefault().post(dataItem); +// } + + // 或者发送整个集合 + EventBus.getDefault().post(dataList); + } + + // 判断是否为 JSON 数组 + private boolean isJsonArray(String jsonString) { + try { + return JSON.parseArray(jsonString) != null; + } catch (Exception e) { + return false; + } + } + + private void receiveMessage(String topic, String data) { + try { + JSONObject jsonObject = JSON.parseObject(data); + int type = jsonObject.getIntValue("type"); + String message = jsonObject.getString("msg"); + + // 将事件处理放到主线程执行 + new Handler(Looper.getMainLooper()).post(() -> { + processMessageType(type, message); + }); + } catch (Exception e) { + Log.e("MQTT", "解析MQTT消息异常", e); +// ToastUtils.show("收到礼物飘屏,解析异常"); + } + } + + private void processMessageType(int type, String message) { + switch (type) { + case 5019://推送所有人-横幅礼物通知 + new RoomGiftRunable(message).run(); + break; + case 8000: +// XLHBean xlhBean= GsonUtils.fromJson(message, XLHBean.class); +// if (xlhBean!=null && xlhBean.getRoom_id()!=null && SpUtil.getMyRoomId()!=null) { +// if (xlhBean.getRoom_id().equals(SpUtil.getMyRoomId())) { +// if (xlhBean.getFrom_type()==3) { + LogUtils.e("MQTT", "收到消息" + message); + + MqttXlhEnd mqttXlhEnd = new MqttXlhEnd(); + mqttXlhEnd.setMessage(message); + EventBus.getDefault().post(mqttXlhEnd); + +// } +// } +// } + break; + default: + break; + } + } + + private void receiveXlhMessage(String messageStr) { + try { + JSONObject jsonObject = JSON.parseObject(messageStr); + int type = jsonObject.getIntValue("type"); + String message = jsonObject.getString("msg"); + XLHBean xlhBean = JSON.parseObject(message, XLHBean.class); + // 将事件处理放到主线程执行 + new Handler(Looper.getMainLooper()).post(() -> { + processMessageType(type, message); + EventBus.getDefault().post(xlhBean); + }); + } catch (Exception e) { + Log.e("MQTT", "解析MQTT消息异常", e); +// ToastUtils.show("收到轮盘飘屏,解析异常"); + } + } + + /** + * publish发布成功后会执行到这里 + */ + @Override + public void deliveryComplete(IMqttDeliveryToken token) { + + } + + +// 原文链接:https://blog.csdn.net/Fyx1987496919/article/details/140516525 +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/ClickUtils.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/ClickUtils.java new file mode 100644 index 00000000..ca420428 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/ClickUtils.java @@ -0,0 +1,19 @@ +package com.xscm.moduleutil.utils; +/** + *@author qx + *@data 2025/9/10 + *@description: 防止重复点击的工具类 + */ +public class ClickUtils { + private static final long CLICK_INTERVAL = 1000; // 1000ms内不允许重复点击 + private static long lastClickTime = 0; + + public static boolean isFastDoubleClick() { + long currentTime = System.currentTimeMillis(); + if (currentTime - lastClickTime < CLICK_INTERVAL) { + return true; + } + lastClickTime = currentTime; + return false; + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/CrashHandler.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/CrashHandler.java new file mode 100644 index 00000000..98b608d4 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/CrashHandler.java @@ -0,0 +1,41 @@ +package com.xscm.moduleutil.utils; + +import android.content.Context; +import android.util.Log; + +import com.alibaba.android.arouter.launcher.ARouter; + +public class CrashHandler implements Thread.UncaughtExceptionHandler { + private static CrashHandler instance; + private Thread.UncaughtExceptionHandler defaultHandler; + + private CrashHandler(Context context) { + defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + } + + public static void init(Context context) { + if (instance == null) { + instance = new CrashHandler(context); + Thread.setDefaultUncaughtExceptionHandler(instance); + } + } + + @Override + public void uncaughtException(Thread t, Throwable e) { + // 记录崩溃日志 + Log.e("CrashHandler", "未捕获异常: " + e.getMessage()); + // 简单处理空指针 + if (e instanceof NullPointerException) { + // 重启应用或跳转错误页 + restartApp(); + } else { + // 交给系统默认处理 + defaultHandler.uncaughtException(t, e); + } + } + + private void restartApp() { + // 实现应用重启逻辑 + ARouter.getInstance().build(ARouteConstants.ME).navigation(); + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/IMServiceManager.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/IMServiceManager.java new file mode 100644 index 00000000..c7fd461c --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/IMServiceManager.java @@ -0,0 +1,58 @@ +package com.xscm.moduleutil.utils; + +import android.content.Context; +import android.content.Intent; +import android.os.Build; + +import com.xscm.moduleutil.service.IMConnectionService; + +public class IMServiceManager { + private static IMServiceManager instance; + private boolean isServiceStarted = false; + + private IMServiceManager() { + } + + public static synchronized IMServiceManager getInstance() { + if (instance == null) { + instance = new IMServiceManager(); + } + return instance; + } + + public void startIMService(Context context) { + if (isServiceStarted) { + return; + } + + Intent serviceIntent = new Intent(context, IMConnectionService.class); + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.startForegroundService(serviceIntent); + } else { + context.startService(serviceIntent); + } + isServiceStarted = true; + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void stopIMService(Context context) { + if (!isServiceStarted) { + return; + } + + Intent serviceIntent = new Intent(context, IMConnectionService.class); + try { + context.stopService(serviceIntent); + isServiceStarted = false; + } catch (Exception e) { + e.printStackTrace(); + } + } + + public boolean isServiceStarted() { + return isServiceStarted; + } +} \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/MemoryOptimizationUtils.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/MemoryOptimizationUtils.java new file mode 100644 index 00000000..56ac405a --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/MemoryOptimizationUtils.java @@ -0,0 +1,105 @@ +package com.xscm.moduleutil.utils; + +import android.content.Context; + +import com.blankj.utilcode.util.LogUtils; +import com.bumptech.glide.Glide; +import com.orhanobut.logger.Logger; + +public class MemoryOptimizationUtils { + private static final String TAG = "MemoryOptimization"; + + /** + * 检查内存状态 + */ + public static boolean isMemoryLow() { + Runtime runtime = Runtime.getRuntime(); + long usedMemory = runtime.totalMemory() - runtime.freeMemory(); + long maxMemory = runtime.maxMemory(); + double memoryUsage = (double) usedMemory / maxMemory; + + LogUtils.d(TAG, "Memory usage: " + (memoryUsage * 100) + "%"); + + // 内存使用超过85%认为是低内存 + return memoryUsage > 0.85; + } + private static long lastGCTime = 0; + private static final long MIN_GC_INTERVAL = 5000; // 5秒最小间隔 + + /** + * 强制进行垃圾回收 + */ + public static void forceGC() { + long currentTime = System.currentTimeMillis(); + + // 避免频繁调用GC + if (currentTime - lastGCTime < MIN_GC_INTERVAL) { + Logger.d(TAG, "Skipping GC, too frequent"); + return; + } + + lastGCTime = currentTime; + + // 使用异步方式调用GC + new Thread(() -> { + try { + // 在后台线程执行GC + System.gc(); + Thread.sleep(100); // 给GC一些时间 + Runtime.getRuntime().runFinalization(); + Logger.d(TAG, "Garbage collection completed"); + } catch (Exception e) { + Logger.e(TAG, "Error during GC: " + e.getMessage()); + } + }).start(); + } + + /** + * 清理图片缓存 + */ + public static void clearImageCache(Context context) { + try { + // 清理Glide缓存 + Glide.get(context).clearMemory(); + + // 在后台线程清理磁盘缓存 + new Thread(() -> { + try { + Glide.get(context).clearDiskCache(); + } catch (Exception e) { + LogUtils.e(TAG, "Error clearing Glide disk cache: " + e.getMessage()); + } + }).start(); + } catch (Exception e) { + LogUtils.e(TAG, "Error clearing image cache: " + e.getMessage()); + } + } + /** + * 获取当前内存使用情况 + */ + public static String getMemoryInfo() { + Runtime runtime = Runtime.getRuntime(); + long maxMemory = runtime.maxMemory(); + long totalMemory = runtime.totalMemory(); + long freeMemory = runtime.freeMemory(); + long usedMemory = totalMemory - freeMemory; + + return String.format("Max: %d MB, Total: %d MB, Used: %d MB, Free: %d MB", + maxMemory / (1024 * 1024), + totalMemory / (1024 * 1024), + usedMemory / (1024 * 1024), + freeMemory / (1024 * 1024)); + } + /** + * 清理SVGA缓存 + */ + public static void clearSVGACache() { + try { + // 如果SVGA库提供了清理缓存的方法,调用它 + // SVGAParser.clearCache(); // 假设有这样的方法 + } catch (Exception e) { + LogUtils.e(TAG, "Error clearing SVGA cache: " + e.getMessage()); + } + } +} + diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/QXRedPacketManager.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/QXRedPacketManager.java new file mode 100644 index 00000000..2e57a881 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/QXRedPacketManager.java @@ -0,0 +1,281 @@ +package com.xscm.moduleutil.utils; + +import android.os.Handler; +import android.os.Looper; +import com.blankj.utilcode.util.LogUtils; +import com.xscm.moduleutil.bean.RedPacketInfo; +import lombok.Getter; +import lombok.Setter; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 红包管理器单例类 + */ +public class QXRedPacketManager { + private static QXRedPacketManager instance; + private final Map redPackets; + private Handler checkTimerHandler; + private Runnable checkTimerRunnable; + + // 私有构造函数,防止外部实例化 + private QXRedPacketManager() { + this.redPackets = new ConcurrentHashMap<>(); + } + + /** + * 获取单例实例 + * + * @return QXRedPacketManager 单例 + */ + public static QXRedPacketManager getInstance() { + if (instance == null) { + synchronized (QXRedPacketManager.class) { + if (instance == null) { + instance = new QXRedPacketManager(); + } + } + } + return instance; + } + public List getSortedUserListLambda(Map userMap) { + List redPacketInfoList = new ArrayList<>(userMap.values()); + redPacketInfoList.sort((user1, user2) -> Long.compare(user1.getStart_time(), user2.getStart_time())); + return redPacketInfoList; + } + + /** + * 添加红包列表 + * + * @param redPackets 红包模型列表 + */ + public void addRedPackets(List redPackets) { + if (redPackets == null || redPackets.isEmpty()) { + return; + } + + for (RedPacketInfo model : redPackets) { + this.redPackets.put(model.getRedpacket_id(), model); + } + + // 在添加数据后启动定时器(如果尚未启动) + startCheckTimer(); + if (this.delegate != null && this.delegate instanceof QXRedPacketManagerDelegate) { + ((QXRedPacketManagerDelegate) this.delegate).onRedPacketsAdded(redPackets, this.redPackets.size()); + } + } + + /** + * 添加单个红包 + * + * @param redPacket 红包模型 + */ + public void addRedPacket(RedPacketInfo redPacket) { + if (redPacket == null || redPacket.getRedpacket_id() == null) { + return; + } + + this.redPackets.put(redPacket.getRedpacket_id(), redPacket); + + // 在添加数据后启动定时器(如果尚未启动) + startCheckTimer(); + if (this.delegate != null && this.delegate instanceof QXRedPacketManagerDelegate) { + ((QXRedPacketManagerDelegate) this.delegate).onRedPacketAdded(redPacket, this.redPackets.size()); + } + } + + /** + * 移除红包 + * + * @param packetId 红包ID + */ + public void removeRedPacket(String packetId) { + this.redPackets.remove(packetId); + + if (this.delegate != null && this.delegate instanceof QXRedPacketManagerDelegate) { + ((QXRedPacketManagerDelegate) this.delegate).onRedPacketRemoved(packetId, this.redPackets.size()); + } + } + + /** + * 获取所有红包 + * + * @return 红包列表 + */ + public List getAllRedPackets() { + return getSortedUserListLambda(redPackets); + } + + /** + * 根据ID获取红包 + * + * @param packetId 红包ID + * @return 红包模型 + */ + public RedPacketInfo getRedPacket(String packetId) { + return this.redPackets.get(packetId); + } + + /** + * 开始检查定时器 + */ + public void startCheckTimer() { + // 如果定时器已经在运行,直接返回 + if (checkTimerRunnable != null && checkTimerHandler != null) { + return; + } + if (checkTimerRunnable == null) { + checkTimerRunnable = new Runnable() { + @Override + public void run() { + checkAndUpdateRedPackets(); + } + }; + + checkTimerHandler = new Handler(Looper.getMainLooper()); + checkTimerHandler.post(checkTimerRunnable); + } + } + + /** + * 检查并更新红包状态 + */ + private void checkAndUpdateRedPackets() { + // 添加空值检查 + if (this.redPackets == null || this.redPackets.isEmpty()) { + return; + } + List packets = getAllRedPackets(); + + for (RedPacketInfo packet : packets) { + long packetTime = packet.remainingTime(); + LogUtils.e("红包剩余时间:" + packet.getRedpacket_time()); + long redpacketTime = 0; + try { + if (packet.getRedpacket_time() != null) { + redpacketTime = Long.parseLong(packet.getRedpacket_time()); + } + } catch (NumberFormatException e) { + LogUtils.e("红包时间格式错误: " + packet.getRedpacket_time()); + } + if (packetTime <= -redpacketTime) { + + removeRedPacket(packet.getRedpacket_id()); + } + if (packet.getCountdown()==0){ + continue; + } + + if (this.delegate != null && this.delegate instanceof QXRedPacketManagerDelegate) { + ((QXRedPacketManagerDelegate) this.delegate).didUpdateRedPacketTime(packet, packetTime); + } + + boolean wasAvailable = packet.isAvailable(); + packet.setAvailable(packet.canOpenNow()); + + // 状态发生变化时通知 + if (wasAvailable != packet.isAvailable()) { + if (this.delegate != null && this.delegate instanceof QXRedPacketManagerDelegate) { + ((QXRedPacketManagerDelegate) this.delegate).onRedPacketUpdated(packet, this.redPackets.size()); + } + } + } + + // 继续执行定时任务 + // 修复:增加空值检查避免 NullPointerException + if (checkTimerHandler != null && checkTimerRunnable != null) { + // 继续执行定时任务 + checkTimerHandler.postDelayed(checkTimerRunnable, 1000); + } + } + + /** + * 移除所有红包 + */ + public void removeAllRedPackets() { + this.redPackets.clear(); + endCheckTimer(); + } + + /** + * 结束检查定时器 + */ + public void endCheckTimer() { + if (checkTimerHandler != null) { + checkTimerHandler.removeCallbacks(checkTimerRunnable); + checkTimerHandler = null; + checkTimerRunnable = null; + } + } + + /** + * 销毁红包信息 + */ + public void destroyRedpacketInfo() { + removeAllRedPackets(); + endCheckTimer(); + this.delegate = null; + } + + /** + * 委托接口 + */ + public interface QXRedPacketManagerDelegate { + /** + * 添加红包列表回调 + * + * @param redPackets 红包列表 + * @param remainingCount 剩余数量 + */ + void onRedPacketsAdded(List redPackets, int remainingCount); + + /** + * 添加单个红包回调 + * + @param redPacket 红包模型 + * @param remainingCount 剩余数量 + */ + void onRedPacketAdded(RedPacketInfo redPacket, int remainingCount); + + /** + * 移除红包回调 + * + * @param packetId 红包ID + * @param remainingCount 剩余数量 + */ + void onRedPacketRemoved(String packetId, int remainingCount); + + /** + * 更新红包状态回调 + * + * @param packet 红包模型 + * @param remainingCount 剩余数量 + */ + void onRedPacketUpdated(RedPacketInfo packet, int remainingCount); + + /** + * 更新红包时间回调 + * + * @param packet 红包模型 + * @param packetTime 红包剩余时间 + */ + void didUpdateRedPacketTime(RedPacketInfo packet, long packetTime); + } + + /** + * -- SETTER -- + * 设置委托对象 + * + * + * -- GETTER -- + * 获取委托对象 + * + @param delegate 委托对象 + * @return 委托对象 + */ + @Getter + @Setter + private QXRedPacketManagerDelegate delegate; +} + diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/TextViewUtils.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/TextViewUtils.java new file mode 100644 index 00000000..d25a5321 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/TextViewUtils.java @@ -0,0 +1,171 @@ +package com.xscm.moduleutil.utils; +import android.graphics.Color; +import android.graphics.Typeface; +import android.os.Build; +import android.text.Html; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.method.LinkMovementMethod; +import android.text.style.BackgroundColorSpan; +import android.text.style.ClickableSpan; +import android.text.style.ForegroundColorSpan; +import android.text.style.RelativeSizeSpan; +import android.text.style.StrikethroughSpan; +import android.text.style.StyleSpan; +import android.text.style.UnderlineSpan; +import android.view.View; +import android.widget.TextView; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; + +/** + * TextView 富文本工具类(Java实现) + * 支持HTML解析、部分文本样式、点击事件等功能 + */ +public class TextViewUtils { + + /** + * 显示HTML格式文本 + * @param textView 目标TextView + * @param htmlContent HTML内容字符串 + */ + public static void setHtmlText(TextView textView, String htmlContent) { + setHtmlText(textView, htmlContent, true); + } + + /** + * 显示HTML格式文本(可控制链接点击) + * @param textView 目标TextView + * @param htmlContent HTML内容字符串 + * @param enableLinks 是否启用链接点击 + */ + public static void setHtmlText(TextView textView, String htmlContent, boolean enableLinks) { + if (textView == null || htmlContent == null) return; + + // 处理不同Android版本的HTML解析 + CharSequence spannedText; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + spannedText = Html.fromHtml(htmlContent, Html.FROM_HTML_MODE_COMPACT); + } else { + // 兼容Android N以下版本 + spannedText = Html.fromHtml(htmlContent); + } + + textView.setText(spannedText); + + // 启用链接点击功能 + if (enableLinks) { + textView.setMovementMethod(LinkMovementMethod.getInstance()); + textView.setHighlightColor(Color.TRANSPARENT); // 去除点击高亮 + } + } + + /** + * 给部分文本设置样式 + * @param textView 目标TextView + * @param fullText 完整文本 + * @param targetText 需要设置样式的子文本 + * @param spans 样式集合(可传入多个) + */ + public static void setPartialStyle(TextView textView, String fullText, + String targetText, Object... spans) { + if (textView == null || fullText == null || targetText == null) return; + + int startIndex = fullText.indexOf(targetText); + if (startIndex == -1) { + textView.setText(fullText); + return; + } + + int endIndex = startIndex + targetText.length(); + SpannableString spannable = new SpannableString(fullText); + + // 应用所有样式 + for (Object span : spans) { + spannable.setSpan(span, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + + textView.setText(spannable); + } + + /** + * 设置可点击文本 + * @param textView 目标TextView + * @param fullText 完整文本 + * @param clickText 可点击的子文本 + * @param linkColor 链接颜色 + * @param isUnderline 是否显示下划线 + * @param listener 点击事件监听器 + */ + public static void setClickableText(TextView textView, String fullText, String clickText, + @ColorInt int linkColor, boolean isUnderline, + OnClickableTextListener listener) { + if (textView == null || fullText == null || clickText == null || listener == null) return; + + int startIndex = fullText.indexOf(clickText); + if (startIndex == -1) { + textView.setText(fullText); + return; + } + + int endIndex = startIndex + clickText.length(); + SpannableString spannable = new SpannableString(fullText); + + // 创建可点击样式 + ClickableSpan clickableSpan = new ClickableSpan() { + @Override + public void onClick(@NonNull View widget) { + listener.onClick(); + } + + @Override + public void updateDrawState(@NonNull android.text.TextPaint ds) { + super.updateDrawState(ds); + ds.setColor(linkColor); + ds.setUnderlineText(isUnderline); + } + }; + + spannable.setSpan(clickableSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + textView.setText(spannable); + textView.setMovementMethod(LinkMovementMethod.getInstance()); + textView.setHighlightColor(Color.TRANSPARENT); + } + + // 快捷创建样式的工具方法 + public static StyleSpan createBoldSpan() { + return new StyleSpan(Typeface.BOLD); + } + + public static StyleSpan createItalicSpan() { + return new StyleSpan(Typeface.ITALIC); + } + + public static ForegroundColorSpan createTextColorSpan(@ColorInt int color) { + return new ForegroundColorSpan(color); + } + + public static BackgroundColorSpan createBgColorSpan(@ColorInt int color) { + return new BackgroundColorSpan(color); + } + + public static UnderlineSpan createUnderlineSpan() { + return new UnderlineSpan(); + } + + public static StrikethroughSpan createStrikethroughSpan() { + return new StrikethroughSpan(); + } + + public static RelativeSizeSpan createTextSizeSpan(float proportion) { + return new RelativeSizeSpan(proportion); + } + + /** + * 可点击文本的监听器接口 + */ + public interface OnClickableTextListener { + void onClick(); + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/CosUploadManager.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/CosUploadManager.java new file mode 100644 index 00000000..c3d916c1 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/CosUploadManager.java @@ -0,0 +1,146 @@ +package com.xscm.moduleutil.utils.cos; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import androidx.annotation.Nullable; +import com.blankj.utilcode.util.LogUtils; +import com.tencent.cos.xml.CosXmlService; +import com.tencent.cos.xml.CosXmlServiceConfig; +import com.tencent.cos.xml.exception.CosXmlClientException; +import com.tencent.cos.xml.exception.CosXmlServiceException; +import com.tencent.cos.xml.listener.CosXmlResultListener; +import com.tencent.cos.xml.model.CosXmlRequest; +import com.tencent.cos.xml.model.CosXmlResult; +import com.tencent.cos.xml.model.object.PutObjectRequest; +import com.tencent.cos.xml.transfer.COSXMLUploadTask; +import com.tencent.cos.xml.transfer.TransferConfig; +import com.tencent.cos.xml.transfer.TransferManager; +import com.tencent.qcloud.core.auth.SessionQCloudCredentials; +import com.xscm.moduleutil.http.BaseObserver; +import com.xscm.moduleutil.http.RetrofitClient; +import com.xscm.moduleutil.utils.oss.OSSOperUtils; +import io.reactivex.disposables.Disposable; +import org.jetbrains.annotations.NotNull; + + +/** + * com.xscm.moduleutil.utils.cos + * qx + * 2025/10/23 + */ +public class CosUploadManager { + private static volatile CosUploadManager instance; + private Context context; + private Handler mainHandler; + // 私有构造函数,防止外部实例化 + private CosUploadManager() { + mainHandler = new Handler(Looper.getMainLooper()); + } + + // 双重检查锁定获取单例实例 + public static CosUploadManager getInstance() { + if (instance == null) { + synchronized (CosUploadManager.class) { + if (instance == null) { + instance = new CosUploadManager(); + } + } + } + return instance; + } + public void init(Context context) { + this.context = context.getApplicationContext(); + } + public void upParameters( String objectKey, String localPath, UploadCallback callback) { + // 确保已初始化 + if (context == null) { + callback.onFailure(new IllegalStateException("CosUploadManager not initialized with context")); + return; + } + RetrofitClient.getInstance().getTempKey(new BaseObserver() { + @Override + public void onSubscribe(@NotNull Disposable disposable) { + + } + + @Override + public void onNext(@NotNull TempKeyBean tempKeyBean) { + if (tempKeyBean != null){ + upCosData(tempKeyBean, tempKeyBean.getBucket(), objectKey, localPath, callback); + } + } + }); + } + + public void upCosData(TempKeyBean tempKeyBean, String bucketName, String objectKey, String localFilePath, UploadCallback callback){ + // 获取临时密钥(业务层控制获取的方式) + String tmpSecretId = tempKeyBean.getCredentials().getTmpSecretId(); // 临时密钥 SecretId + String tmpSecretKey = tempKeyBean.getCredentials().getTmpSecretKey(); // 临时密钥 SecretKey + String sessionToken = tempKeyBean.getCredentials().getSessionToken(); // 临时密钥 Token + long expiredTime = tempKeyBean.getExpiredTime();//临时密钥有效截止时间戳,单位是秒 +// 建议返回服务器时间作为签名的开始时间,避免由于用户手机本地时间偏差过大导致请求过期 + long startTime = tempKeyBean.getStartTime(); //临时密钥有效起始时间,单位是秒 + // 存储桶所在地域简称,例如广州地区是 ap-guangzhou + String region = tempKeyBean.getRegion(); + + SessionQCloudCredentials sessionQCloudCredentials = new SessionQCloudCredentials(tmpSecretId, tmpSecretKey, + sessionToken, startTime, expiredTime); + // 创建 CosXmlServiceConfig 对象,根据需要修改默认的配置参数 + CosXmlServiceConfig serviceConfig = new CosXmlServiceConfig.Builder() + .setRegion(region) + .isHttps(true) // 使用 HTTPS 请求, 默认为 HTTP 请求 + .builder(); + CosXmlService cosXmlService = new CosXmlService(context, serviceConfig); + + // 任何 CosXmlRequest 都支持这种方式,例如上传 PutObjectRequest、下载 GetObjectRequest、删除 DeleteObjectRequest 等 +// 以下用上传进行示例 + PutObjectRequest putRequest = new PutObjectRequest(bucketName, objectKey, localFilePath); +// sessionQCloudCredentials 为第一步“初始化密钥”中获取到的单次临时密钥 + putRequest.setCredential(sessionQCloudCredentials); +// 初始化 TransferConfig,这里使用默认配置,如果需要定制,请参考 SDK 接口文档 + TransferConfig transferConfig = new TransferConfig.Builder().build(); +// 初始化 TransferManager + TransferManager transferManager = new TransferManager(cosXmlService, transferConfig); + COSXMLUploadTask uploadTask = transferManager.upload(putRequest, null); + uploadTask.setCosXmlResultListener(new CosXmlResultListener() { + + @Override + public void onSuccess(CosXmlRequest cosXmlRequest, CosXmlResult cosXmlResult) { + COSXMLUploadTask.COSXMLUploadTaskResult uploadResult = + (COSXMLUploadTask.COSXMLUploadTaskResult) cosXmlResult; + LogUtils.e("@@@1", "上传成功", "描述:", "文件ID" + uploadResult); + // 如果有回调,则调用成功回调 + if (callback != null) { + // 构造文件访问URL + String url =uploadResult.accessUrl; + mainHandler.post(() -> callback.onSuccess(url)); + } + } + + @Override + public void onFail(CosXmlRequest cosXmlRequest, @Nullable @org.jetbrains.annotations.Nullable CosXmlClientException e, @Nullable @org.jetbrains.annotations.Nullable CosXmlServiceException e1) { + // 切换到主线程执行回调 + mainHandler.post(() -> { + if (e != null) { + LogUtils.e("CosUpload", "上传失败", e); + if (callback != null) { + callback.onFailure(e); + } + } else { + LogUtils.e("CosUpload", "上传失败", e1); + if (callback != null) { + callback.onFailure(e1); + } + } + }); + } + }); + } + + // 上传回调接口 + public interface UploadCallback { + void onSuccess(String url); // 上传成功,返回访问URL + void onFailure(Exception e); // 上传失败 + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/FilePathHelpe.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/FilePathHelpe.java new file mode 100644 index 00000000..86d67981 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/FilePathHelpe.java @@ -0,0 +1,216 @@ +package com.xscm.moduleutil.utils.cos; + +import android.annotation.SuppressLint; +import android.content.ContentUris; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.provider.DocumentsContract; +import android.provider.MediaStore; +import android.util.Log; +import androidx.annotation.RequiresApi; + +/** + * com.xscm.moduleutil.utils.cos + * qx + * 2025/10/23 + */ +public class FilePathHelpe { + + public static String getPathFromUri(Context context, Uri uri) { + + String scheme = uri.getScheme(); + Log.d("TAG", scheme); + if (scheme.equalsIgnoreCase("content")) { + return getPathFromMediaUri(context, uri); + } else if (scheme.equalsIgnoreCase("file")){ + return getPathFromFileUri(context, uri); + } + return ""; + } + + + private static String getPathFromMediaUri(Context context, Uri uri) { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + return getKitKatPathFromMediaUri(context, uri); + } else { + return getImagePathFromMediaUri(context, uri, null); + } + } + + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + private static String getKitKatPathFromMediaUri(Context context, Uri uri) { + + String imagePath = ""; + if (DocumentsContract.isDocumentUri(context, uri)) { + String docId = DocumentsContract.getDocumentId(uri); + if ("com.android.providers.media.documents".equals(uri.getAuthority())) { + //Log.d(TAG, uri.toString()); + String id = docId.split(":")[1]; + String selection = MediaStore.Images.Media._ID + "=" + id; + + imagePath = getImagePathFromMediaUri(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection); + } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) { + //Log.d(TAG, uri.toString()); + Uri contentUri = ContentUris.withAppendedId( + Uri.parse("content://downloads/public_downloads"), + Long.valueOf(docId)); + imagePath = getImagePathFromMediaUri(context, contentUri, null); + } + } else if ("content".equalsIgnoreCase(uri.getScheme())) { + //Log.d(TAG, "content: " + uri.toString()); + imagePath = getImagePathFromMediaUri(context, uri, null); + } + return imagePath; + } + + @SuppressLint("Range") + private static String getImagePathFromMediaUri(Context context, Uri uri, String selection) { + String path = null; + Cursor cursor = context.getContentResolver().query(uri, null, selection, null, null); + if (cursor != null) { + if (cursor.moveToFirst()) { + //path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); + path = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA)); + } + + cursor.close(); + } + return path; + } + + private static String getPathFromFileUri(Context context, Uri uri) { + + return uri.getPath(); + } + + + public static String getPathBeforeKitKat(Context context, Uri uri) { + if ("content".equalsIgnoreCase(uri.getScheme())) { + String[] projection = { MediaStore.MediaColumns.DATA }; + Cursor cursor = null; + try { + cursor = context.getContentResolver().query(uri, projection,null, null, null); + int column_index = cursor.getColumnIndexOrThrow("_data"); + if (cursor.moveToFirst()) { + return cursor.getString(column_index); + } + } catch (Exception e) { + + } finally { + if(cursor != null) + cursor.close(); + } + } else if ("file".equalsIgnoreCase(uri.getScheme())) { + return uri.getPath(); + } + + return null; + } + + @SuppressLint("NewApi") + public static String getPathAfterKitKat(Context context, Uri uri) { + + if (DocumentsContract.isDocumentUri(context, uri)) { + // ExternalStorageProvider + if (isExternalStorageDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + if ("primary".equalsIgnoreCase(type)) { + return Environment.getExternalStorageDirectory() + "/" + split[1]; + } + + // TODO handle non-primary volumes + } + // DownloadsProvider + else if (isDownloadsDocument(uri)) { + + final String id = DocumentsContract.getDocumentId(uri); + final Uri contentUri = ContentUris.withAppendedId( + Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); + + return getDataColumn(context, contentUri, null, null); + } + // MediaProvider + else if (isMediaDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + Uri contentUri = null; + if ("image".equals(type)) { + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else if ("video".equals(type)) { + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + } else if ("audio".equals(type)) { + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + } + + final String selection = "_id=?"; + final String[] selectionArgs = new String[] { split[1] }; + + return getDataColumn(context, contentUri, selection, selectionArgs); + } + } + // MediaStore (and general) + else if ("content".equalsIgnoreCase(uri.getScheme())) { + return getDataColumn(context, uri, null, null); + } + // File + else if ("file".equalsIgnoreCase(uri.getScheme())) { + return uri.getPath(); + } + + return null; + } + + + public static String getDataColumn(Context context, Uri uri, String selection, + String[] selectionArgs) { + + Cursor cursor = null; + final String column = "_data"; + final String[] projection = { column }; + + try { + cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, + null); + if (cursor != null && cursor.moveToFirst()) { + final int column_index = cursor.getColumnIndexOrThrow(column); + return cursor.getString(column_index); + } + } finally { + if (cursor != null) + cursor.close(); + } + return null; + } + + + public static boolean isExternalStorageDocument(Uri uri) { + return "com.android.externalstorage.documents".equals(uri.getAuthority()); + } + + + public static boolean isDownloadsDocument(Uri uri) { + return "com.android.providers.downloads.documents".equals(uri.getAuthority()); + } + + + public static boolean isMediaDocument(Uri uri) { + return "com.android.providers.media.documents".equals(uri.getAuthority()); + } + + public static String getPath(Context context, Uri uri) { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + return getPathAfterKitKat(context, uri); + } + return getPathBeforeKitKat(context, uri); + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/RemoteCOSSigner.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/RemoteCOSSigner.java new file mode 100644 index 00000000..fc0affc0 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/RemoteCOSSigner.java @@ -0,0 +1,158 @@ +package com.xscm.moduleutil.utils.cos; + +import android.text.TextUtils; +import com.tencent.qcloud.core.auth.QCloudCredentials; +import com.tencent.qcloud.core.auth.QCloudSigner; +import com.tencent.qcloud.core.common.QCloudClientException; +import com.tencent.qcloud.core.common.QCloudServiceException; +import com.tencent.qcloud.core.http.QCloudHttpClient; +import com.tencent.qcloud.core.http.QCloudHttpRequest; +import com.tencent.qcloud.core.http.RequestBodySerializer; +import org.json.JSONException; +import org.json.JSONObject; + +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * com.xscm.moduleutil.utils.cos + * qx + * 2025/10/23 + */ +public class RemoteCOSSigner implements QCloudSigner { + + private URL requestSignUrl; + + public RemoteCOSSigner(URL url) { + + requestSignUrl = url; + } + + /** + * @param request 即为发送到 CSP 服务端的请求,您需要根据这个 HTTP 请求的参数来计算签名,并给其添加 Authorization header + * @param credentials 空字段,请不要使用 + * @throws QCloudClientException 您可以在处理过程中抛出异常 + */ + @Override + public void sign(QCloudHttpRequest request, QCloudCredentials credentials) throws QCloudClientException { + + /** + * 获取计算签名所需字段 + */ + URL url = request.url(); + String method = request.method(); + String host = url.getHost(); + String schema = url.getProtocol(); + String path = url.getPath(); + Map headers = getHeaderMap(request.headers()); + Map params = getQueryMap(url.getQuery()); + + + String signFieldJson = null; + try { + signFieldJson = signField2Json(method, schema, host, path, headers, params); + } catch (JSONException e) { + e.printStackTrace(); + throw new QCloudClientException("sign field transfer to json failed"); + } + + + /** + * 向您自己的服务端请求签名 + */ + QCloudHttpRequest httpRequest = new QCloudHttpRequest.Builder() + .method("PUT") + .url(requestSignUrl) + .body(RequestBodySerializer.string(null, signFieldJson)) + .build(); + + String response = null; + try { + response = QCloudHttpClient.getDefault().resolveRequest(httpRequest).executeNow().content(); + } catch (QCloudServiceException e) { + e.printStackTrace(); + throw new QCloudClientException(e); + } + + String sign = null; + try { + sign = getSignFromResponse(response); + } catch (JSONException e) { + e.printStackTrace(); + throw new QCloudClientException("parse response failed"); + } + + /** + * 给请求设置 Authorization Header + */ + if (TextUtils.isEmpty(sign)) { + throw new QCloudClientException("get sign from server failed!!!"); + } + request.addHeader("Authorization", sign); + } + + private Map getHeaderMap(Map> multiValuesHeaders) { + + Map header = new HashMap<>(); + for (Map.Entry> entry : multiValuesHeaders.entrySet()) { + + if (entry.getValue().size() > 0) { + header.put(entry.getKey(), entry.getValue().get(0)); + } + } + + return header; + } + + private Map getQueryMap(String query) + { + + Map map = new HashMap<>(); + if (TextUtils.isEmpty(query)) { + return map; + } + + String[] params = query.split("&"); + for (String param : params) + { + String[] paramKeyValue = param.split("="); + if (paramKeyValue.length >= 2) { + String name = paramKeyValue[0]; + String value = paramKeyValue[1]; + map.put(name, value); + } + } + return map; + } + + /** + * 将签名需要的字段转化为 json 字符串 + * + * @return + */ + private String signField2Json(String method, String schema, String host, String path, + Map headers, Map params) throws JSONException { + + JSONObject signJson = new JSONObject(); + signJson.put("method", method); + signJson.put("schema", schema); + signJson.put("host", host); + signJson.put("path", path); + + JSONObject headersJSON = new JSONObject(headers); + signJson.put("headers", headersJSON); + + JSONObject paramsJSON = new JSONObject(params); + signJson.put("params", paramsJSON); + + return signJson.toString(); + } + + private String getSignFromResponse(String response) throws JSONException { + + JSONObject jsonObject = new JSONObject(response); + return jsonObject.optString("sign"); + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/RemoteStorage.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/RemoteStorage.java new file mode 100644 index 00000000..943edac6 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/RemoteStorage.java @@ -0,0 +1,132 @@ +package com.xscm.moduleutil.utils.cos; + +import android.content.Context; +import com.tencent.cos.xml.CosXmlService; +import com.tencent.cos.xml.CosXmlServiceConfig; +import com.tencent.cos.xml.exception.CosXmlClientException; +import com.tencent.cos.xml.exception.CosXmlServiceException; +import com.tencent.cos.xml.listener.CosXmlProgressListener; +import com.tencent.cos.xml.model.bucket.PutBucketRequest; +import com.tencent.cos.xml.model.bucket.PutBucketResult; +import com.tencent.cos.xml.model.object.PutObjectRequest; +import com.tencent.cos.xml.model.object.PutObjectResult; +import com.tencent.cos.xml.model.service.GetServiceRequest; +import com.tencent.cos.xml.model.service.GetServiceResult; +import com.tencent.cos.xml.transfer.UploadService; +import com.tencent.qcloud.core.auth.QCloudSigner; +import com.xscm.moduleutil.base.CommonAppContext; +import com.xscm.moduleutil.utils.SpUtil; +import com.xscm.moduleutil.widget.Constants; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + * com.xscm.moduleutil.utils.cos + * qx + * 2025/10/23 + */ +public class RemoteStorage { + + private int MULTIPART_UPLOAD_SIZE = 1024 * 2; + + private CosXmlService cosXmlService; + private boolean isHttps; + private String appid; + private String region; + + + public RemoteStorage(Context context, String appid, String region, String hostFormat) { + + isHttps = false; + this.appid = appid; + this.region = region; + + /** + * 初始化配置 + */ + CosXmlServiceConfig cosXmlServiceConfig = new CosXmlServiceConfig.Builder() + .isHttps(isHttps) + .setAppidAndRegion(appid, region) // appid 和 region 均可以为空 + .setDebuggable(true) + .setBucketInPath(false) // 将 Bucket 放在 URL 的 Path 中 + .setHostFormat(hostFormat) // 私有云需要设置主域名 + .builder(); + + /** + * 私有云暂时不支持临时密钥进行签名,如果直接在客户端直接使用永久密钥会有安全性问题,因此这里采用 + * 服务端直接下发签名的方式来进行鉴权。 + */ + URL url = null; // 您的服务端签名的 URL 地址 + try { + url = new URL(CommonAppContext.getInstance().getCurrentEnvironment().getServerUrl()+ Constants.GET_TEMP_KEY+"?"+ SpUtil.getToken()); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + QCloudSigner cosSigner = new RemoteCOSSigner(url); + + cosXmlService = new CosXmlService(context, cosXmlServiceConfig, cosSigner); + } + + + /** + * 上传文件 + * + * @param bucketName bucket 名称 + * @param cosPath 上传到 COS 的路径 + * @param localPath 需要上传文件的本地路径 + * @param progressListener 进度监听器 + * + * @return 本次上传的 id,可以通过这个 id 来取消上传 + */ + public UploadService.UploadServiceResult uploadFile(String bucketName, String cosPath, String localPath, CosXmlProgressListener progressListener) + throws CosXmlServiceException, CosXmlClientException { + + UploadService.ResumeData resumeData = new UploadService.ResumeData(); + resumeData.sliceSize = MULTIPART_UPLOAD_SIZE; // 分片上传的大小 + resumeData.cosPath = cosPath; + resumeData.bucket = bucketName; + resumeData.srcPath = localPath; + + /** + * 上传服务类,这个类封装了 {@link CosXmlService} 几个上传相关的接口,通过使用该接口,您可以更加方便的上传文件。 + * 注意,每次上传都要初始化一个新的 {@link CosXmlService} 对象。 + */ + final UploadService uploadService = new UploadService(cosXmlService, resumeData); + uploadService.setProgressListener(progressListener); + return uploadService.upload(); + } + + public PutObjectResult simpleUploadFile(String bucketName, String cosPath, String localPath, CosXmlProgressListener progressListener) + throws CosXmlServiceException, CosXmlClientException { + + PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, cosPath, localPath); + putObjectRequest.setProgressListener(progressListener); + + return cosXmlService.putObject(putObjectRequest); + } + /** + * 列出所有的 bucket + */ + public GetServiceResult getService() throws CosXmlServiceException, CosXmlClientException { + + GetServiceRequest getServiceRequest = new GetServiceRequest(); + getServiceRequest.setRequestHeaders("x-cos-meta-bucket", "BucketName", false); + + return cosXmlService.getService(getServiceRequest); + } + + + /** + * 创建 bucket + * + * @param bucketName bucket 名称 + */ + public PutBucketResult putBucket(String bucketName) throws CosXmlServiceException, CosXmlClientException { + + PutBucketRequest putBucketRequest = new PutBucketRequest(bucketName); + + return cosXmlService.putBucket(putBucketRequest); + } + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/TaskFactory.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/TaskFactory.java new file mode 100644 index 00000000..1ffec683 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/TaskFactory.java @@ -0,0 +1,239 @@ +package com.xscm.moduleutil.utils.cos; + +import android.content.Context; +import android.os.AsyncTask; +import android.widget.Toast; +import com.tencent.cos.xml.exception.CosXmlClientException; +import com.tencent.cos.xml.exception.CosXmlServiceException; +import com.tencent.cos.xml.listener.CosXmlProgressListener; +import com.tencent.cos.xml.model.bucket.PutBucketResult; +import com.tencent.cos.xml.model.object.PutObjectResult; +import com.tencent.cos.xml.model.service.GetServiceResult; +import com.tencent.cos.xml.model.tag.ListAllMyBuckets; +import com.tencent.cos.xml.transfer.UploadService; +import com.tencent.qcloud.core.logger.QCloudLogger; + +import java.util.List; + +/** + * com.xscm.moduleutil.utils.cos + * qx + * 2025/10/23 + */ +public class TaskFactory { + + private static TaskFactory instance; + + private TaskFactory() {} + + public static TaskFactory getInstance() { + + if (instance == null) { + synchronized (TaskFactory.class) { + if (instance == null) { + instance = new TaskFactory(); + } + } + } + + return instance; + } + + public GetServiceTask createGetServiceTask(Context context, RemoteStorage remoteStorage) { + + return new GetServiceTask(context, remoteStorage); + } + + public PutBucketTask createPutBucketTask(Context context, RemoteStorage remoteStorage, String bucketName) { + + return new PutBucketTask(context, remoteStorage, bucketName); + } + + public PutObjectTask createPutObjectTask(Context context, RemoteStorage remoteStorage, String bucket, + String srcPath, String dstPath) { + + return new PutObjectTask(context, remoteStorage, bucket, srcPath, dstPath); + } + + + + public SimplePutObjectTask createSimplePutObjectTask(Context context, RemoteStorage remoteStorage, String bucket, + String srcPath, String dstPath) { + + return new SimplePutObjectTask(context, remoteStorage, bucket, srcPath, dstPath); + } + + + public class GetServiceTask extends AsyncTask { + + Context context; + RemoteStorage remoteStorage ; + + public GetServiceTask(Context context, RemoteStorage remoteStorage) { + this.remoteStorage = remoteStorage; + this.context = context; + } + + @Override + protected GetServiceResult doInBackground(Void ... voids) { + try { + return remoteStorage.getService(); + } catch (CosXmlServiceException e) { + e.printStackTrace(); + } catch (CosXmlClientException e) { + e.printStackTrace(); + } + + return null; + } + + protected void onPostExecute(GetServiceResult getServiceResult) { + + if (getServiceResult != null && getServiceResult.listAllMyBuckets != null) { + List buckets = getServiceResult.listAllMyBuckets.buckets; + Toast.makeText(context, buckets.toString(), Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(context, "GetService failed", Toast.LENGTH_SHORT).show(); + } + } + } + + public class PutBucketTask extends AsyncTask { + + RemoteStorage remoteStorage ; + String bucketName; + Context context; + + public PutBucketTask(Context context, RemoteStorage remoteStorage, String bucketName) { + this.context = context; + this.remoteStorage = remoteStorage; + this.bucketName = bucketName; + } + + @Override + protected PutBucketResult doInBackground(Void ... voids) { + try { + return remoteStorage.putBucket(bucketName); + } catch (CosXmlServiceException e) { + e.printStackTrace(); + } catch (CosXmlClientException e) { + e.printStackTrace(); + } + + return null; + } + + @Override + protected void onPostExecute(PutBucketResult putBucketResult) { + + if (putBucketResult != null) { + Toast.makeText(context, putBucketResult.printResult(), Toast.LENGTH_SHORT).show(); + } + } + } + + static class PutObjectTask extends AsyncTask { + + Context context; + RemoteStorage remoteStorage; + String bucket; + String srcPath; + String dstPath; + + public PutObjectTask(Context context, RemoteStorage remoteStorage, String bucket, String srcPath, String dstPath) { + + this.context = context; + this.remoteStorage = remoteStorage; + this.bucket = bucket; + this.srcPath = srcPath; + this.dstPath = dstPath; + } + + @Override + protected UploadService.UploadServiceResult doInBackground(Void... voids) { + try { + return remoteStorage.uploadFile(bucket, dstPath, srcPath, new CosXmlProgressListener() { + @Override + public void onProgress(long progress, long total) { + publishProgress((int) ((progress/ (float) total) * 100)); + } + }); + } catch (CosXmlServiceException e) { + e.printStackTrace(); + } catch (CosXmlClientException e) { + e.printStackTrace(); + } + + return null; + } + + + @Override + protected void onProgressUpdate(Integer... values) { + + QCloudLogger.i("upload", "progress " + values[0]); + } + + + @Override + protected void onPostExecute(UploadService.UploadServiceResult uploadServiceResult) { + + if (uploadServiceResult != null) { + Toast.makeText(context, uploadServiceResult.printResult(), Toast.LENGTH_SHORT).show(); + } + } + } + + static class SimplePutObjectTask extends AsyncTask { + + Context context; + RemoteStorage remoteStorage; + String bucket; + String srcPath; + String dstPath; + + public SimplePutObjectTask(Context context, RemoteStorage remoteStorage, String bucket, String srcPath, String dstPath) { + + this.context = context; + this.remoteStorage = remoteStorage; + this.bucket = bucket; + this.srcPath = srcPath; + this.dstPath = dstPath; + } + + @Override + protected PutObjectResult doInBackground(Void... voids) { + try { + return remoteStorage.simpleUploadFile(bucket, dstPath, srcPath, new CosXmlProgressListener() { + @Override + public void onProgress(long progress, long total) { + publishProgress((int) ((progress/ (float) total) * 100)); + } + }); + } catch (CosXmlServiceException e) { + e.printStackTrace(); + } catch (CosXmlClientException e) { + e.printStackTrace(); + } + + return null; + } + + + @Override + protected void onProgressUpdate(Integer... values) { + + QCloudLogger.i("upload", "progress " + values[0]); + } + + + @Override + protected void onPostExecute(PutObjectResult putObjectResult) { + + if (putObjectResult != null) { + Toast.makeText(context, putObjectResult.printResult(), Toast.LENGTH_SHORT).show(); + } + } + } +} + diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/TempKeyBean.kt b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/TempKeyBean.kt new file mode 100644 index 00000000..8ac6cd6f --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/cos/TempKeyBean.kt @@ -0,0 +1,21 @@ +package com.xscm.moduleutil.utils.cos + +/** + *com.xscm.moduleutil.utils.cos + *qx + *2025/10/23 + * + */ +data class TempKeyBean ( + var startTime:Long = 0, + var expiredTime:Long = 0, + var region:String = "", + var bucket:String = "", + var credentials : Credentials = Credentials(), +) + +data class Credentials( + var sessionToken : String="", + var tmpSecretId : String="", + var tmpSecretKey : String="" +) \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/logger/LogInterceptor.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/logger/LogInterceptor.java new file mode 100644 index 00000000..6c466c2f --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/logger/LogInterceptor.java @@ -0,0 +1,276 @@ +package com.xscm.moduleutil.utils.logger; + +import android.util.Log; + +import androidx.annotation.NonNull; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +import okhttp3.Interceptor; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okhttp3.internal.http.HttpHeaders; +import okio.Buffer; +import okio.BufferedSource; + +/** + * OkHttp 日志拦截器,用于打印请求和响应详情 + */ +public class LogInterceptor implements Interceptor { + private static final String TAG = "NetworkLog"; + private static final Charset UTF8 = StandardCharsets.UTF_8; + + // 日志开关(可根据debug/release环境动态设置) + private boolean isLogEnabled = true; + // 是否打印请求体 + private boolean logRequestBody = true; + // 是否打印响应体 + + private boolean logResponseBody = true; + // 最大日志长度(避免过大的响应体导致日志刷屏) + private int maxLogLength = 2048; + + public LogInterceptor() { + } + + // 配置方法 + public LogInterceptor setLogEnabled(boolean enabled) { + isLogEnabled = enabled; + return this; + } + + public LogInterceptor setLogRequestBody(boolean logRequestBody) { + this.logRequestBody = logRequestBody; + return this; + } + + public LogInterceptor setLogResponseBody(boolean logResponseBody) { + this.logResponseBody = logResponseBody; + return this; + } + + public LogInterceptor setMaxLogLength(int maxLogLength) { + this.maxLogLength = maxLogLength; + return this; + } + + @NonNull + @Override + public Response intercept(@NonNull Chain chain) throws IOException { + if (!isLogEnabled) { + return chain.proceed(chain.request()); + } + + Request request = chain.request(); + // 打印请求日志 + logRequest(request); + + // 记录请求开始时间,用于计算耗时 + long startNs = System.nanoTime(); + Response response; + try { + response = chain.proceed(request); + } catch (Exception e) { + // 打印请求异常 + Log.e(TAG, "请求失败: " + e.getMessage()); + throw e; + } + // 计算请求耗时 + long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); + + // 打印响应日志 + logResponse(response, tookMs); + + return response; + } + + /** + * 打印请求日志 + */ + private void logRequest(Request request) { + try { + StringBuilder log = new StringBuilder(); + log.append("\n==================== 请求开始 ====================\n"); + + // 请求行: 方法 + URL + log.append(String.format("方法: %s URL: %s\n", request.method(), request.url())); + + // 请求头 + log.append("请求头:\n"); + for (String name : request.headers().names()) { + // 脱敏敏感头信息(如Authorization、Cookie等) + String value = isSensitiveHeader(name) ? "***" : request.headers().get(name); + log.append(String.format(" %s: %s\n", name, value)); + } + + // 请求体 + if (logRequestBody && request.body() != null) { + RequestBody requestBody = request.body(); + if (requestBody.contentLength() > 0) { + log.append("请求体:\n"); + + // 复制请求体(避免原请求体被消耗) + Buffer buffer = new Buffer(); + requestBody.writeTo(buffer); + Charset charset = UTF8; + MediaType contentType = requestBody.contentType(); + if (contentType != null) { + charset = contentType.charset(UTF8); + } + + // 读取请求体内容 + String body = buffer.readString(charset); + // 格式化JSON(如果是JSON类型) + if (isJson(contentType)) { + body = formatJson(body); + } + // 截断过长的日志 + log.append(truncateLog(body)).append("\n"); + } + } + + log.append("==================== 请求结束 ====================\n"); + Log.d(TAG, log.toString()); + } catch (Exception e) { + Log.e(TAG, "打印请求日志失败: " + e.getMessage()); + } + } + + /** + * 打印响应日志 + */ + private void logResponse(Response response, long tookMs) { + try { + StringBuilder log = new StringBuilder(); + log.append("\n==================== 响应开始 ====================\n"); + + // 响应行: 状态码 + 消息 + 耗时 + log.append(String.format("状态码: %d 消息: %s 耗时: %dms\n", + response.code(), response.message(), tookMs)); + + // 响应头 + log.append("响应头:\n"); + for (String name : response.headers().names()) { + log.append(String.format(" %s: %s\n", name, response.headers().get(name))); + } + + // 响应体 + if (logResponseBody && HttpHeaders.hasBody(response)) { + ResponseBody responseBody = response.body(); + if (responseBody != null) { + BufferedSource source = responseBody.source(); + source.request(Long.MAX_VALUE); // 读取整个响应体 + Buffer buffer = source.buffer(); + + Charset charset = UTF8; + MediaType contentType = responseBody.contentType(); + if (contentType != null) { + charset = contentType.charset(UTF8); + } + + // 读取响应体内容 + String body = buffer.clone().readString(charset); + // 格式化JSON + if (isJson(contentType)) { + body = formatJson(body); + } + // 截断过长的日志 + log.append("响应体:\n").append(truncateLog(body)).append("\n"); + } + } + + log.append("==================== 响应结束 ====================\n"); + Log.d(TAG, log.toString()); + } catch (Exception e) { + Log.e(TAG, "打印响应日志失败: " + e.getMessage()); + } + } + + /** + * 判断是否为JSON类型 + */ + private boolean isJson(MediaType mediaType) { + if (mediaType == null) return false; + return mediaType.type().equals("application") && + mediaType.subtype().equals("json"); + } + + /** + * 格式化JSON字符串(增强可读性) + */ + private String formatJson(String json) { + try { + // 简单格式化(可根据需要使用更复杂的JSON格式化库) + StringBuilder formatted = new StringBuilder(); + int indent = 0; + boolean inQuotes = false; + char lastChar = ' '; + + for (char c : json.toCharArray()) { + if (c == '"' && lastChar != '\\') { + inQuotes = !inQuotes; + } + + if (!inQuotes) { + switch (c) { + case '{': + case '[': + formatted.append(c).append("\n"); + indent += 4; + formatted.append(" ".repeat(indent)); + break; + case '}': + case ']': + formatted.append("\n"); + indent -= 4; + formatted.append(" ".repeat(indent)).append(c); + break; + case ',': + formatted.append(c).append("\n").append(" ".repeat(indent)); + break; + case ':': + formatted.append(" : "); + break; + default: + formatted.append(c); + break; + } + } else { + formatted.append(c); + } + lastChar = c; + } + return formatted.toString(); + } catch (Exception e) { + // 格式化失败时返回原始字符串 + return json; + } + } + + /** + * 截断过长的日志 + */ + private String truncateLog(String log) { + if (log.length() <= maxLogLength) { + return log; + } + return log.substring(0, maxLogLength) + "\n...[日志过长,已截断]..."; + } + + /** + * 判断是否为敏感头信息(需要脱敏) + */ + private boolean isSensitiveHeader(String headerName) { + String lowerHeader = headerName.toLowerCase(); + return lowerHeader.contains("authorization") || + lowerHeader.contains("cookie") || + lowerHeader.contains("token") || + lowerHeader.contains("secret"); + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/roomview/GiftDisplayManager.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/roomview/GiftDisplayManager.java new file mode 100644 index 00000000..996cbba6 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/roomview/GiftDisplayManager.java @@ -0,0 +1,233 @@ +package com.xscm.moduleutil.utils.roomview; + +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.bean.RoonGiftModel; + +import java.lang.ref.WeakReference; +import java.util.*; + +public class GiftDisplayManager { + private static GiftDisplayManager instance; + + private WeakReference containerRef; + private List displayViews; + private Queue giftQueue; + private Map accumulatedGifts; + private boolean isProcessingQueue = false; + + private Handler mainHandler = new Handler(Looper.getMainLooper()); + + public static GiftDisplayManager getInstance() { + if (instance == null) { + synchronized (GiftDisplayManager.class) { + if (instance == null) { + instance = new GiftDisplayManager(); + } + } + } + return instance; + } + + private GiftDisplayManager() { + displayViews = new ArrayList<>(); + giftQueue = new LinkedList<>(); + accumulatedGifts = new HashMap<>(); + } + + public void setupDisplayView(ViewGroup container) { + this.containerRef = new WeakReference<>(container); + createDisplayViews(); + } + + private void createDisplayViews() { + if (displayViews.size() > 0 || containerRef == null || containerRef.get() == null) { + return; + } + + ViewGroup container = containerRef.get(); + int viewHeight = dpToPx(40); + int spacing = dpToPx(10); + int topMargin = dpToPx(100); + int width = dpToPx(270); + + for (int i = 0; i < 3; i++) { + int y = topMargin + (viewHeight + spacing) * i; + + GiftDisplayView displayView = new GiftDisplayView(container.getContext()); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, viewHeight); + params.setMargins(0, y, 0, 0); + displayView.setLayoutParams(params); + displayView.setTag(1000 + i); + + final int finalI = i; + displayView.setGiftAnimationListener(view -> { + Log.d("GiftDisplayManager", "Gift animation ended on view: " + finalI); + onGiftAnimationEnd(view); + }); + + container.addView(displayView); + displayViews.add(displayView); + + Log.d("GiftDisplayManager", "Created display view " + i); + } + } + + public void receiveGift(GiftBean gift) { + if (gift == null) return; + + Log.d("GiftDisplayManager", "Received gift: " + gift.getSenderName() + + " - " + gift.getGift_name() + " x" + gift.getNumber()); + + mainHandler.post(() -> internalReceiveGift(gift)); + } + + private void internalReceiveGift(GiftBean gift) { + // 查找正在显示的同类型礼物 + GiftDisplayView displayingView = findDisplayingViewForGift(gift); + + if (displayingView != null) { + // 找到正在显示的视图,直接累加 + String key = gift.getGiftKey(); + GiftBean accumulatedGift = accumulatedGifts.get(key); + if (accumulatedGift != null) { + accumulatedGift.setNumber(accumulatedGift.getNumber() + gift.getNumber()); + displayingView.updateGiftCount(accumulatedGift.getNumber()); + Log.d("GiftDisplayManager", "Gift accumulated: " + gift.getGift_name() + + " x" + accumulatedGift.getNumber()); + } + } else { + // 新礼物,检查是否可以立即显示 + GiftDisplayView availableView = findAvailableDisplayView(); + if (availableView != null) { + // 有可用视图,立即显示 + String key = gift.getGiftKey(); + accumulatedGifts.put(key, gift.clone()); + availableView.showGift(gift); + Log.d("GiftDisplayManager", "Immediately display gift on view: " + availableView.getTag()); + } else { + // 没有可用视图,加入队列 + giftQueue.offer(gift); + Log.d("GiftDisplayManager", "Added to queue, current queue size: " + giftQueue.size()); + } + } + + // 处理队列 + processGiftQueue(); + } + + private GiftDisplayView findDisplayingViewForGift(GiftBean gift) { + for (GiftDisplayView view : displayViews) { + if (view.isAnimating() && view.getCurrentGift() != null && + view.getCurrentGift().isSameGiftFromSameSender(gift)) { + return view; + } + } + return null; + } + + private GiftDisplayView findAvailableDisplayView() { + for (GiftDisplayView view : displayViews) { + if (!view.isAnimating()) { + return view; + } + } + return null; + } + + private void processGiftQueue() { + if (isProcessingQueue) { + return; + } + + isProcessingQueue = true; + + // 循环处理队列直到队列为空或没有可用视图 + while (!giftQueue.isEmpty()) { + GiftDisplayView availableView = findAvailableDisplayView(); + if (availableView == null) { + break; + } + + GiftBean gift = giftQueue.poll(); + if (gift == null) continue; + + // 检查是否已经有同类型礼物在显示 + GiftDisplayView displayingView = findDisplayingViewForGift(gift); + if (displayingView == null) { + String key = gift.getGiftKey(); + accumulatedGifts.put(key, gift.clone()); + availableView.showGift(gift); + Log.d("GiftDisplayManager", "Display gift from queue: " + gift.getGift_name()); + } else { + // 如果已经在显示,累加到现有视图 + String key = gift.getGiftKey(); + GiftBean accumulatedGift = accumulatedGifts.get(key); + if (accumulatedGift != null) { + accumulatedGift.setNumber(accumulatedGift.getNumber() + gift.getNumber()); + displayingView.updateGiftCount(accumulatedGift.getNumber()); + Log.d("GiftDisplayManager", "Queue gift accumulated to existing: " + + gift.getNickname() + " x" + accumulatedGift.getNumber()); + } + } + } + + isProcessingQueue = false; + + // 打印队列状态 + if (!giftQueue.isEmpty()) { + Log.d("GiftDisplayManager", "Still " + giftQueue.size() + " gifts waiting in queue"); + } + } + + private void onGiftAnimationEnd(GiftDisplayView view) { + Log.d("GiftDisplayManager", "Gift animation end on view: " + view.getTag()); + + // 从累加记录中移除 + if (view.getCurrentGift() != null) { + String key = view.getCurrentGift().getGiftKey(); + accumulatedGifts.remove(key); + Log.d("GiftDisplayManager", "Removed accumulated record: " + key); + } + + // 延迟一下再处理队列,确保视图状态完全重置 + mainHandler.postDelayed(this::processGiftQueue, 100); + } + + public void clearAll() { + Log.d("GiftDisplayManager", "Clear all gifts and queue"); + + for (GiftDisplayView view : displayViews) { + view.finishAnimationImmediately(); + } + containerRef.clear(); + displayViews.clear(); + giftQueue.clear(); + accumulatedGifts.clear(); + isProcessingQueue = false; + } + + // 调试方法 + public void printDebugInfo() { + Log.d("GiftDisplayManager", "=== Gift Display Manager Status ==="); + Log.d("GiftDisplayManager", "Queue size: " + giftQueue.size()); + Log.d("GiftDisplayManager", "Accumulated records: " + accumulatedGifts.size()); + + for (int i = 0; i < displayViews.size(); i++) { + GiftDisplayView view = displayViews.get(i); + Log.d("GiftDisplayManager", "View " + i + ": Animating=" + view.isAnimating() + + ", Gift=" + (view.getCurrentGift() != null ? view.getCurrentGift().getGift_name() : "None")); + } + Log.d("GiftDisplayManager", "==================================="); + } + + private int dpToPx(int dp) { + if (containerRef == null || containerRef.get() == null) return dp; + float density = containerRef.get().getResources().getDisplayMetrics().density; + return Math.round(dp * density); + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/utils/roomview/GiftDisplayView.java b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/roomview/GiftDisplayView.java new file mode 100644 index 00000000..37d8baff --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/utils/roomview/GiftDisplayView.java @@ -0,0 +1,263 @@ +package com.xscm.moduleutil.utils.roomview; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.graphics.Color; +import android.os.Handler; +import android.util.AttributeSet; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.utils.ImageUtils; + +import java.util.Random; + +public class GiftDisplayView extends FrameLayout { + private ImageView avatarImageView; + private TextView senderTextView; + private TextView giftTextView; + private TextView countTextView; + private ImageView giftImageView; + private LinearLayout ll; + + private GiftBean currentGift; + private boolean isAnimating = false; + private GiftAnimationListener listener; + private Handler handler = new Handler(); + private Runnable hideRunnable; + + public interface GiftAnimationListener { + void onGiftAnimationEnd(GiftDisplayView view); + } + + public GiftDisplayView(Context context) { + super(context); + initView(); + } + + public GiftDisplayView(Context context, AttributeSet attrs) { + super(context, attrs); + initView(); + } + + private void initView() { + LayoutInflater.from(getContext()).inflate(R.layout.gift_display_layout, this, true); + + avatarImageView = findViewById(R.id.iv_avatar); + senderTextView = findViewById(R.id.tv_sender); + giftTextView = findViewById(R.id.tv_gift); + countTextView = findViewById(R.id.tv_count); + giftImageView = findViewById(R.id.iv_gift); +// ll = findViewById(R.id.ll); + +// setBackgroundResource(R.drawable.gift_background); + setAlpha(0f); + } + + public void showGift(GiftBean gift) { + if (isAnimating) { + Log.w("GiftDisplayView", "View is animating, cannot show new gift"); + return; + } + + this.currentGift = gift; + this.isAnimating = true; + + Log.d("GiftDisplayView", "Start showing gift: " + gift.getGift_name()); + + // 更新UI + updateUIWithGift(gift); + + // 重置位置 + setTranslationX(-getWidth()); + setAlpha(1f); + + // 从左往右进入动画 + animate() + .translationX(0) + .setDuration(500) + .setInterpolator(new AccelerateDecelerateInterpolator()) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + Log.d("GiftDisplayView", "Enter animation completed: " + gift.getGift_name()); + startHideTimer(); + } + }) + .start(); + } + + private void updateUIWithGift(GiftBean gift) { + if (gift == null) return; + + senderTextView.setText(gift.getNickname()!=null ? gift.getNickname() : "未知用户"); + // 更新发送者名称 +// senderTextView.setText(gift.getSenderName() != null ? gift.getSenderName() : "未知用户"); + + // 更新礼物信息 + giftTextView.setText("送给 "+(gift.getSenderName() != null ? gift.getSenderName() : "未知用户") + (gift.getGift_name() != null ? gift.getGift_name() : "礼物")); + + // 更新礼物数量 + countTextView.setText("x" + gift.getNumber()); + + // 加载头像图片(这里可以使用Glide、Picasso等图片加载库) + loadAvatarImage(gift.getUserAvatar()); + + // 加载礼物图片 + loadGiftImage(gift.getBase_image()); + + Log.d("GiftDisplayView", "Update UI: " + gift.getSenderName() + " - " + + gift.getGift_name() + " x" + gift.getNumber()); + } + + private void loadAvatarImage(String avatarUrl) { + if (avatarUrl != null && !avatarUrl.isEmpty()) { + // 使用图片加载库,例如: + // Glide.with(getContext()).load(avatarUrl).into(avatarImageView); + + // 临时用颜色代替 +// avatarImageView.setBackgroundColor(getRandomColor()); + ImageUtils.loadHeadCC(avatarUrl, avatarImageView); + } else { + avatarImageView.setBackgroundColor(Color.LTGRAY); + } + } + + private void loadGiftImage(String giftImageUrl) { + if (giftImageUrl != null && !giftImageUrl.isEmpty()) { + // 使用图片加载库 + // Glide.with(getContext()).load(giftImageUrl).into(giftImageView); + + // 临时用颜色代替 +// giftImageView.setBackgroundColor(getRandomColor()); + ImageUtils.loadHeadCC(giftImageUrl, giftImageView); + } else { + giftImageView.setBackgroundColor(Color.parseColor("#FFA500")); + } + } + + private int getRandomColor() { + Random random = new Random(); + return Color.argb(255, random.nextInt(256), random.nextInt(256), random.nextInt(256)); + } + + public void updateGiftCount(int count) { + if (!isAnimating) { + Log.w("GiftDisplayView", "View is not animating, cannot update count"); + return; + } + + Log.d("GiftDisplayView", "Update gift count: " + count); + + // 更新数量显示 + countTextView.setText("x" + count); + + // 数量更新动画 + countTextView.animate() + .scaleX(1.5f) + .scaleY(1.5f) + .setDuration(200) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + countTextView.animate() + .scaleX(1f) + .scaleY(1f) + .setDuration(200) + .start(); + } + }) + .start(); + + // 重置计时器 + resetHideTimer(); + } + + private void startHideTimer() { + // 移除之前的任务 + if (hideRunnable != null) { + handler.removeCallbacks(hideRunnable); + } + + hideRunnable = this::hideAnimation; + handler.postDelayed(hideRunnable, 3000); + } + + private void resetHideTimer() { + startHideTimer(); + } + + private void hideAnimation() { + if (!isAnimating) { + return; + } + + Log.d("GiftDisplayView", "Start hide animation: " + currentGift.getGift_name()); + + // 从右往左消失动画 + animate() + .translationX(-getWidth()) + .alpha(0f) + .setDuration(500) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + Log.d("GiftDisplayView", "Hide animation completed: " + currentGift.getGift_name()); + isAnimating = false; + + if (listener != null) { + listener.onGiftAnimationEnd(GiftDisplayView.this); + } + + currentGift = null; + } + }) + .start(); + } + + public void finishAnimationImmediately() { + Log.d("GiftDisplayView", "Finish animation immediately"); + + // 移除计时任务 + if (hideRunnable != null) { + handler.removeCallbacks(hideRunnable); + hideRunnable = null; + } + + // 清除动画 + clearAnimation(); + animate().cancel(); + + isAnimating = false; + currentGift = null; + setAlpha(0f); + setTranslationX(-getWidth()); + } + + public boolean isAnimating() { + return isAnimating; + } + + public GiftBean getCurrentGift() { + return currentGift; + } + + public void setGiftAnimationListener(GiftAnimationListener listener) { + this.listener = listener; + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (hideRunnable != null) { + handler.removeCallbacks(hideRunnable); + } + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/view/CustomDialogView.java b/moduleUtil/src/main/java/com/xscm/moduleutil/view/CustomDialogView.java new file mode 100644 index 00000000..a1f1abac --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/view/CustomDialogView.java @@ -0,0 +1,44 @@ +package com.xscm.moduleutil.view; + +import android.content.Context; +import android.util.AttributeSet; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.core.content.ContextCompat; +import com.xscm.moduleutil.R; +import org.jetbrains.annotations.NotNull; + +/** + * 这是抢红包的自定义view + */ +public class CustomDialogView extends ConstraintLayout { + public CustomDialogView(@NonNull @NotNull Context context) { + super(context); + init(); + } + + public CustomDialogView(@NonNull @NotNull Context context, @Nullable @org.jetbrains.annotations.Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + public CustomDialogView(@NonNull @NotNull Context context, @Nullable @org.jetbrains.annotations.Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + public CustomDialogView(@NonNull @NotNull Context context, @Nullable @org.jetbrains.annotations.Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(); + } + + private void init() { + // 初始化视图 + // 设置背景色 + setBackground(ContextCompat.getDrawable(getContext(), R.drawable.bg_red_16_envel)); + + + } + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/view/QXMeetGiftView.java b/moduleUtil/src/main/java/com/xscm/moduleutil/view/QXMeetGiftView.java new file mode 100644 index 00000000..74df3d21 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/view/QXMeetGiftView.java @@ -0,0 +1,262 @@ +package com.xscm.moduleutil.view; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.RotateAnimation; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.bumptech.glide.Glide; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean; + +public class QXMeetGiftView extends RelativeLayout { + + private TextView giftNameLabel; + private ImageView giftPriceBgView; + private Button giftCoin; + private ImageView bgImageView; + private ImageView giftBgImageView; + private ImageView giftImageView; + + private boolean isLockGift; + private Object model; // 这里用 Object 代替 QXDrawGiftModel + + public QXMeetGiftView(Context context) { + super(context); + initSubviews(context); + } + + public QXMeetGiftView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initSubviews(context); + } + + public QXMeetGiftView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initSubviews(context); + } + + private void initSubviews(Context context) { + // 创建背景图片视图 + bgImageView = new ImageView(context); + bgImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + bgImageView.setImageResource(R.drawable.ac_left_gift_bg); + LayoutParams bgParams = new LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT + ); + addView(bgImageView, bgParams); + + // 创建礼物图片视图(圆形) + giftImageView = new ImageView(context); + giftImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + LayoutParams giftImageParams = new LayoutParams( + dpToPx(48), // 固定宽度 + dpToPx(62) // 固定高度 + ); + giftImageParams.addRule(CENTER_IN_PARENT); + giftImageParams.topMargin = dpToPx(10); + addView(giftImageView, giftImageParams); + + // 创建礼物背景光效视图 + giftBgImageView = new ImageView(context); + giftBgImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + giftBgImageView.setImageResource(R.drawable.ac_lock_gift_light_bg); + giftBgImageView.setVisibility(View.GONE); // 初始隐藏 + LayoutParams giftBgParams = new LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT + ); + addView(giftBgImageView, giftBgParams); + + + + // 创建价格背景视图 + giftPriceBgView = new ImageView(context); + giftPriceBgView.setImageResource(R.drawable.ac_meet_gift_name_bg); + LayoutParams priceBgParams = new LayoutParams( + LayoutParams.MATCH_PARENT, + dpToPx(15) + ); + priceBgParams.addRule(CENTER_HORIZONTAL); + priceBgParams.addRule(ALIGN_PARENT_BOTTOM); + priceBgParams.bottomMargin = dpToPx(10); // 在名称标签上方 + addView(giftPriceBgView, priceBgParams); + + + // 创建金币按钮 + giftCoin = new Button(context); + giftCoin.setTextColor(0xFFC7BF62); // 使用直接的颜色值 + // 设置按钮图标 + Drawable coinDrawable = getResources().getDrawable(R.mipmap.jinb); + coinDrawable.setBounds(0, 0, dpToPx(1), dpToPx(1)); + giftCoin.setCompoundDrawables(coinDrawable, null, null, null); + giftCoin.setTextSize(10); + giftCoin.setBackgroundColor(0x00000000); // 透明背景 + LayoutParams coinParams = new LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT + ); + coinParams.addRule(CENTER_HORIZONTAL); + coinParams.addRule(ALIGN_PARENT_BOTTOM); + coinParams.bottomMargin = -dpToPx(2); + addView(giftCoin, coinParams); + + // 创建礼物名称标签 + giftNameLabel = new TextView(context); + giftNameLabel.setTextColor(0xFFFFFFFF); + giftNameLabel.setTextSize(12); + giftNameLabel.setGravity(android.view.Gravity.CENTER); + giftNameLabel.setSingleLine(true); // 设置为单行显示 + giftNameLabel.setEllipsize(android.text.TextUtils.TruncateAt.END); // 超出部分用省略号表示 + LayoutParams nameParams = new LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT + ); + nameParams.addRule(CENTER_HORIZONTAL); + nameParams.addRule(ALIGN_PARENT_BOTTOM); + nameParams.bottomMargin = dpToPx(1); + addView(giftNameLabel, nameParams); + + // 调整视图层级 - 确保正确的层级关系 + // 按添加顺序已经确定层级,最晚添加的在最上层 + } + + public void setIsLockGift(boolean isLockGift) { + this.isLockGift = isLockGift; + + // 设置背景图片 + int bgResource = isLockGift ? + R.drawable.ac_lock_gift_bg : R.drawable.ac_left_gift_bg; + bgImageView.setImageResource(bgResource); + + // 显示/隐藏光效背景 + giftBgImageView.setVisibility(isLockGift ? View.VISIBLE : View.GONE); + + if (isLockGift) { + // 重新设置礼物图片的约束 + LayoutParams params = (LayoutParams) giftImageView.getLayoutParams(); + params.width = dpToPx(36); + params.height = dpToPx(36); + params.addRule(CENTER_IN_PARENT); + params.setMargins(0, 0, 0, 0); + giftImageView.setLayoutParams(params); + } else { + // 恢复原始约束 + LayoutParams params = (LayoutParams) giftImageView.getLayoutParams(); + params.width = LayoutParams.MATCH_PARENT; + params.height = LayoutParams.WRAP_CONTENT; + params.addRule(CENTER_IN_PARENT); + params.setMargins(dpToPx(6), dpToPx(6), dpToPx(6), 0); + giftImageView.setLayoutParams(params); + } + } + + public void setModel(BlindBoxBean.GiveGift model) { + this.model = model; + // 这里需要根据您的 QXDrawGiftModel 类来实现具体逻辑 + + if (model instanceof BlindBoxBean.GiveGift) { + BlindBoxBean.GiveGift giftModel = (BlindBoxBean.GiveGift) model; + + // 使用图片加载库加载图片 + Glide.with(getContext()).load(giftModel.getBase_image()).into(giftImageView); + + giftNameLabel.setText(giftModel.getGift_name()); + giftCoin.setText(giftModel.getGift_price()); + } + } + + public void startAnimation() { + // 礼物图片顺时针旋转动画 + RotateAnimation rotateAnimation = new RotateAnimation( + 0, 360, // 从 0 度旋转到 360 度 + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f + ); + rotateAnimation.setDuration(3000); // 3 秒 + rotateAnimation.setRepeatCount(Animation.INFINITE); + rotateAnimation.setRepeatMode(Animation.RESTART); + rotateAnimation.setInterpolator(getContext(), android.R.anim.linear_interpolator); + giftImageView.startAnimation(rotateAnimation); + + // 光效背景逆时针旋转动画 + RotateAnimation rotateAnimation1 = new RotateAnimation( + 0, -360, // 从 0 度旋转到 -360 度 + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f + ); + rotateAnimation1.setDuration(3000); // 3 秒 + rotateAnimation1.setRepeatCount(Animation.INFINITE); + rotateAnimation1.setRepeatMode(Animation.RESTART); + rotateAnimation1.setInterpolator(getContext(), android.R.anim.linear_interpolator); + giftBgImageView.startAnimation(rotateAnimation1); + } + + public void resetAnimation() { + giftImageView.clearAnimation(); + giftBgImageView.clearAnimation(); + } + + public void stopAnimation() { + giftImageView.clearAnimation(); + giftBgImageView.clearAnimation(); + } + + // 辅助方法:dp 转 px + private int dpToPx(int dp) { + float density = getResources().getDisplayMetrics().density; + return Math.round(dp * density); + } + + // 缩放宽度方法(对应 ScaleWidth) + private int scaleWidth(int value) { + // 这里需要根据您的缩放逻辑实现 + // 通常可以根据屏幕密度进行缩放 + float scale = getResources().getDisplayMetrics().density; + return (int) (value * scale); + } + + // Getter 方法 + public TextView getGiftNameLabel() { + return giftNameLabel; + } + + public ImageView getGiftPriceBgView() { + return giftPriceBgView; + } + + public Button getGiftCoin() { + return giftCoin; + } + + public ImageView getBgImageView() { + return bgImageView; + } + + public ImageView getGiftBgImageView() { + return giftBgImageView; + } + + public ImageView getGiftImageView() { + return giftImageView; + } + + public boolean isLockGift() { + return isLockGift; + } + + public Object getModel() { + return model; + } +} \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/view/QXMeetUserView.java b/moduleUtil/src/main/java/com/xscm/moduleutil/view/QXMeetUserView.java new file mode 100644 index 00000000..daa86c91 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/view/QXMeetUserView.java @@ -0,0 +1,332 @@ +package com.xscm.moduleutil.view; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.drawable.GradientDrawable; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Gravity; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.bean.blindboxwheel.BlindBoxBean; +import com.xscm.moduleutil.utils.ImageUtils; +import com.xscm.moduleutil.widget.GifAvatarOvalView; + +public class QXMeetUserView extends RelativeLayout { + private static final String TAG = "QXMeetUserView"; + + private GifAvatarOvalView headerImageView; // 头像 + private ImageView dressImageView; // 装饰图 + private TextView tagLabel; // 标签 + private TextView nameLabel; // 名称 + + // 布局属性变量 + private int avatarSize; // 头像大小 + private int dressSize; // 装饰图大小 + private float nameTextSize; // 名字字体大小 + private int nameTextColor; // 名字颜色 + private float tagTextSize; // 标签字体大小 + private int tagTextColor; // 标签颜色 + private int tagMargin; // 标签与头像的水平间距 + + // 布局常量(dp) + private static final int DEFAULT_AVATAR_SIZE = 60; // 默认头像大小 + private static final int DEFAULT_DRESS_SIZE = 70; // 默认装饰图大小 + private static final float DEFAULT_NAME_TEXT_SIZE = 12; // 默认名字字体大小 + private static final int DEFAULT_NAME_TEXT_COLOR = 0xFFFFFFFF; // 默认名字颜色 + private static final float DEFAULT_TAG_TEXT_SIZE = 12; // 默认标签字体大小 + private static final int DEFAULT_TAG_TEXT_COLOR = 0xFFFFE554; // 默认标签颜色 + private static final int DEFAULT_TAG_MARGIN = 0; // 默认标签间距 + private static final int NAME_MARGIN_TOP = 3; // 名字与标签间距 + + public QXMeetUserView(Context context) { + super(context); + initAttrs(null); + initSubviews(context); + } + + public QXMeetUserView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initAttrs(attrs); + initSubviews(context); + } + + public QXMeetUserView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initAttrs(attrs); + initSubviews(context); + } + + // 初始化自定义属性 + private void initAttrs(AttributeSet attrs) { + if (attrs == null) { + // 设置默认值 + avatarSize = dpToPx(DEFAULT_AVATAR_SIZE); + dressSize = dpToPx(DEFAULT_DRESS_SIZE); + nameTextSize = DEFAULT_NAME_TEXT_SIZE; + nameTextColor = DEFAULT_NAME_TEXT_COLOR; + tagTextSize = DEFAULT_TAG_TEXT_SIZE; + tagTextColor = DEFAULT_TAG_TEXT_COLOR; + tagMargin = dpToPx(DEFAULT_TAG_MARGIN); + return; + } + + // 从XML获取属性 + TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.QXMeetUserView); + avatarSize = ta.getDimensionPixelSize(R.styleable.QXMeetUserView_avatarSize, dpToPx(DEFAULT_AVATAR_SIZE)); + dressSize = ta.getDimensionPixelSize(R.styleable.QXMeetUserView_dressSize, dpToPx(DEFAULT_DRESS_SIZE)); + nameTextSize = ta.getDimension(R.styleable.QXMeetUserView_nameTextSize, DEFAULT_NAME_TEXT_SIZE); + nameTextColor = ta.getColor(R.styleable.QXMeetUserView_nameTextColor, DEFAULT_NAME_TEXT_COLOR); + tagTextSize = ta.getDimension(R.styleable.QXMeetUserView_tagTextSize, DEFAULT_TAG_TEXT_SIZE); + tagTextColor = ta.getColor(R.styleable.QXMeetUserView_tagTextColor, DEFAULT_TAG_TEXT_COLOR); + tagMargin = ta.getDimensionPixelSize(R.styleable.QXMeetUserView_tagMargin, dpToPx(DEFAULT_TAG_MARGIN)); + ta.recycle(); + + // 日志输出属性值,便于调试 + Log.d(TAG, "属性初始化 - 头像大小: " + avatarSize + ", 装饰大小: " + dressSize); + } + + private void initSubviews(Context context) { + setClipChildren(false); + setClipToPadding(false); + setWillNotDraw(false); + // 为整个视图添加背景色,便于调试视图范围 + // setBackgroundColor(0x0A000000); // 极浅灰色背景 + + // 2. 头像(中间层) + headerImageView = new GifAvatarOvalView(context); + headerImageView.setId(View.generateViewId()); + headerImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + // 设置强制背景色,确保即使资源加载失败也能看到 + // headerImageView.setBackgroundColor(0x33FF0000); // 半透明红色 + + // 尝试加载默认头像资源 + try { + int resId = R.mipmap.default_avatar; + // headerImageView.setImageResource(resId); + Log.d(TAG, "尝试加载默认头像资源: " + resId); + } catch (Exception e) { + Log.e(TAG, "默认头像资源加载失败: " + e.getMessage()); + } + + LayoutParams headerParams = new LayoutParams(avatarSize, avatarSize); + headerParams.addRule(CENTER_IN_PARENT); // 头像在父容器居中 + addView(headerImageView, headerParams); + Log.d(TAG, "头像已添加到视图,大小: " + avatarSize + "x" + avatarSize); + + + + // 1. 装饰图(底层)- 优先初始化确保在最底层 + dressImageView = new ImageView(context); + dressImageView.setId(View.generateViewId()); + dressImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + // 设置强制背景色,确保即使资源加载失败也能看到 + /// dressImageView.setBackgroundColor(0x330000FF); // 半透明蓝色 + + // 尝试加载装饰图资源 + try { + int resId = R.mipmap.xlh_image; + dressImageView.setImageResource(resId); + Log.d(TAG, "尝试加载装饰图资源: " + resId); + } catch (Exception e) { + Log.e(TAG, "装饰图资源加载失败: " + e.getMessage()); + } + + LayoutParams dressParams = new LayoutParams(dressSize, dressSize); + dressParams.addRule(CENTER_HORIZONTAL); + dressParams.topMargin = dpToPx(5); // 稍微向下移动一点,确保可见 + addView(dressImageView, dressParams); + Log.d(TAG, "装饰图已添加到视图,大小: " + dressSize + "x" + dressSize); + + + // 3. 标签(顶层,与头像底部平齐) + tagLabel = new TextView(context); + tagLabel.setId(View.generateViewId()); + tagLabel.setTextColor(tagTextColor); + tagLabel.setTextSize(tagTextSize); + tagLabel.setGravity(Gravity.CENTER); + tagLabel.setText("房主"); + tagLabel.setBackground(getRoundedRectBackground(0xFF8D6F28, dpToPx(8))); + tagLabel.setPadding(dpToPx(6), 0, dpToPx(6), 0); + + LayoutParams tagParams = new LayoutParams(LayoutParams.WRAP_CONTENT, dpToPx(16)); + tagParams.addRule(CENTER_HORIZONTAL); + addView(tagLabel, tagParams); + + // 4. 名字(顶层,在标签下方) + nameLabel = new TextView(context); + nameLabel.setId(View.generateViewId()); + nameLabel.setTextColor(nameTextColor); + nameLabel.setTextSize(nameTextSize); + nameLabel.setText("虚位以待"); + nameLabel.setGravity(Gravity.CENTER); + nameLabel.setSingleLine(true); + + LayoutParams nameParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + nameParams.addRule(CENTER_HORIZONTAL); + nameParams.addRule(BELOW, tagLabel.getId()); + nameParams.topMargin = dpToPx(NAME_MARGIN_TOP); + addView(nameLabel, nameParams); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // 强制设置最小宽高,确保视图可见 + int minWidth = Math.max(avatarSize, dressSize); + int minHeight = dressSize + dpToPx(40); // 装饰图高度 + 标签和名字的高度 + + int width = resolveSizeAndState(minWidth, widthMeasureSpec, 0); + int height = resolveSizeAndState(minHeight, heightMeasureSpec, 0); + + setMeasuredDimension(width, height); + + // 测量子视图 + measureChildren( + MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + ); + + Log.d(TAG, "onMeasure - 视图大小: " + width + "x" + height); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + + // 确保装饰图正确布局 + if (dressImageView != null) { + int dressLeft = (getWidth() - dressSize) / 2; + int dressTop = dpToPx(5); // 顶部留出一点空间 + dressImageView.layout( + dressLeft, + dressTop, + dressLeft + dressSize, + dressTop + dressSize + ); + Log.d(TAG, "装饰图布局位置: " + dressLeft + "," + dressTop + "," + + (dressLeft + dressSize) + "," + (dressTop + dressSize)); + } + + // 确保头像正确布局 + if (headerImageView != null) { + int avatarLeft = (getWidth() - avatarSize) / 2; + int avatarTop = (dressSize - avatarSize) / 2 + dpToPx(5); // 居中显示在装饰图上 + headerImageView.layout( + avatarLeft, + avatarTop, + avatarLeft + avatarSize, + avatarTop + avatarSize + ); + Log.d(TAG, "头像布局位置: " + avatarLeft + "," + avatarTop + "," + + (avatarLeft + avatarSize) + "," + (avatarTop + avatarSize)); + } + + // 标签布局(与头像底部平齐) + if (headerImageView != null && tagLabel != null) { + int avatarBottom = headerImageView.getBottom(); + int tagTop = avatarBottom + tagMargin; + int tagLeft = (getWidth() - tagLabel.getMeasuredWidth()) / 2; + + tagLabel.layout( + tagLeft, + tagTop, + tagLeft + tagLabel.getMeasuredWidth(), + tagTop + tagLabel.getMeasuredHeight() + ); + } + + // 名字布局(在标签下方) + if (tagLabel != null && nameLabel != null) { + int tagBottom = tagLabel.getBottom(); + int nameTop = tagBottom + dpToPx(NAME_MARGIN_TOP); + int nameLeft = (getWidth() - nameLabel.getMeasuredWidth()) / 2; + + nameLabel.layout( + nameLeft, + nameTop, + nameLeft + nameLabel.getMeasuredWidth(), + nameTop + nameLabel.getMeasuredHeight() + ); + } + } + + // 以下方法保持不变 + public void setIsLuckUser(boolean isLuckUser) { + if (tagLabel == null) return; + + if (isLuckUser) { + tagLabel.setTextColor(0xFFFFFFFF); + tagLabel.setBackground(getRoundedRectBackground(0xFF6C49E4, dpToPx(8))); + tagLabel.setText("幸运者"); + } else { + tagLabel.setTextColor(tagTextColor); + tagLabel.setBackground(getRoundedRectBackground(0xFF8D6F28, dpToPx(8))); + tagLabel.setText("房主"); + } + } + + public void setModel(BlindBoxBean.xlhUser model) { + + if (headerImageView == null || nameLabel == null) return; + + if (model != null) { + try { + if (model.getAvatar().toString()!=""){ + ImageUtils.loadHeadCC(model.getAvatar(), headerImageView); + }else { + int resId = R.mipmap.default_avatar; + headerImageView.setImageResource(resId); + } + + Log.d(TAG, "加载用户头像: " + model.getAvatar()); + } catch (Exception e) { + int resId = R.mipmap.default_avatar; + headerImageView.setImageResource(resId); + Log.e(TAG, "加载用户头像失败: " + e.getMessage()); + //headerImageView.setBackgroundColor(0x33FF0000); // 保持红色背景以便识别 + } + nameLabel.setText(model.getNickname() != null ? model.getNickname() : "虚位以待"); + } else { + resetView(); + } + } + + public void resetView() { + if (headerImageView != null) { + try { + headerImageView.setImageResource(R.mipmap.default_avatar); + } catch (Exception e) { + Log.e(TAG, "重置头像失败: " + e.getMessage()); + // headerImageView.setBackgroundColor(0x33FF0000); + } + } + if (nameLabel != null) { + nameLabel.setText("虚位以待"); + } + setIsLuckUser(false); + } + + private GradientDrawable getRoundedRectBackground(int color, float radius) { + GradientDrawable drawable = new GradientDrawable(); + drawable.setColor(color); + drawable.setCornerRadius(radius); + return drawable; + } + + private int dpToPx(int dp) { + float density = getResources().getDisplayMetrics().density; + return Math.round(dp * density); + } + + // Getter方法 + public ImageView getHeaderImageView() { return headerImageView; } + public ImageView getDressImageView() { return dressImageView; } + public TextView getTagLabel() { return tagLabel; } + public TextView getNameLabel() { return nameLabel; } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/view/QXRedBagSendView.java b/moduleUtil/src/main/java/com/xscm/moduleutil/view/QXRedBagSendView.java new file mode 100644 index 00000000..3c924550 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/view/QXRedBagSendView.java @@ -0,0 +1,860 @@ +package com.xscm.moduleutil.view; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Color; +import android.text.InputType; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; +import android.webkit.WebView; +import android.widget.Button; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; +import com.xscm.moduleutil.R; + +public class QXRedBagSendView extends FrameLayout { + + // Properties + private String redBagType = "1"; + private String redBagContentType = "1"; + private String redBagTime = "0"; + private int currentPage = 0; + private boolean isFromRule = false; + + // UI Components + private LinearLayout mainContainer; + private ImageView bgImageView; + private TextView titleLabel; + private Button helpBtn; + private Button backBtn; + private Button closeBtn; + private Button nextBtn; + private Button commitBtn; + + private LinearLayout firstContentView; + private Button normalRedBagBtn; + private Button pwdRedBagBtn; + private LinearLayout firstPwdView; + private EditText pwdTextField; + private LinearLayout firstTimeView; + private View scrollBgView; + private Button coinRedBagBtn; + private Button diamondRedBagBtn; + private Button selectedRedBagTimeBtn; + + private LinearLayout nextContentView; + private TextView moneyLabel; + private TextView moneyUnitLabel; + private EditText moneyTextField; + private EditText countTextField; + private EditText remarkTextField; + private Button noDrawAuthBtn; + private Button collectDrawAuthBtn; + private Button upSeatDrawAuthBtn; + + private LinearLayout ruleContentView; + private WebView webView; + + private final int[] timeArray = {0, 1, 2, 5, 10}; + private final int[] drawAuthArray = {0, 1, 2}; + + public QXRedBagSendView(Context context) { + super(context); + init(context); + } + + public QXRedBagSendView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public QXRedBagSendView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + )); + setBackgroundColor(Color.parseColor("#80000000")); + + initMainContainer(context); + initTitleBar(context); + initContentArea(context); + initButtons(context); + + // 默认选择普通红包 + selectedRedBagTypeAction(normalRedBagBtn); + } + + private void initMainContainer(Context context) { + mainContainer = new LinearLayout(context); + mainContainer.setOrientation(LinearLayout.VERTICAL); + LayoutParams containerParams = new LayoutParams( + dpToPx(345), + dpToPx(454) + ); + containerParams.gravity = Gravity.CENTER; + mainContainer.setLayoutParams(containerParams); + + // 背景图片 + bgImageView = new ImageView(context); + bgImageView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + )); + // 设置背景资源,需要你在res/drawable中添加对应的图片 + bgImageView.setBackgroundResource(R.mipmap.red_en); +// bgImageView.setBackgroundColor(Color.parseColor("#FFD700")); // 临时颜色 + + // 将背景图片添加到主容器 + mainContainer.addView(bgImageView); + + addView(mainContainer); + } + + private void initTitleBar(Context context) { + // 标题栏容器 + LinearLayout titleContainer = new LinearLayout(context); + titleContainer.setOrientation(LinearLayout.HORIZONTAL); + titleContainer.setGravity(Gravity.CENTER_VERTICAL); + LinearLayout.LayoutParams titleContainerParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ); + titleContainerParams.setMargins(0, dpToPx(15), 0, 0); + titleContainer.setLayoutParams(titleContainerParams); + + // 帮助按钮 + helpBtn = createIconButton(context); + helpBtn.setBackgroundColor(Color.TRANSPARENT); + helpBtn.setOnClickListener(v -> helpAction()); + titleContainer.addView(helpBtn); + + // 返回按钮 + backBtn = createIconButton(context); + backBtn.setBackgroundColor(Color.TRANSPARENT); + backBtn.setOnClickListener(v -> backAction()); + backBtn.setVisibility(View.GONE); + titleContainer.addView(backBtn); + + // 标题 + titleLabel = new TextView(context); + titleLabel.setText("直播间红包"); + titleLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); + titleLabel.setTextColor(Color.WHITE); + titleLabel.setTypeface(titleLabel.getTypeface(), android.graphics.Typeface.BOLD); + LinearLayout.LayoutParams titleParams = new LinearLayout.LayoutParams( + 0, ViewGroup.LayoutParams.WRAP_CONTENT, 1 + ); + titleLabel.setLayoutParams(titleParams); + titleLabel.setGravity(Gravity.CENTER); + titleContainer.addView(titleLabel); + + // 关闭按钮 + closeBtn = createIconButton(context); + closeBtn.setBackgroundColor(Color.TRANSPARENT); + closeBtn.setOnClickListener(v -> closeAction()); + titleContainer.addView(closeBtn); + + // 将标题栏添加到主容器(在背景图片之上) + mainContainer.addView(titleContainer); + } + + private void initContentArea(Context context) { + // 内容区域容器 + LinearLayout contentArea = new LinearLayout(context); + contentArea.setOrientation(LinearLayout.VERTICAL); + LinearLayout.LayoutParams contentParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + 0, 1 + ); + contentParams.setMargins(dpToPx(15), dpToPx(15), dpToPx(15), dpToPx(15)); + contentArea.setLayoutParams(contentParams); + + initFirstContentView(context, contentArea); + initNextContentView(context, contentArea); + initRuleView(context, contentArea); + + mainContainer.addView(contentArea); + } + + private void initButtons(Context context) { + // 按钮容器 + LinearLayout buttonContainer = new LinearLayout(context); + buttonContainer.setOrientation(LinearLayout.VERTICAL); + LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ); + buttonParams.setMargins(dpToPx(15), 0, dpToPx(15), dpToPx(15)); + buttonContainer.setLayoutParams(buttonParams); + + // 下一步按钮 + nextBtn = createActionButton(context, "下一步"); + nextBtn.setOnClickListener(v -> nextAction()); + buttonContainer.addView(nextBtn); + + // 提交按钮 + commitBtn = createActionButton(context, "发红包"); + commitBtn.setOnClickListener(v -> commitAction()); + commitBtn.setVisibility(View.GONE); + buttonContainer.addView(commitBtn); + + mainContainer.addView(buttonContainer); + } + + private void initFirstContentView(Context context, ViewGroup parent) { + firstContentView = new LinearLayout(context); + firstContentView.setOrientation(LinearLayout.VERTICAL); + firstContentView.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + )); + parent.addView(firstContentView); + + // 顶部视图 - 参与领取限制 + LinearLayout firstTopView = createCardView(context); + firstTopView.setOrientation(LinearLayout.VERTICAL); + LinearLayout.LayoutParams topParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + dpToPx(88) + ); + topParams.bottomMargin = dpToPx(12); + firstTopView.setLayoutParams(topParams); + firstContentView.addView(firstTopView); + + TextView topTitleLabel = createTitleLabel(context, "参与领取限制"); + firstTopView.addView(topTitleLabel); + + LinearLayout typeButtonContainer = new LinearLayout(context); + typeButtonContainer.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + typeButtonContainer.setWeightSum(2); + firstTopView.addView(typeButtonContainer); + + normalRedBagBtn = createTypeButton(context, "普通红包"); + normalRedBagBtn.setOnClickListener(v -> selectedRedBagTypeAction(normalRedBagBtn)); + typeButtonContainer.addView(normalRedBagBtn); + + pwdRedBagBtn = createTypeButton(context, "口令红包"); + pwdRedBagBtn.setOnClickListener(v -> selectedRedBagTypeAction(pwdRedBagBtn)); + typeButtonContainer.addView(pwdRedBagBtn); + + // 口令输入视图 + firstPwdView = createInputCard(context, "口令", "请输入口令"); + pwdTextField = (EditText) ((LinearLayout) firstPwdView).getChildAt(1); + firstContentView.addView(firstPwdView); + + // 时间选择视图 + firstTimeView = createCardView(context); + firstTimeView.setOrientation(LinearLayout.VERTICAL); + LinearLayout.LayoutParams timeParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + dpToPx(88) + ); + timeParams.bottomMargin = dpToPx(12); + firstTimeView.setLayoutParams(timeParams); + firstContentView.addView(firstTimeView); + + TextView timeTitleLabel = createTitleLabel(context, "开奖倒计时"); + firstTimeView.addView(timeTitleLabel); + + LinearLayout timeButtonContainer = new LinearLayout(context); + timeButtonContainer.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + firstTimeView.addView(timeButtonContainer); + + // 创建时间选择按钮 + for (int time : timeArray) { + Button timeBtn = createTimeButton(context, time); + timeBtn.setOnClickListener(v -> redBagTimeAction(timeBtn)); + if (time == 0) { + timeBtn.setSelected(true); + selectedRedBagTimeBtn = timeBtn; + } + timeButtonContainer.addView(timeBtn); + } + + // 红包类型选择 + LinearLayout bottomView = createCardView(context); + bottomView.setOrientation(LinearLayout.HORIZONTAL); + bottomView.setGravity(Gravity.CENTER_VERTICAL); + LinearLayout.LayoutParams bottomParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + dpToPx(48) + ); + bottomView.setLayoutParams(bottomParams); + firstContentView.addView(bottomView); + + TextView redBagTypeLabel = createTitleLabel(context, "红包类型"); + bottomView.addView(redBagTypeLabel); + + // 红包类型切换容器 + RelativeLayout typeSwitchContainer = new RelativeLayout(context); + LinearLayout.LayoutParams switchParams = new LinearLayout.LayoutParams( + dpToPx(130), + dpToPx(26) + ); + switchParams.gravity = Gravity.CENTER_VERTICAL; + typeSwitchContainer.setLayoutParams(switchParams); + typeSwitchContainer.setBackgroundColor(Color.parseColor("#BA230A")); + typeSwitchContainer.setPadding(dpToPx(2), dpToPx(2), dpToPx(2), dpToPx(2)); + bottomView.addView(typeSwitchContainer); + + scrollBgView = new View(context); + RelativeLayout.LayoutParams scrollParams = new RelativeLayout.LayoutParams( + dpToPx(63), + ViewGroup.LayoutParams.MATCH_PARENT + ); + scrollBgView.setLayoutParams(scrollParams); + scrollBgView.setBackgroundColor(Color.parseColor("#FDE8A3")); + typeSwitchContainer.addView(scrollBgView); + + coinRedBagBtn = createContentTypeButton(context, "金币红包"); + coinRedBagBtn.setSelected(true); + coinRedBagBtn.setOnClickListener(v -> redBagContentTypeAction(coinRedBagBtn)); + typeSwitchContainer.addView(coinRedBagBtn); + + diamondRedBagBtn = createContentTypeButton(context, "钻石红包"); + diamondRedBagBtn.setOnClickListener(v -> redBagContentTypeAction(diamondRedBagBtn)); + typeSwitchContainer.addView(diamondRedBagBtn); + } + + private void initNextContentView(Context context, ViewGroup parent) { + nextContentView = new LinearLayout(context); + nextContentView.setOrientation(LinearLayout.VERTICAL); + nextContentView.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + )); + nextContentView.setVisibility(View.GONE); + parent.addView(nextContentView); + + // 可用余额标签 + moneyLabel = new TextView(context); + moneyLabel.setText("-金币可用"); + moneyLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13); + moneyLabel.setTextColor(Color.WHITE); + LinearLayout.LayoutParams moneyLabelParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ); + moneyLabelParams.gravity = Gravity.END; + moneyLabel.setLayoutParams(moneyLabelParams); + nextContentView.addView(moneyLabel); + + // 金额输入 + LinearLayout moneyBgView = createInputCard(context, "金额", "请输入红包金额"); + moneyTextField = (EditText) moneyBgView.getChildAt(1); + + moneyUnitLabel = new TextView(context); + moneyUnitLabel.setText("金币"); + moneyUnitLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13); + moneyUnitLabel.setTextColor(Color.parseColor("#666666")); + LinearLayout.LayoutParams unitParams = new LinearLayout.LayoutParams( + dpToPx(30), + ViewGroup.LayoutParams.WRAP_CONTENT + ); + moneyUnitLabel.setLayoutParams(unitParams); + moneyBgView.addView(moneyUnitLabel); + + nextContentView.addView(moneyBgView); + + // 个数输入 + LinearLayout countBgView = createInputCard(context, "个数", "请输入红包数量"); + countTextField = (EditText) countBgView.getChildAt(1); + + TextView countUnitLabel = new TextView(context); + countUnitLabel.setText("个"); + countUnitLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13); + countUnitLabel.setTextColor(Color.parseColor("#666666")); + countUnitLabel.setLayoutParams(unitParams); + countBgView.addView(countUnitLabel); + + nextContentView.addView(countBgView); + + // 领取条件 + LinearLayout drawAuthBgView = createCardView(context); + drawAuthBgView.setOrientation(LinearLayout.VERTICAL); + LinearLayout.LayoutParams authParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + dpToPx(88) + ); + authParams.bottomMargin = dpToPx(12); + drawAuthBgView.setLayoutParams(authParams); + nextContentView.addView(drawAuthBgView); + + TextView authTitleLabel = createTitleLabel(context, "条件"); + drawAuthBgView.addView(authTitleLabel); + + LinearLayout authButtonContainer = new LinearLayout(context); + authButtonContainer.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + )); + drawAuthBgView.addView(authButtonContainer); + + // 创建领取条件按钮 + noDrawAuthBtn = createAuthButton(context, "无"); + noDrawAuthBtn.setSelected(true); + noDrawAuthBtn.setOnClickListener(v -> drawAuthAction(noDrawAuthBtn)); + authButtonContainer.addView(noDrawAuthBtn); + + collectDrawAuthBtn = createAuthButton(context, "收藏房间"); + collectDrawAuthBtn.setOnClickListener(v -> drawAuthAction(collectDrawAuthBtn)); + authButtonContainer.addView(collectDrawAuthBtn); + + upSeatDrawAuthBtn = createAuthButton(context, "仅麦上用户"); + upSeatDrawAuthBtn.setOnClickListener(v -> drawAuthAction(upSeatDrawAuthBtn)); + authButtonContainer.addView(upSeatDrawAuthBtn); + + // 备注输入 + LinearLayout remarkBgView = createInputCard(context, "备注", "请输入备注"); + remarkTextField = (EditText) remarkBgView.getChildAt(1); + nextContentView.addView(remarkBgView); + } + + private void initRuleView(Context context, ViewGroup parent) { + ruleContentView = new LinearLayout(context); + ruleContentView.setOrientation(LinearLayout.VERTICAL); + ruleContentView.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + )); + ruleContentView.setBackgroundColor(Color.WHITE); + ruleContentView.setPadding(dpToPx(15), dpToPx(15), dpToPx(15), dpToPx(15)); + ruleContentView.setVisibility(View.GONE); + parent.addView(ruleContentView); + + webView = new WebView(context); + webView.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + )); + ruleContentView.addView(webView); + } + + // 工具方法 + private Button createIconButton(Context context) { + Button button = new Button(context); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + dpToPx(40), + dpToPx(40) + ); + button.setLayoutParams(params); + return button; + } + + private Button createActionButton(Context context, String text) { + Button button = new Button(context); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + dpToPx(44) + ); + button.setLayoutParams(params); + button.setText(text); + button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); + button.setTextColor(Color.parseColor("#F35248")); + button.setTypeface(button.getTypeface(), android.graphics.Typeface.BOLD); + button.setBackgroundColor(Color.parseColor("#FDE8A3")); // 临时背景色 + return button; + } + + private LinearLayout createCardView(Context context) { + LinearLayout card = new LinearLayout(context); + card.setBackgroundColor(Color.WHITE); + card.setPadding(dpToPx(15), dpToPx(11), dpToPx(15), dpToPx(5)); + return card; + } + + private TextView createTitleLabel(Context context, String text) { + TextView label = new TextView(context); + label.setText(text); + label.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); + label.setTextColor(Color.parseColor("#666666")); + label.setTypeface(label.getTypeface(), android.graphics.Typeface.BOLD); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + dpToPx(26) + ); + label.setLayoutParams(params); + return label; + } + + private Button createTypeButton(Context context, String text) { + Button button = new Button(context); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + 0, dpToPx(36), 1 + ); + params.setMargins(0, 0, dpToPx(10), 0); + button.setLayoutParams(params); + button.setText(text); + button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); + button.setTextColor(Color.WHITE); + button.setTypeface(button.getTypeface(), android.graphics.Typeface.BOLD); + button.setBackgroundColor(Color.parseColor("#FF9999")); // 临时背景色 + return button; + } + + private LinearLayout createInputCard(Context context, String title, String hint) { + LinearLayout card = new LinearLayout(context); + card.setOrientation(LinearLayout.HORIZONTAL); + card.setGravity(Gravity.CENTER_VERTICAL); + LinearLayout.LayoutParams cardParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + dpToPx(48) + ); + cardParams.bottomMargin = dpToPx(12); + card.setLayoutParams(cardParams); + card.setBackgroundColor(Color.WHITE); + card.setPadding(dpToPx(15), 0, dpToPx(15), 0); + + TextView titleLabel = createTitleLabel(context, title); + card.addView(titleLabel); + + EditText editText = new EditText(context); + LinearLayout.LayoutParams editParams = new LinearLayout.LayoutParams( + 0, ViewGroup.LayoutParams.MATCH_PARENT, 1 + ); + editParams.setMargins(dpToPx(15), 0, dpToPx(15), 0); + editText.setLayoutParams(editParams); + editText.setHint(hint); + editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); + editText.setTextColor(Color.parseColor("#666666")); + editText.setGravity(Gravity.END); + editText.setBackground(null); + editText.setInputType(InputType.TYPE_CLASS_TEXT); + card.addView(editText); + + return card; + } + + private Button createTimeButton(Context context, int minutes) { + Button button = new Button(context); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + dpToPx(49), dpToPx(36) + ); + params.setMargins(0, 0, dpToPx(10), 0); + button.setLayoutParams(params); + + String text = minutes == 0 ? "立刻" : minutes + "分钟"; + button.setText(text); + button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); + button.setTypeface(button.getTypeface(), android.graphics.Typeface.BOLD); + button.setBackgroundColor(Color.parseColor("#EEEEEE")); // 临时背景色 + return button; + } + + private Button createContentTypeButton(Context context, String text) { + Button button = new Button(context); + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( + dpToPx(63), ViewGroup.LayoutParams.MATCH_PARENT + ); + button.setLayoutParams(params); + button.setText(text); + button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12); + button.setBackgroundColor(Color.TRANSPARENT); + button.setTextColor(Color.parseColor("#FFC9C7")); + return button; + } + + private Button createAuthButton(Context context, String text) { + Button button = new Button(context); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + 0, dpToPx(36), 1 + ); + params.setMargins(0, 0, dpToPx(10), 0); + button.setLayoutParams(params); + button.setText(text); + button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12); + button.setTypeface(button.getTypeface(), android.graphics.Typeface.BOLD); + button.setBackgroundColor(Color.parseColor("#EEEEEE")); // 临时背景色 + return button; + } + + private int dpToPx(int dp) { + return (int) TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + dp, + getResources().getDisplayMetrics() + ); + } + + // Action Methods + private void nextAction() { + currentPage = 1; + moneyUnitLabel.setText(redBagContentType.equals("1") ? "金币" : "钻石"); + + backBtn.setVisibility(View.GONE); + helpBtn.setVisibility(View.VISIBLE); + nextBtn.setVisibility(View.GONE); + commitBtn.setVisibility(View.VISIBLE); + + switchContentView(firstContentView, nextContentView); + } + + private void commitAction() { + // 实现发红包逻辑 + } + + private void helpAction() { + isFromRule = true; + webView.loadUrl("http://www.baidu.com"); + + backBtn.setVisibility(View.VISIBLE); + helpBtn.setVisibility(View.GONE); + nextBtn.setVisibility(View.GONE); + commitBtn.setVisibility(View.GONE); + + View currentView = currentPage == 1 ? nextContentView : firstContentView; + switchContentView(currentView, ruleContentView); + } + + private void closeAction() { + hide(); + } + + private void backAction() { + backBtn.setVisibility(View.GONE); + helpBtn.setVisibility(View.VISIBLE); + + View currentView = currentPage == 1 ? nextContentView : firstContentView; + + nextBtn.setVisibility(currentPage == 0 ? View.VISIBLE : View.GONE); + commitBtn.setVisibility(currentPage == 1 ? View.VISIBLE : View.GONE); + + switchContentView(ruleContentView, currentView); + isFromRule = false; + } + + private void selectedRedBagTypeAction(Button sender) { + if (sender.isSelected()) return; + + if (sender == normalRedBagBtn) { + pwdRedBagBtn.setSelected(false); + normalRedBagBtn.setSelected(true); + firstPwdView.setVisibility(View.GONE); + + // 调整时间视图位置 + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) firstTimeView.getLayoutParams(); + params.topMargin = 0; + params.bottomMargin = dpToPx(12); + firstTimeView.setLayoutParams(params); + + redBagType = "1"; + } else { + pwdRedBagBtn.setSelected(true); + normalRedBagBtn.setSelected(false); + firstPwdView.setVisibility(View.VISIBLE); + + // 调整时间视图位置 + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) firstTimeView.getLayoutParams(); + params.topMargin = dpToPx(60); + params.bottomMargin = dpToPx(12); + firstTimeView.setLayoutParams(params); + + redBagType = "2"; + } + + // 更新按钮背景色 + updateButtonSelection(normalRedBagBtn, sender == normalRedBagBtn); + updateButtonSelection(pwdRedBagBtn, sender == pwdRedBagBtn); + } + + private void redBagContentTypeAction(Button sender) { + if (sender.isSelected()) return; + + if (sender == coinRedBagBtn) { + diamondRedBagBtn.setSelected(false); + coinRedBagBtn.setSelected(true); + redBagContentType = "1"; + animateSwitchBg(true); + } else { + coinRedBagBtn.setSelected(false); + diamondRedBagBtn.setSelected(true); + redBagContentType = "2"; + animateSwitchBg(false); + } + + // 更新按钮文字颜色 + updateContentTypeButtonColor(coinRedBagBtn, coinRedBagBtn.isSelected()); + updateContentTypeButtonColor(diamondRedBagBtn, diamondRedBagBtn.isSelected()); + } + + private void drawAuthAction(Button sender) { + if (sender == noDrawAuthBtn) { + noDrawAuthBtn.setSelected(true); + collectDrawAuthBtn.setSelected(false); + upSeatDrawAuthBtn.setSelected(false); + } else if (sender == collectDrawAuthBtn) { + collectDrawAuthBtn.setSelected(!collectDrawAuthBtn.isSelected()); + if (upSeatDrawAuthBtn.isSelected() || collectDrawAuthBtn.isSelected()) { + noDrawAuthBtn.setSelected(false); + } else { + noDrawAuthBtn.setSelected(true); + } + } else if (sender == upSeatDrawAuthBtn) { + noDrawAuthBtn.setSelected(false); + upSeatDrawAuthBtn.setSelected(!upSeatDrawAuthBtn.isSelected()); + if (upSeatDrawAuthBtn.isSelected() || collectDrawAuthBtn.isSelected()) { + noDrawAuthBtn.setSelected(false); + } else { + noDrawAuthBtn.setSelected(true); + } + } + + // 更新按钮背景色 + updateAuthButtonSelection(noDrawAuthBtn, noDrawAuthBtn.isSelected()); + updateAuthButtonSelection(collectDrawAuthBtn, collectDrawAuthBtn.isSelected()); + updateAuthButtonSelection(upSeatDrawAuthBtn, upSeatDrawAuthBtn.isSelected()); + } + + private void redBagTimeAction(Button sender) { + if (sender.isSelected()) return; + + if (selectedRedBagTimeBtn != null) { + selectedRedBagTimeBtn.setSelected(false); + updateTimeButtonSelection(selectedRedBagTimeBtn, false); + } + + sender.setSelected(true); + selectedRedBagTimeBtn = sender; + int minutes = 0; + try { + String text = sender.getText().toString(); + if (text.equals("立刻")) { + minutes = 0; + } else { + minutes = Integer.parseInt(text.replace("分钟", "")); + } + } catch (Exception e) { + minutes = 0; + } + redBagTime = String.valueOf(minutes * 60); + + updateTimeButtonSelection(sender, true); + } + + // Helper Methods + private void switchContentView(View hideView, View showView) { + hideView.setVisibility(View.GONE); + showView.setVisibility(View.VISIBLE); + } + + private void updateButtonSelection(Button button, boolean selected) { + button.setBackgroundColor(selected ? + Color.parseColor("#FF5555") : Color.parseColor("#FF9999")); + } + + private void updateTimeButtonSelection(Button button, boolean selected) { + button.setBackgroundColor(selected ? + Color.parseColor("#FF5555") : Color.parseColor("#EEEEEE")); + } + + private void updateAuthButtonSelection(Button button, boolean selected) { + button.setBackgroundColor(selected ? + Color.parseColor("#FF5555") : Color.parseColor("#EEEEEE")); + } + + private void updateContentTypeButtonColor(Button button, boolean selected) { + button.setTextColor(selected ? + Color.parseColor("#D01717") : Color.parseColor("#FFC9C7")); + } + + private void animateSwitchBg(boolean toLeft) { + int targetX = toLeft ? 0 : dpToPx(63); + + ValueAnimator animator = ValueAnimator.ofInt( + ((RelativeLayout.LayoutParams) scrollBgView.getLayoutParams()).leftMargin, + targetX + ); + animator.addUpdateListener(animation -> { + int value = (int) animation.getAnimatedValue(); + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) scrollBgView.getLayoutParams(); + params.leftMargin = value; + scrollBgView.setLayoutParams(params); + }); + animator.setDuration(300); + animator.setInterpolator(new DecelerateInterpolator()); + animator.start(); + } + + // Public Methods + public void showInView(ViewGroup parent) { + parent.addView(this); + + // 添加入场动画 + mainContainer.setTranslationY(-getHeight()); + mainContainer.animate() + .translationY(0) + .setDuration(300) + .setInterpolator(new DecelerateInterpolator()) + .start(); + } + + public void hide() { + // 添加退场动画 + mainContainer.animate() + .translationY(getHeight()) + .setDuration(300) + .setInterpolator(new DecelerateInterpolator()) + .withEndAction(() -> { + ViewGroup parent = (ViewGroup) getParent(); + if (parent != null) { + parent.removeView(QXRedBagSendView.this); + } + }) + .start(); + } + + // Getter methods + public String getRedBagType() { + return redBagType; + } + + public String getRedBagContentType() { + return redBagContentType; + } + + public String getRedBagTime() { + return redBagTime; + } + + public String getPassword() { + return pwdTextField.getText().toString(); + } + + public String getMoney() { + return moneyTextField.getText().toString(); + } + + public String getCount() { + return countTextField.getText().toString(); + } + + public String getRemark() { + return remarkTextField.getText().toString(); + } + + public int getDrawAuth() { + if (noDrawAuthBtn.isSelected()) return 0; + if (collectDrawAuthBtn.isSelected()) return 1; + if (upSeatDrawAuthBtn.isSelected()) return 2; + return 0; + } +} \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/view/QXTimeDownView.java b/moduleUtil/src/main/java/com/xscm/moduleutil/view/QXTimeDownView.java new file mode 100644 index 00000000..5743c9db --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/view/QXTimeDownView.java @@ -0,0 +1,268 @@ +package com.xscm.moduleutil.view; + +import android.content.Context; +import android.graphics.Typeface; +import android.os.Handler; +import android.os.Looper; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.ScaleAnimation; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.xscm.moduleutil.R; + +public class QXTimeDownView extends FrameLayout { + + private ImageView bgImageView; + private TextView titleLabel; + private TextView timeLabel; + private TextView bigTimeLabel; + + private long endTime; + private long startTime; + private Handler timerHandler; + private Runnable timerRunnable; + + private TimeDownDelegate delegate; + + public interface TimeDownDelegate { + void timeDownStartAnimation(); + void timeDownUpdateAnimationWithTime(long time); + void timeDownStopAnimation(); + void timeDownDidFinished(); + } + + public QXTimeDownView(Context context) { + super(context); + initSubviews(context); + } + + public QXTimeDownView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + initSubviews(context); + } + + public QXTimeDownView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initSubviews(context); + } + + private void initSubviews(Context context) { + // 背景图片(最大的圆圈) + bgImageView = new ImageView(context); + bgImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + bgImageView.setImageResource(R.drawable.ac_time_down_bg); + LayoutParams bgParams = new LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT + ); + bgParams.gravity = Gravity.CENTER; + addView(bgImageView, bgParams); + + // 时间标签(居中显示在背景图上) + timeLabel = new TextView(context); + timeLabel.setTextSize(16); + timeLabel.setTextColor(0xFFFFECA7); + timeLabel.setGravity(Gravity.CENTER); + timeLabel.setTypeface(android.graphics.Typeface.create("sans-serif-condensed", android.graphics.Typeface.NORMAL)); + LayoutParams timeParams = new LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT + ); + timeParams.gravity = Gravity.CENTER; + timeParams.topMargin = dpToPx(-10); + addView(timeLabel, timeParams); + + // 标题标签(显示在时间标签下方) + titleLabel = new TextView(context); + titleLabel.setTextSize(12); + titleLabel.setTextColor(0xFFFFECA7); + titleLabel.setText("倒计时"); + titleLabel.setGravity(Gravity.CENTER); + LayoutParams titleParams = new LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT + ); + titleParams.gravity = Gravity.CENTER; + titleParams.topMargin = dpToPx(12); // 在timeLabel下方一定距离 + addView(titleLabel, titleParams); + + // 大时间标签(初始隐藏,用于最后30秒显示) + bigTimeLabel = new TextView(context); + bigTimeLabel.setTextSize(20); + bigTimeLabel.setText("-"); + bigTimeLabel.setTextColor(0xFFFFECA7); + bigTimeLabel.setGravity(Gravity.CENTER); + bigTimeLabel.setVisibility(View.GONE); + bigTimeLabel.setTypeface(Typeface.create("semibold", Typeface.NORMAL)); + LayoutParams bigTimeParams = new LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT + ); + bigTimeParams.gravity = Gravity.CENTER; + addView(bigTimeLabel, bigTimeParams); + + // 初始化定时器 + timerHandler = new Handler(Looper.getMainLooper()); + } + + public void setEndTime(long endTime) { + this.endTime = endTime; + + // 获取当前时间(秒) + long currentTime = System.currentTimeMillis() / 1000; + this.startTime = endTime - currentTime; + + if (this.startTime <= 0) { + // 时间错误不进行倒计时 + showBigTimeLabel("0"); + return; + } + + stopTimer(); + startTimer(); + } + + private void startTimer() { + timerRunnable = new Runnable() { + @Override + public void run() { + startTime--; + + long min = (startTime % 3600) / 60; + long second = startTime % 60; + + if (startTime <= 30) { + // 最后30秒显示大数字 + showBigTimeLabel(String.valueOf(startTime)); + + if (startTime == 30) { + if (delegate != null) { + delegate.timeDownStartAnimation(); + } + } else { + if (delegate != null) { + delegate.timeDownUpdateAnimationWithTime(startTime); + } + } + + // 弹性动画 + performScaleAnimation(); + } else { + // 正常倒计时显示 + showNormalTime(String.format("%02d:%02d", min, second)); + + if (delegate != null) { + delegate.timeDownStopAnimation(); + } + } + + if (startTime <= 0) { + stopTimer(); + showBigTimeLabel("0"); + + if (delegate != null) { + delegate.timeDownDidFinished(); + delegate.timeDownStopAnimation(); + } + } else { + // 继续下一次计时 + timerHandler.postDelayed(this, 1000); + } + } + }; + + // 立即开始第一次执行 + timerHandler.post(timerRunnable); + } + + public void stopTimer() { + if (timerHandler != null && timerRunnable != null) { + timerHandler.removeCallbacks(timerRunnable); + timerRunnable = null; + } + } + + private void showBigTimeLabel(String text) { + bigTimeLabel.setVisibility(View.VISIBLE); + timeLabel.setVisibility(View.GONE); + titleLabel.setVisibility(View.GONE); + bigTimeLabel.setText(text); + } + + private void showNormalTime(String timeText) { + bigTimeLabel.setVisibility(View.GONE); + timeLabel.setVisibility(View.VISIBLE); + titleLabel.setVisibility(View.VISIBLE); + timeLabel.setText(timeText); + } + + private void performScaleAnimation() { + ScaleAnimation scaleAnimation = new ScaleAnimation( + 1.0f, 1.5f, // X轴从1.0缩放到1.5 + 1.0f, 1.5f, // Y轴从1.0缩放到1.5 + ScaleAnimation.RELATIVE_TO_SELF, 0.5f, // 缩放中心X + ScaleAnimation.RELATIVE_TO_SELF, 0.5f // 缩放中心Y + ); + + scaleAnimation.setDuration(600); + scaleAnimation.setFillAfter(false); + + bigTimeLabel.startAnimation(scaleAnimation); + } + + public void reset() { + stopTimer(); + showNormalTime("00:00"); + bigTimeLabel.setVisibility(View.GONE); + timeLabel.setVisibility(View.VISIBLE); + titleLabel.setVisibility(View.VISIBLE); + } + + // 辅助方法:dp 转 px + private int dpToPx(int dp) { + float density = getResources().getDisplayMetrics().density; + return Math.round(dp * density); + } + + // Getter 和 Setter 方法 + public void setDelegate(TimeDownDelegate delegate) { + this.delegate = delegate; + } + + public long getEndTime() { + return endTime; + } + + public long getStartTime() { + return startTime; + } + + public TextView getTitleLabel() { + return titleLabel; + } + + public TextView getTimeLabel() { + return timeLabel; + } + + public TextView getBigTimeLabel() { + return bigTimeLabel; + } + + public ImageView getBgImageView() { + return bgImageView; + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + stopTimer(); + } +} \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/view/RichTextView.kt b/moduleUtil/src/main/java/com/xscm/moduleutil/view/RichTextView.kt new file mode 100644 index 00000000..b9165e11 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/view/RichTextView.kt @@ -0,0 +1,207 @@ +package com.xscm.moduleutil.view + +import android.content.Context +import android.graphics.Color +import android.graphics.Typeface +import android.text.Html +import android.text.Spannable +import android.text.SpannableStringBuilder +import android.text.TextPaint +import android.text.method.LinkMovementMethod +import android.text.style.* +import android.util.Log +import android.util.AttributeSet +import android.view.View +import android.widget.TextView +import androidx.annotation.ColorInt +import androidx.annotation.StringRes + +/** + * 封装了富文本展示功能的自定义TextView + * 支持HTML格式、自定义样式文本和点击事件 + */ +class RichTextView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : androidx.appcompat.widget.AppCompatTextView(context, attrs, defStyleAttr) { + + // 富文本构建器 + private val spannableBuilder = SpannableStringBuilder() + + init { + // 初始化配置 + movementMethod = LinkMovementMethod.getInstance() + highlightColor = Color.TRANSPARENT // 移除点击高亮 + } + + /** + * 设置HTML格式的富文本 + */ + fun setHtmlText(html: String) { + val spanned = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + Html.fromHtml(html, Html.FROM_HTML_MODE_COMPACT) + } else { + @Suppress("DEPRECATION") + Html.fromHtml(html) + } + text = spanned + } + + /** + * 从资源文件设置HTML富文本 + */ + fun setHtmlText(@StringRes resId: Int) { + setHtmlText(context.getString(resId)) + } + + /** + * 开始构建富文本 + */ + fun beginBuild(): RichTextBuilder { + spannableBuilder.clear() + return RichTextBuilder() + } + + /** + * 富文本构建器 + * 支持链式调用添加各种样式的文本 + */ + inner class RichTextBuilder { + + /** + * 添加普通文本 + */ + fun addText(text: String): RichTextBuilder { + spannableBuilder.append(text) + return this + } + + /** + * 添加普通文本(从资源文件) + */ + fun addText(@StringRes resId: Int): RichTextBuilder { + return addText(context.getString(resId)) + } + + /** + * 添加加粗文本 + */ + fun addBoldText(text: String): RichTextBuilder { + return addStyledText(text, StyleSpan(Typeface.BOLD)) + } + + /** + * 添加斜体文本 + */ + fun addItalicText(text: String): RichTextBuilder { + return addStyledText(text, StyleSpan(Typeface.ITALIC)) + } + + /** + * 添加下划线文本 + */ + fun addUnderlineText(text: String): RichTextBuilder { + return addStyledText(text, UnderlineSpan()) + } + + /** + * 添加删除线文本 + */ + fun addStrikethroughText(text: String): RichTextBuilder { + return addStyledText(text, StrikethroughSpan()) + } + + /** + * 添加指定颜色的文本 + */ + fun addColoredText(text: String, @ColorInt color: Int): RichTextBuilder { + return addStyledText(text, ForegroundColorSpan(color)) + } + + /** + * 添加指定背景色的文本 + */ + fun addBackgroundColoredText(text: String, @ColorInt color: Int): RichTextBuilder { + return addStyledText(text, BackgroundColorSpan(color)) + } + + /** + * 添加指定大小的文本 + * @param proportion 相对于默认大小的比例 + */ + fun addSizedText(text: String, proportion: Float): RichTextBuilder { + return addStyledText(text, RelativeSizeSpan(proportion)) + } + + /** + * 添加带有点击事件的文本 + */ + fun addClickableText( + text: String, + @ColorInt linkColor: Int = Color.BLUE, + isUnderline: Boolean = false, + onClick: () -> Unit + ): RichTextBuilder { + val start = spannableBuilder.length + spannableBuilder.append(text) + val end = spannableBuilder.length + + val clickableSpan = object : ClickableSpan() { + override fun onClick(widget: View) { + onClick.invoke() + } + + override fun updateDrawState(ds: TextPaint) { + super.updateDrawState(ds) + ds.color = linkColor + ds.isUnderlineText = isUnderline + } + } + + spannableBuilder.setSpan( + clickableSpan, + start, + end, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + + return this + } + + /** + * 添加换行 + */ + fun addLineBreak(): RichTextBuilder { + spannableBuilder.append("\n") + return this + } + + /** + * 添加自定义样式的文本 + */ + fun addStyledText(text: String, vararg spans: Any): RichTextBuilder { + val start = spannableBuilder.length + spannableBuilder.append(text) + val end = spannableBuilder.length + + spans.forEach { span -> + spannableBuilder.setSpan( + span, + start, + end, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + } + + return this + } + + /** + * 完成构建并应用到TextView + */ + fun build() { + text = spannableBuilder + } + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/CenterScrollHelper.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/CenterScrollHelper.java new file mode 100644 index 00000000..198c749e --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/CenterScrollHelper.java @@ -0,0 +1,271 @@ +package com.xscm.moduleutil.widget; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.RecyclerView; + +/** + * @Author lxj$ + * @Time $ 2025-9-4 21:04:34$ + * @Description 自定义滚动辅助类$ + */ +public class CenterScrollHelper { + private RecyclerView recyclerView; + + public CenterScrollHelper(RecyclerView recyclerView) { + this.recyclerView = recyclerView; + } + + /** + * 循环滚动指定圈数后停在目标位置 + * @param targetPosition 目标位置 + * @param circles 滚动圈数 + * @param durationPerItem 每个item滚动的持续时间(控制速度) + * @param adapterSize 适配器总大小 + */ + public void scrollWithCircles(int targetPosition, int circles, int durationPerItem, int adapterSize) { + scrollWithCircles(targetPosition, circles, durationPerItem, adapterSize, null); + } + + /** + * 循环滚动指定圈数后停在目标位置(带回调) + * @param targetPosition 目标位置 + * @param circles 滚动圈数 + * @param durationPerItem 每个item滚动的持续时间(控制速度) + * @param adapterSize 适配器总大小 + * @param onComplete 滚动完成回调 + */ + public void scrollWithCircles(int targetPosition, int circles, int durationPerItem, + int adapterSize, Runnable onComplete) { + if (recyclerView.getLayoutManager() == null) { + if (onComplete != null) onComplete.run(); + return; + } + + // 计算总滚动位置(多圈+目标位置) + int totalItems = circles * adapterSize + targetPosition; + + + // 使用LinearSmoothScroller进行平滑滚动 + LinearSmoothScroller smoothScroller = new LinearSmoothScroller(recyclerView.getContext()) { + private static final float ACCELERATION = 0.5f; // 加速度 + private static final float DECELERATION = 0.8f; // 减速度 + + @Override + protected int calculateTimeForScrolling(int dx) { + // 使用缓动函数计算时间,实现从慢到快再到慢的效果 +// return calculateEasingTime(dx, durationPerItem); + +// // 简单线性时间计算,确保滚动速度一致 +// int screenWidth = recyclerView.getWidth(); +// if (screenWidth <= 0) { +// return durationPerItem * 3; +// } +// int itemWidth = screenWidth / 3; +// int items = Math.max(1, dx / itemWidth); +// return durationPerItem * items; + + // 使用缓动函数计算时间,实现从慢到快再到慢的效果 + return calculateEasingTime(dx, durationPerItem); + } + + @Override + protected void onStop() { + super.onStop(); + // 滚动停止后确保目标位置居中 +// scrollToCenter(targetPosition); + // 执行完成回调 + if (onComplete != null) { + recyclerView.post(onComplete); + } + } + }; + + smoothScroller.setTargetPosition(totalItems); + recyclerView.getLayoutManager().startSmoothScroll(smoothScroller); + } + + // 在 CenterScrollHelper 类中添加 + public void reset() { + // 清理可能存在的回调或状态 + if (recyclerView != null) { + recyclerView.stopScroll(); + recyclerView.getHandler().removeCallbacksAndMessages(null); + } + } + + /** + * 使用缓动函数计算滚动时间,实现加速减速效果 + * @param dx 滚动距离 + * @param baseDurationPerItem 基础时间 + * @return 计算后的时间 + */ + private int calculateEasingTime(int dx, int baseDurationPerItem) { + if (dx <= 0) return 0; + + // 获取屏幕宽度作为参考 + int screenWidth = recyclerView.getWidth(); + if (screenWidth <= 0) { + return baseDurationPerItem * 3; // 默认值 + } + + // 计算item宽度(假设每屏3个item) + int itemWidth = screenWidth / 3; + // 计算滚动的item数量 + int items = Math.max(1, dx / itemWidth); + + // 使用easeInOutQuad缓动函数实现先慢中快后慢的效果 + double progress = Math.min(1.0, (double) items / 100); // 假设100个item为完整过程 + + // easeInOutQuad缓动函数 + double easeProgress; + if (progress < 0.5) { + easeProgress = 2 * progress * progress; // 先慢后快 + } else { + easeProgress = 1 - Math.pow(-2 * progress + 2, 2) / 2; // 后慢 + } + + // 计算时间:开始慢(500ms),后来快(50ms) + int minDuration = 1000; // 最快速度 + int maxDuration = 2000; // 最慢速度 + int calculatedTime = (int) (maxDuration - (maxDuration - minDuration) * easeProgress); + + return Math.max(minDuration, calculatedTime); + } + + /** + * 将指定位置的item精确居中显示 + * @param position 需要居中的位置(在循环列表中的实际位置) + * @param originalSize 原始数据大小 + */ + public void scrollToCenter(int position, int originalSize) { + if (recyclerView.getLayoutManager() == null) return; + + int screenWidth = recyclerView.getWidth(); + if (screenWidth <= 0) return; + + // 计算item宽度(假设每个item等宽) + int itemWidth = screenWidth / 3; // 每屏显示3个item + + // 计算使item居中需要滚动的总距离 + int targetScrollX = position * itemWidth - (screenWidth - itemWidth) / 2; + + // 获取当前滚动位置 + int currentScrollX = recyclerView.computeHorizontalScrollOffset(); + + // 计算需要滚动的距离 + int scrollDistance = targetScrollX - currentScrollX; + + // 执行滚动 + recyclerView.smoothScrollBy(scrollDistance, 0); + } + + /** + * 将指定位置的item精确居中显示(简化版) + * @param position 需要居中的位置 + */ + public void scrollToCenter(int position) { + if (recyclerView.getLayoutManager() == null) return; + + int screenWidth = recyclerView.getWidth(); + if (screenWidth <= 0) return; + + // 计算item宽度 + int itemWidth = screenWidth / 3; + + // 计算目标位置的左边缘 + int targetLeft = position * itemWidth; + + // 计算使item居中需要滚动到的位置 + int targetScrollX = targetLeft - (screenWidth - itemWidth) / 2; + + // 获取当前滚动位置 + int currentScrollX = recyclerView.computeHorizontalScrollOffset(); + + // 计算需要滚动的距离 + int scrollDistance = targetScrollX - currentScrollX; + + // 如果距离很小,就不需要滚动了 + if (Math.abs(scrollDistance) > 5) { + // 执行滚动 + recyclerView.smoothScrollBy(scrollDistance, 0); + } + } + /** + * 将指定位置的item居中显示(支持循环) + */ + public void centerItem(int targetPosition, int adapterSize) { + if (recyclerView.getLayoutManager() == null) return; + + LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); + int screenWidth = recyclerView.getWidth(); + if (screenWidth <= 0) return; + + int itemWidth = screenWidth / 3; // 每个item占屏幕1/3 + + // 计算需要滚动的距离使item居中 + // 这里需要根据实际的item宽度和屏幕宽度来计算居中位置 + int targetScrollX = targetPosition * itemWidth - (screenWidth - itemWidth) / 2; + int currentScrollX = recyclerView.computeHorizontalScrollOffset(); + int scrollDistance = targetScrollX - currentScrollX; + + // 使用smoothScrollBy确保平滑滚动到居中位置 + recyclerView.smoothScrollBy(scrollDistance, 0); + } + /** + * 使用更复杂的缓动函数计算滚动时间 + * @param dx 滚动距离 + * @param baseDurationPerItem 基础时间 + * @return 计算后的时间 + */ + private int calculateAdvancedEasingTime(int dx, int baseDurationPerItem) { + if (dx <= 0) return 0; + + int screenWidth = recyclerView.getWidth(); + if (screenWidth <= 0) { + return baseDurationPerItem * 3; + } + + int itemWidth = screenWidth / 3; + int totalItems = dx / itemWidth; + + // 分段处理:开始慢,中间快,结束慢 + int totalTime = 0; + for (int i = 0; i < totalItems; i++) { + // 计算当前位置的进度 (0-1) + double progress = (double) i / Math.max(1, totalItems); + + // 使用贝塞尔缓动函数:慢-快-慢 + double easedProgress = bezierEasing(progress, 0.25, 0.1, 0.25, 1.0); + + // 根据进度调整时间 + int minTime = 30; // 最快时间 + int maxTime = baseDurationPerItem * 2; // 最慢时间 + int itemTime = (int) (maxTime - (maxTime - minTime) * easedProgress); + + totalTime += itemTime; + } + + return Math.max(100, totalTime); // 至少100ms + } + + /** + * 贝塞尔缓动函数 + * @param t 时间进度 (0-1) + * @param x1 控制点1 x + * @param y1 控制点1 y + * @param x2 控制点2 x + * @param y2 控制点2 y + * @return 缓动后的值 + */ + private double bezierEasing(double t, double x1, double y1, double x2, double y2) { + // 简化的贝塞尔曲线计算 + // 这里使用一个近似算法 + double a = 1 - t; + return 3 * a * a * t * y1 + 3 * a * t * t * y2 + t * t * t; + } + + +} + + diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/DropHourlView.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/DropHourlView.java new file mode 100644 index 00000000..e290cf27 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/DropHourlView.java @@ -0,0 +1,285 @@ +package com.xscm.moduleutil.widget; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.os.Build; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewAnimationUtils; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import com.blankj.utilcode.util.ScreenUtils; +import com.xscm.moduleutil.utils.BarUtils; + +/** + * 描述:小时榜的显示视图 + */ +public class DropHourlView extends LinearLayout { + + private int rightMargin = 0; + private float lastX, lastY; + private int screenWidth; + private int screenHeight; // 添加屏幕高度变量 + + public DropHourlView(Context context) { + super(context); + init(); + } + + public DropHourlView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public DropHourlView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + + void init() { + // 初始化屏幕尺寸 + screenWidth = ScreenUtils.getScreenWidth(); + screenHeight = ScreenUtils.getScreenHeight(); + + post(new Runnable() { + @Override + public void run() { + //设置初始位置 + int sh = ScreenUtils.getScreenHeight(); + int sw = ScreenUtils.getScreenWidth()-200; +// setBackgroundResource(R.drawable.bg_home_drop_view); + int y = (int) (0.5f * sh) - getHeight(); + // 确保Y坐标不会超出屏幕范围 + y = Math.max(0, Math.min(y, sh - getHeight())); + int x = sw - getWidth(); + setTranslationX(x); + setTranslationY(y); + } + }); + + updateSize(); + mStatusBarHeight = BarUtils.getStatusBarHeight(); + } + /** + * 更新屏幕尺寸信息 + */ + protected void updateSize() { + ViewGroup viewGroup = (ViewGroup) getParent(); + if (viewGroup != null) { + mScreenWidth = viewGroup.getWidth(); + mScreenHeight = viewGroup.getHeight(); + } else { + // 如果父视图为空,使用屏幕的实际宽度和高度 + mScreenWidth = getResources().getDisplayMetrics().widthPixels; + mScreenHeight = getResources().getDisplayMetrics().heightPixels; + } + } + + boolean starDrap = false; + float X1; + float X2; + float Y1; + float Y2; + // 记录视图初始位置 + private float originalX; + private float originalY; + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + if (starDrap) return true; + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + X1 = event.getRawX(); + Y1 = event.getRawY(); + // 记录视图当前位置 + originalX = getTranslationX(); + originalY = getTranslationY(); + break; + + case MotionEvent.ACTION_MOVE: + X2 = event.getRawX(); + Y2 = event.getRawY(); + Action(X1, X2, Y1, Y2); + break; + + + } + return starDrap; + } + + String TAG = "DropHourlView"; + + public boolean Action(float X1, float X2, float Y1, float Y2) { + float ComparedX = X2 - X1;//第二次的X坐标的位置减去第一次X坐标的位置,代表X坐标上的变化情况 + float ComparedY = Y2 - Y1;//同理 + //当X坐标的变化量的绝对值大于Y坐标的变化量的绝对值,以X坐标的变化情况作为判断依据 + //上下左右的判断,都在一条直线上,但手指的操作不可能划直线,所有选择变化量大的方向上的量 + //作为判断依据 + if (Math.abs(ComparedX) > 30 || Math.abs(ComparedY) > 30) { + Log.i(TAG, "Action: 拖动"); + starDrap = true; +// setBackgroundResource(R.drawable.bg_home_drop_view); + return true; + } else { + starDrap = false; + return false; + } + } + private float mOriginalRawX; + private float mOriginalRawY; + private float mOriginalX; + private float mOriginalY; + protected int mScreenWidth; + private int mScreenHeight; + private int mStatusBarHeight; + + private void updateViewPosition(MotionEvent event) { + // 计算新的Y位置 + float desY = mOriginalY + event.getRawY() - mOriginalRawY; + + // 限制Y位置不超出屏幕边界 + if (desY < mStatusBarHeight) { + desY = mStatusBarHeight; + } + if (desY > mScreenHeight - getHeight()) { + desY = mScreenHeight - getHeight(); + } + + // 计算新的X位置 + float desX = mOriginalX + event.getRawX() - mOriginalRawX; + + // 限制X位置不超出屏幕边界 + if (desX < 0) { + desX = 0; + } + if (desX > mScreenWidth - getWidth()) { + desX = mScreenWidth - getWidth(); + } + + // 设置视图的新位置 + setX(desX); + setY(desY); + } + private void changeOriginalTouchParams(MotionEvent event) { + mOriginalX = getX();//getX()相对于控件X坐标的距离 + mOriginalY = getY(); + mOriginalRawX = event.getRawX();//getRawX()指控件在屏幕上的X坐标 + mOriginalRawY = event.getRawY(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event == null) { + return false; + } + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + changeOriginalTouchParams(event); + updateSize(); // 添加这行确保尺寸是最新的 + // ... 其他现有代码 ... + + break; + case MotionEvent.ACTION_MOVE: + + updateViewPosition(event); // 使用更新后的带边界检查的方法 + +// setBackgroundResource(R.drawable.bg_home_drop_view); + // 使用屏幕绝对坐标计算新位置 +// float newX = originalX + (event.getRawX() - X1); +// float newY = originalY + (event.getRawY() - Y1); +// +// // 限制X和Y坐标在屏幕范围内 +// newX = Math.max(0, Math.min(newX, screenWidth - getWidth())); +// newY = Math.max(0, Math.min(newY, screenHeight - getHeight())); +// +// setTranslationX(newX); +// setTranslationY(newY); +// X2 = event.getRawX(); + break; + case MotionEvent.ACTION_UP: + starDrap = false; + int sw = ScreenUtils.getScreenWidth(); + Log.i(TAG, "onTouchEvent: " + sw + "," + X2); + boolean isR = getTranslationX() + getWidth() / 2 >= sw / 2;//贴边方向 + + // 获取当前Y坐标 + float currentY = getTranslationY(); + + // 创建X轴和Y轴的动画 + ObjectAnimator animX = ObjectAnimator.ofFloat(this, "translationX", isR ? sw - getWidth() : 0f).setDuration(200); + // Y轴保持当前位置,但确保在屏幕范围内 + currentY = Math.max(0, Math.min(currentY, screenHeight - getHeight())); + ObjectAnimator animY = ObjectAnimator.ofFloat(this, "translationY", currentY).setDuration(200); + + animX.start(); + animY.start(); + + break; + + } + + return true; + } + + + public void doRevealAnimation(View mPuppet, boolean flag) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + int[] vLocation = new int[2]; + getLocationInWindow(vLocation); + int centerX = vLocation[0] + getMeasuredWidth() / 2; + int centerY = vLocation[1] + getMeasuredHeight() / 2; + + int height = ScreenUtils.getScreenHeight(); + int width = ScreenUtils.getScreenWidth(); + int maxRradius = (int) Math.hypot(height, width); + Log.e("hei", maxRradius + ""); + + if (flag) { + mPuppet.setVisibility(VISIBLE); + Animator animator = ViewAnimationUtils.createCircularReveal(mPuppet, centerX, centerY, maxRradius, 0); + animator.setDuration(600); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mPuppet.setVisibility(View.GONE); + } + }); + animator.start(); + flag = false; + } else { + Animator animator = ViewAnimationUtils.createCircularReveal(mPuppet, centerX, centerY, 0, maxRradius); + animator.setDuration(1000); + animator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + mPuppet.setVisibility(View.VISIBLE); + } + + @Override + public void onAnimationEnd(Animator animation) { + } + + @Override + public void onAnimationCancel(Animator animation) { + + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + animator.start(); + flag = true; + } + } + } + + +} \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/DropRedView.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/DropRedView.java new file mode 100644 index 00000000..30117f0e --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/DropRedView.java @@ -0,0 +1,286 @@ +package com.xscm.moduleutil.widget; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.os.Build; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewAnimationUtils; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import com.blankj.utilcode.util.ScreenUtils; +import com.xscm.moduleutil.utils.BarUtils; + +/** + * 这是红包入口悬浮框 + */ +public class DropRedView extends LinearLayout { + + private int rightMargin = 0; + private float lastX, lastY; + private int screenWidth; + private int screenHeight; // 添加屏幕高度变量 + + public DropRedView(Context context) { + super(context); + init(); + } + + public DropRedView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public DropRedView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + + void init() { + // 初始化屏幕尺寸 + screenWidth = ScreenUtils.getScreenWidth(); + screenHeight = ScreenUtils.getScreenHeight(); + + post(new Runnable() { + @Override + public void run() { + //设置初始位置 + int sh = ScreenUtils.getScreenHeight(); + int sw = ScreenUtils.getScreenWidth(); +// setBackgroundResource(R.drawable.bg_home_drop_view); + int y = (int) (0.5f * sh) - getHeight(); + // 确保Y坐标不会超出屏幕范围 + y = Math.max(0, Math.min(y, sh - getHeight())); +// int x = sw - getWidth();//这是靠右边展示的 + int x=20 ;//这里这只一小的数值,就是靠左展示的 + setTranslationX(x); + setTranslationY(y); + } + }); + + updateSize(); + mStatusBarHeight = BarUtils.getStatusBarHeight(); + } + /** + * 更新屏幕尺寸信息 + */ + protected void updateSize() { + ViewGroup viewGroup = (ViewGroup) getParent(); + if (viewGroup != null) { + mScreenWidth = viewGroup.getWidth(); + mScreenHeight = viewGroup.getHeight(); + } else { + // 如果父视图为空,使用屏幕的实际宽度和高度 + mScreenWidth = getResources().getDisplayMetrics().widthPixels; + mScreenHeight = getResources().getDisplayMetrics().heightPixels; + } + } + + boolean starDrap = false; + float X1; + float X2; + float Y1; + float Y2; + // 记录视图初始位置 + private float originalX; + private float originalY; + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + if (starDrap) return true; + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + X1 = event.getRawX(); + Y1 = event.getRawY(); + // 记录视图当前位置 + originalX = getTranslationX(); + originalY = getTranslationY(); + break; + + case MotionEvent.ACTION_MOVE: + X2 = event.getRawX(); + Y2 = event.getRawY(); + Action(X1, X2, Y1, Y2); + break; + + + } + return starDrap; + } + + String TAG = "DropHourlView"; + + public boolean Action(float X1, float X2, float Y1, float Y2) { + float ComparedX = X2 - X1;//第二次的X坐标的位置减去第一次X坐标的位置,代表X坐标上的变化情况 + float ComparedY = Y2 - Y1;//同理 + //当X坐标的变化量的绝对值大于Y坐标的变化量的绝对值,以X坐标的变化情况作为判断依据 + //上下左右的判断,都在一条直线上,但手指的操作不可能划直线,所有选择变化量大的方向上的量 + //作为判断依据 + if (Math.abs(ComparedX) > 30 || Math.abs(ComparedY) > 30) { + Log.i(TAG, "Action: 拖动"); + starDrap = true; +// setBackgroundResource(R.drawable.bg_home_drop_view); + return true; + } else { + starDrap = false; + return false; + } + } + private float mOriginalRawX; + private float mOriginalRawY; + private float mOriginalX; + private float mOriginalY; + protected int mScreenWidth; + private int mScreenHeight; + private int mStatusBarHeight; + + private void updateViewPosition(MotionEvent event) { + // 计算新的Y位置 + float desY = mOriginalY + event.getRawY() - mOriginalRawY; + + // 限制Y位置不超出屏幕边界 + if (desY < mStatusBarHeight) { + desY = mStatusBarHeight; + } + if (desY > mScreenHeight - getHeight()) { + desY = mScreenHeight - getHeight(); + } + + // 计算新的X位置 + float desX = mOriginalX + event.getRawX() - mOriginalRawX; + + // 限制X位置不超出屏幕边界 + if (desX < 0) { + desX = 0; + } + if (desX > mScreenWidth - getWidth()) { + desX = mScreenWidth - getWidth(); + } + + // 设置视图的新位置 + setX(desX); + setY(desY); + } + private void changeOriginalTouchParams(MotionEvent event) { + mOriginalX = getX();//getX()相对于控件X坐标的距离 + mOriginalY = getY(); + mOriginalRawX = event.getRawX();//getRawX()指控件在屏幕上的X坐标 + mOriginalRawY = event.getRawY(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event == null) { + return false; + } + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + changeOriginalTouchParams(event); + updateSize(); // 添加这行确保尺寸是最新的 + // ... 其他现有代码 ... + + break; + case MotionEvent.ACTION_MOVE: + + updateViewPosition(event); // 使用更新后的带边界检查的方法 + +// setBackgroundResource(R.drawable.bg_home_drop_view); + // 使用屏幕绝对坐标计算新位置 +// float newX = originalX + (event.getRawX() - X1); +// float newY = originalY + (event.getRawY() - Y1); +// +// // 限制X和Y坐标在屏幕范围内 +// newX = Math.max(0, Math.min(newX, screenWidth - getWidth())); +// newY = Math.max(0, Math.min(newY, screenHeight - getHeight())); +// +// setTranslationX(newX); +// setTranslationY(newY); +// X2 = event.getRawX(); + break; + case MotionEvent.ACTION_UP: + starDrap = false; + int sw = ScreenUtils.getScreenWidth(); + Log.i(TAG, "onTouchEvent: " + sw + "," + X2); + boolean isR = getTranslationX() + getWidth() / 2 >= sw / 2;//贴边方向 + + // 获取当前Y坐标 + float currentY = getTranslationY(); + + // 创建X轴和Y轴的动画 + ObjectAnimator animX = ObjectAnimator.ofFloat(this, "translationX", isR ? sw - getWidth() : 0f).setDuration(200); + // Y轴保持当前位置,但确保在屏幕范围内 + currentY = Math.max(0, Math.min(currentY, screenHeight - getHeight())); + ObjectAnimator animY = ObjectAnimator.ofFloat(this, "translationY", currentY).setDuration(200); + + animX.start(); + animY.start(); + + break; + + } + + return true; + } + + + public void doRevealAnimation(View mPuppet, boolean flag) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + int[] vLocation = new int[2]; + getLocationInWindow(vLocation); + int centerX = vLocation[0] + getMeasuredWidth() / 2; + int centerY = vLocation[1] + getMeasuredHeight() / 2; + + int height = ScreenUtils.getScreenHeight(); + int width = ScreenUtils.getScreenWidth(); + int maxRradius = (int) Math.hypot(height, width); + Log.e("hei", maxRradius + ""); + + if (flag) { + mPuppet.setVisibility(VISIBLE); + Animator animator = ViewAnimationUtils.createCircularReveal(mPuppet, centerX, centerY, maxRradius, 0); + animator.setDuration(600); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mPuppet.setVisibility(View.GONE); + } + }); + animator.start(); + flag = false; + } else { + Animator animator = ViewAnimationUtils.createCircularReveal(mPuppet, centerX, centerY, 0, maxRradius); + animator.setDuration(1000); + animator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + mPuppet.setVisibility(View.VISIBLE); + } + + @Override + public void onAnimationEnd(Animator animation) { + } + + @Override + public void onAnimationCancel(Animator animation) { + + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + animator.start(); + flag = true; + } + } + } + + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/DropViewRoom.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/DropViewRoom.java new file mode 100644 index 00000000..2dd470b3 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/DropViewRoom.java @@ -0,0 +1,184 @@ +package com.xscm.moduleutil.widget; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.os.Build; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewAnimationUtils; +import android.widget.LinearLayout; + +import com.blankj.utilcode.util.ScreenUtils; + +public class DropViewRoom extends LinearLayout { + + private int rightMargin = 0; + private float lastX, lastY; + private int screenWidth; + + public DropViewRoom(Context context) { + super(context); + init(); + } + + public DropViewRoom(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public DropViewRoom(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + + void init() { + + post(new Runnable() { + @Override + public void run() { + //设置初始位置 + int sh = ScreenUtils.getScreenHeight(); + int sw = ScreenUtils.getScreenWidth()-100; +// setBackgroundResource(R.drawable.bg_home_drop_view); + int y = (int) (0.5f * sh) - getHeight(); + int x = sw - getWidth(); + setTranslationX(x); + setTranslationY(y); + } + }); + } + + + boolean starDrap = false; + float X1; + float X2; + float Y1; + float Y2; + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + if (starDrap) return true; + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + X1 = event.getX(); + Y1 = event.getY(); + break; + + case MotionEvent.ACTION_MOVE: + X2 = event.getX();//当手指抬起时,再次获取屏幕位置的X值 + Y2 = event.getY();//同理 + Action(X1, X2, Y1, Y2); + break; + + + } + return starDrap; + } + + String TAG = "DropView"; + + public boolean Action(float X1, float X2, float Y1, float Y2) { + float ComparedX = X2 - X1;//第二次的X坐标的位置减去第一次X坐标的位置,代表X坐标上的变化情况 + float ComparedY = Y2 - Y1;//同理 + //当X坐标的变化量的绝对值大于Y坐标的变化量的绝对值,以X坐标的变化情况作为判断依据 + //上下左右的判断,都在一条直线上,但手指的操作不可能划直线,所有选择变化量大的方向上的量 + //作为判断依据 + if (Math.abs(ComparedX) > 30 || Math.abs(ComparedY) > 30) { + Log.i(TAG, "Action: 拖动"); + starDrap = true; +// setBackgroundResource(R.drawable.bg_home_drop_view); + return true; + } else { + starDrap = false; + return false; + } + } + + + @Override + public boolean onTouchEvent(MotionEvent event) { + switch (event.getAction()) { + + case MotionEvent.ACTION_MOVE: +// setBackgroundResource(R.drawable.bg_home_drop_view); + setTranslationX(getX() + (event.getX() - X1)); + setTranslationY(getY() + (event.getY() - Y1)); + X2 = event.getX(); + break; + case MotionEvent.ACTION_UP: + starDrap = false; + int sw = ScreenUtils.getScreenWidth(); + Log.i(TAG, "onTouchEvent: " + sw + "," + X2); + boolean isR = getTranslationX() + getWidth() / 2 >= sw / 2;//贴边方向 + ObjectAnimator anim = ObjectAnimator.ofFloat(this, "translationX", isR ? sw - getWidth()+10 : 0f).setDuration(200); + anim.start(); + + break; + + } + + return true; + } + + + public void doRevealAnimation(View mPuppet, boolean flag) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + int[] vLocation = new int[2]; + getLocationInWindow(vLocation); + int centerX = vLocation[0] + getMeasuredWidth() / 2; + int centerY = vLocation[1] + getMeasuredHeight() / 2; + + int height = ScreenUtils.getScreenHeight(); + int width = ScreenUtils.getScreenWidth(); + int maxRradius = (int) Math.hypot(height, width); + Log.e("hei", maxRradius + ""); + + if (flag) { + mPuppet.setVisibility(VISIBLE); + Animator animator = ViewAnimationUtils.createCircularReveal(mPuppet, centerX, centerY, maxRradius, 0); + animator.setDuration(600); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mPuppet.setVisibility(View.GONE); + } + }); + animator.start(); + flag = false; + } else { + Animator animator = ViewAnimationUtils.createCircularReveal(mPuppet, centerX, centerY, 0, maxRradius); + animator.setDuration(1000); + animator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + mPuppet.setVisibility(View.VISIBLE); + } + + @Override + public void onAnimationEnd(Animator animation) { + } + + @Override + public void onAnimationCancel(Animator animation) { + + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + animator.start(); + flag = true; + } + } + } + + +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/EqualSpaceItemDecoration.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/EqualSpaceItemDecoration.java new file mode 100644 index 00000000..234425ec --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/EqualSpaceItemDecoration.java @@ -0,0 +1,51 @@ +package com.xscm.moduleutil.widget; + +import android.graphics.Canvas; +import android.graphics.Rect; +import android.view.View; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.RecyclerView; + +/** + * @Author lxj$ + * @Time $ 2025-9-4 20:32:52$ + * @Description 自定义的,让在item平分屏幕宽度$ + */ +public class EqualSpaceItemDecoration extends RecyclerView.ItemDecoration { + private int spanCount; + private int spacing; + + public EqualSpaceItemDecoration(int spanCount, int spacing) { + this.spanCount = spanCount; + this.spacing = spacing; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + int position = parent.getChildAdapterPosition(view); + + // 设置间距 + outRect.left = spacing / 2; + outRect.right = spacing / 2; + } + + @Override + public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { + super.onDraw(c, parent, state); + + // 确保每个item宽度为屏幕的1/3 + int childCount = parent.getChildCount(); + int screenWidth = parent.getWidth(); + int itemWidth = screenWidth / spanCount; + + for (int i = 0; i < childCount; i++) { + View child = parent.getChildAt(i); + ViewGroup.LayoutParams params = child.getLayoutParams(); + params.width = itemWidth; + child.setLayoutParams(params); + } + } +} + + diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/FakeNinePatchDrawable.kt b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/FakeNinePatchDrawable.kt new file mode 100644 index 00000000..d102ad51 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/FakeNinePatchDrawable.kt @@ -0,0 +1,96 @@ +package com.xscm.modulemain + +import android.graphics.* +import android.graphics.drawable.Drawable + +/** + * 这是设置图片设置拉伸区域 + */ +class FakeNinePatchDrawable( + private val bitmap: Bitmap, + // 定义拉伸区域的坐标(相对图片的百分比,范围 0~1) + private val left: Float, // 左边界(左侧不拉伸区域的宽度比例) + private val top: Float, // 上边界(上侧不拉伸区域的高度比例) + private val right: Float, // 右边界(右侧不拉伸区域的宽度比例) + private val bottom: Float // 下边界(下侧不拉伸区域的高度比例) +) : Drawable() { + + private val paint = Paint(Paint.ANTI_ALIAS_FLAG) + private val rect = Rect() // 绘制区域 + + override fun draw(canvas: Canvas) { + val bounds = bounds // 视图的实际尺寸(需要填充的区域) + val w = bitmap.width + val h = bitmap.height + + // 计算分割点(像素值) + val splitLeft = (w * left).toInt() + val splitTop = (h * top).toInt() + val splitRight = (w * right).toInt() + val splitBottom = (h * bottom).toInt() + + // 1. 绘制四个角(不拉伸) + // 左上 + rect.set(0, 0, splitLeft, splitTop) + canvas.drawBitmap(bitmap, Rect(0, 0, splitLeft, splitTop), rect, paint) + // 右上 + rect.set(bounds.width() - (w - splitRight), 0, bounds.width(), splitTop) + canvas.drawBitmap(bitmap, Rect(splitRight, 0, w, splitTop), rect, paint) + // 左下 + rect.set(0, bounds.height() - (h - splitBottom), splitLeft, bounds.height()) + canvas.drawBitmap(bitmap, Rect(0, splitBottom, splitLeft, h), rect, paint) + // 右下 + rect.set( + bounds.width() - (w - splitRight), + bounds.height() - (h - splitBottom), + bounds.width(), + bounds.height() + ) + canvas.drawBitmap(bitmap, Rect(splitRight, splitBottom, w, h), rect, paint) + + // 2. 绘制四条边(单向拉伸) + // 上边(水平拉伸) + rect.set(splitLeft, 0, bounds.width() - (w - splitRight), splitTop) + canvas.drawBitmap(bitmap, Rect(splitLeft, 0, splitRight, splitTop), rect, paint) + // 下边(水平拉伸) + rect.set( + splitLeft, + bounds.height() - (h - splitBottom), + bounds.width() - (w - splitRight), + bounds.height() + ) + canvas.drawBitmap(bitmap, Rect(splitLeft, splitBottom, splitRight, h), rect, paint) + // 左边(垂直拉伸) + rect.set(0, splitTop, splitLeft, bounds.height() - (h - splitBottom)) + canvas.drawBitmap(bitmap, Rect(0, splitTop, splitLeft, splitBottom), rect, paint) + // 右边(垂直拉伸) + rect.set( + bounds.width() - (w - splitRight), + splitTop, + bounds.width(), + bounds.height() - (h - splitBottom) + ) + canvas.drawBitmap(bitmap, Rect(splitRight, splitTop, w, splitBottom), rect, paint) + + // 3. 绘制中间区域(双向拉伸) + rect.set( + splitLeft, + splitTop, + bounds.width() - (w - splitRight), + bounds.height() - (h - splitBottom) + ) + canvas.drawBitmap(bitmap, Rect(splitLeft, splitTop, splitRight, splitBottom), rect, paint) + } + + override fun setAlpha(alpha: Int) { + paint.alpha = alpha + invalidateSelf() + } + + override fun getOpacity(): Int = PixelFormat.TRANSLUCENT + override fun getAlpha(): Int = paint.alpha + override fun setColorFilter(colorFilter: ColorFilter?) { + paint.colorFilter = colorFilter + invalidateSelf() + } +} \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/GiftAnimView.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/GiftAnimView.java new file mode 100644 index 00000000..eecb70e2 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/GiftAnimView.java @@ -0,0 +1,513 @@ +package com.xscm.moduleutil.widget; + +import android.content.Context; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.blankj.utilcode.util.LogUtils; +import com.opensource.svgaplayer.SVGACallback; +import com.opensource.svgaplayer.SVGADrawable; +import com.opensource.svgaplayer.SVGAImageView; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; +import com.tencent.qgame.animplayer.AnimConfig; +import com.tencent.qgame.animplayer.AnimView; +import com.tencent.qgame.animplayer.inter.IAnimListener; +import com.xscm.moduleutil.bean.GiftBean; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.ReentrantLock; + +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; + +public class GiftAnimView extends FrameLayout implements GiftSvgaView.OnAnimationListener { + private AnimView playerMp4View; + private GiftSvgaView svgaView; + private GiftBean playModel; + private boolean isLoadEffect = false; + private boolean isShow = true;//是否开启特效 + private ReentrantLock lock = new ReentrantLock(); + private List giftArray = new ArrayList<>(); + public ExecutorService queue = Executors.newSingleThreadExecutor(); + private Context mContext; + private boolean isOnece; + // 添加带Context参数的构造函数 + + // 添加带Context和AttributeSet参数的构造函数(解决XML inflate问题的关键) + public GiftAnimView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + this.mContext = context; + init(); + } + + // 添加带Context、AttributeSet和 defStyleAttr 参数的构造函数(更完整的实现) + public GiftAnimView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + this.mContext = context; + init(); + } + public void setQueue(ExecutorService queue) { + this.queue = queue; + } + + public GiftAnimView(Context context) { + super(context); + this.mContext = context; + init(); + } + + private void init() { + isLoadEffect = false; + + // 初始化SVGA视图 + svgaView = new GiftSvgaView(getContext()); + addView(svgaView); + + playerMp4View = new AnimView(getContext()); + + addView(playerMp4View); + + // 设置布局参数 - 在Android中通常使用LayoutParams + LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + playerMp4View.setLoop(1); + playerMp4View.setLayoutParams(params); + playerMp4View.setAnimListener(new IAnimListener() { + @Override + public void onVideoDestroy() { + LogUtils.e("onVideoDestroy"); + } + + @Override + public void onVideoComplete() { + LogUtils.e("onVideoComplete"); + post(() -> { + if (playerMp4View!=null) { + playerMp4View.setVisibility(View.GONE); + if (isOnece){ + return; + } + // 通知播放完成 + notifyPlaybackComplete(); + loadStartSVGAPlayer(); + } + }); + + } + + @Override + public void onVideoRender(int i, @Nullable AnimConfig animConfig) { +// LogUtils.e("onVideoRender", i, animConfig); + } + + @Override + public void onVideoStart() { + LogUtils.e("onVideoStart"); + } + + @Override + public boolean onVideoConfigReady(@NonNull AnimConfig animConfig) { + LogUtils.e("onVideoConfigReady", animConfig); + return true; + } + + @Override + public void onFailed(int i, @Nullable String s) { + LogUtils.e("onFailed", s); + } + }); + svgaView.setDidFinishedDisplay(this); + svgaView.setDidStartAnimation(this); + } + + public void displayEffectView1(List stringList){ + queue.execute(new Runnable() { + @Override + public void run() { + /// 如果play_image不存在return + if (stringList == null || stringList.isEmpty()) { + return; + } + + + /// 锁住list + lock.lock(); + try { + /// 添加礼物进list + giftArray.addAll(stringList); + + /// 如果没有在加载则开始加载 + if (!isLoadEffect) { + /// 更改加载状态标记 + isLoadEffect = true; + loadStartSVGAPlayer(); + } + } finally { + /// 解锁 + lock.unlock(); + } + } + }); + } + + /// 礼物特效进来 gift为礼物实体类 + public void displayEffectView(final String gift) { + queue.execute(new Runnable() { + @Override + public void run() { + /// 如果play_image不存在return + if (gift == null || gift.isEmpty()) { + return; + } + + /// 将play_image链接转为小写 + String playImage = gift; + String pathExtension = getFileExtension(playImage).toLowerCase(); + + /// 判定礼物的后缀是否为svga或者mp4如果非这两种 则return + if (!("svga".equals(pathExtension) || "mp4".equals(pathExtension))) { + return; + } + + /// 锁住list + lock.lock(); + try { + /// 添加礼物进list + giftArray.add(gift); + + /// 如果没有在加载则开始加载 + if (!isLoadEffect) { + /// 更改加载状态标记 + isLoadEffect = true; + loadStartSVGAPlayer(); + } + } finally { + /// 解锁 + lock.unlock(); + } + } + }); + } + + public void previewEffectWith(String playImage){ + this.isOnece=true; + if (playImage.endsWith("mp4")) { + downloadAndPlay(getContext(), playImage, new DownloadCallback() { + @Override + public void onSuccess(File file) { + post(() -> { + playerMp4View.setVisibility(View.VISIBLE); + svgaView.setVisibility(View.GONE); + playerMp4View.startPlay(file); + }); + } + + @Override + public void onFailure(Exception e) { + LogUtils.e("MP4下载或播放失败: " + e.getMessage()); + // 处理失败情况,继续播放下一个 + } + }); + } else if (playImage.endsWith("svga")) { +// File file = downloadAndPlay(getContext(), playImage); + post(() -> { + playerMp4View.setVisibility(View.GONE); + svgaView.setVisibility(View.VISIBLE); + svgaView.loadSVGAPlayerWith(playImage, false); + }); + } + } + + public void openOrCloseEffectViewWith(boolean isShow) { + this.isShow = isShow; + removeSvgaQueueData(); + + playerMp4View.stopPlay(); + playerMp4View.setVisibility(View.GONE); + setVisibility(isShow ? View.VISIBLE : View.GONE); + } + + public void stopPlay() { + removeSvgaQueueData(); + + playerMp4View.stopPlay(); + playerMp4View.setVisibility(View.GONE); + } + + + private void loadStartSVGAPlayer() { + if (!isShow) { + /// isshow 为是否开启特效 如果未开启则return + return; + } + + String giftModel = null; + + /// list加锁 + lock.lock(); + try { + /// 如果list长度大于0 + if (!giftArray.isEmpty()) { + /// gift的实体类则赋值,取list中的第一个数据 + giftModel = giftArray.get(0); + /// 移除list的第一条数据 + giftArray.remove(0); + isLoadEffect = true; + } else { + isLoadEffect = false; + } + } finally { + /// 解锁 + lock.unlock(); + } + + if (isLoadEffect && giftModel != null && !TextUtils.isEmpty(giftModel)) { + String finalGiftModel = giftModel; + post(new Runnable() { + @Override + public void run() { + String playImage = finalGiftModel; + if (playImage.endsWith("mp4")) { + downloadAndPlay(getContext(), playImage, new DownloadCallback() { + @Override + public void onSuccess(File file) { + post(() -> { + playerMp4View.setVisibility(View.VISIBLE); + svgaView.setVisibility(View.GONE); + playerMp4View.startPlay(file); + }); + } + + @Override + public void onFailure(Exception e) { + LogUtils.e("MP4下载或播放失败: " + e.getMessage()); + // 处理失败情况,继续播放下一个 + post(() -> { + lock.lock(); + try { + isLoadEffect = false; + } finally { + lock.unlock(); + } + loadStartSVGAPlayer(); + }); + } + }); + } else if (playImage.endsWith("svga")) { +// File file = downloadAndPlay(getContext(), playImage); + post(() -> { + playerMp4View.setVisibility(View.GONE); + svgaView.setVisibility(View.VISIBLE); + svgaView.loadSVGAPlayerWith(finalGiftModel, false); + }); + } else { + lock.lock(); + try { + isLoadEffect = false; + } finally { + lock.unlock(); + } + loadStartSVGAPlayer(); + // 直接播放缓存文件 + } + + } + }); + } + } + + + public void downloadAndPlay(Context context, String playImage, DownloadCallback callback) { + String fileName = playImage.substring(playImage.lastIndexOf("/")); + String filePath = context.getCacheDir().getAbsolutePath() + fileName; + + LogUtils.e("@@@@@filePath: " + filePath.toString()); + + File file = new File(filePath); + + if (!file.exists()) { + LogUtils.e("无缓存"); + // 使用OkHttp进行下载 + OkHttpClient client = new OkHttpClient(); + Request request = new Request.Builder() + .url(playImage) + .build(); + + client.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + LogUtils.e("MP4下载失败: " + e.toString()); + // 在主线程中回调失败 + post(() -> { + if (callback != null) { + callback.onFailure(e); + } + }); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + if (response.isSuccessful()) { + try (ResponseBody responseBody = response.body()) { + if (responseBody != null) { + File downloadedFile = new File(filePath); + FileOutputStream fos = new FileOutputStream(downloadedFile); + fos.write(responseBody.bytes()); + fos.close(); + + // 在主线程中回调成功 + post(() -> { + if (callback != null) { + callback.onSuccess(downloadedFile); + } + }); + } else { + // 在主线程中回调失败 + post(() -> { + if (callback != null) { + callback.onFailure(new IOException("Response body is null")); + } + }); + } + } catch (Exception e) { + LogUtils.e("MP4文件保存失败: " + e.getMessage()); + // 在主线程中回调失败 + post(() -> { + if (callback != null) { + callback.onFailure(e); + } + }); + } + } else { + LogUtils.e("MP4下载响应失败"); + // 在主线程中回调失败 + post(() -> { + if (callback != null) { + callback.onFailure(new IOException("Response not successful: " + response.code())); + } + }); + } + } + }); + } else { + // 文件已存在,直接回调成功 + if (callback != null) { + callback.onSuccess(file); + } + } + } + + // 添加回调接口 + public interface DownloadCallback { + void onSuccess(File file); + + void onFailure(Exception e); + } + + + public void destroyEffectView() { + removeSvgaQueueData(); + svgaView.stopEffectSvgaPlay(); + playerMp4View.stopPlay(); + // 清理监听器 + clearPlaybackCompleteListeners(); + removeView(playerMp4View); + removeView(svgaView); + svgaView = null; + playerMp4View = null; + playModel = null; + + if (queue != null) { + queue.shutdown(); + queue = null; + } + } + + private void removeSvgaQueueData() { + lock.lock(); + try { + giftArray.clear(); + isLoadEffect = false; + } finally { + lock.unlock(); + } + } + + private String getFileExtension(String url) { + if (url != null && url.contains(".")) { + return url.substring(url.lastIndexOf(".") + 1); + } + return ""; + } + + @Override + public void onStartAnimation(GiftSvgaView view) { + + } + + @Override + public void onFinishedDisplay(GiftSvgaView view) { + post(() -> { + if (svgaView!=null) { + svgaView.setVisibility(View.GONE); + } + if (isOnece){ + return; + } + // 通知播放完成 + notifyPlaybackComplete(); + loadStartSVGAPlayer(); + }); + } + + // 在 GiftAnimView 类中添加播放完成监听接口 + public interface OnPlaybackCompleteListener { + void onPlaybackComplete(); + } + + // 在 GiftAnimView 类中添加成员变量 + private List playbackCompleteListeners = new ArrayList<>(); + + // 在 GiftAnimView 类中添加监听器管理方法 + public void addOnPlaybackCompleteListener(OnPlaybackCompleteListener listener) { + if (listener != null && !playbackCompleteListeners.contains(listener)) { + playbackCompleteListeners.add(listener); + } + } + + public void removeOnPlaybackCompleteListener(OnPlaybackCompleteListener listener) { + if (listener != null) { + playbackCompleteListeners.remove(listener); + } + } + + public void clearPlaybackCompleteListeners() { + playbackCompleteListeners.clear(); + } + + // 触发播放完成回调的方法 + private void notifyPlaybackComplete() { + for (OnPlaybackCompleteListener listener : new ArrayList<>(playbackCompleteListeners)) { + if (listener != null) { + listener.onPlaybackComplete(); + } + } + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/GiftCardView.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/GiftCardView.java new file mode 100644 index 00000000..1534c06b --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/GiftCardView.java @@ -0,0 +1,306 @@ +package com.xscm.moduleutil.widget; + +import android.animation.ObjectAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.LayerDrawable; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.google.android.material.card.MaterialCardView; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.bean.GiftBean; +import com.xscm.moduleutil.utils.ImageUtils; + +/** + * 礼物卡片控件 - 支持选中效果和自定义样式 + */ +public class GiftCardView extends FrameLayout { + + private ImageView mIconImageView; + private TextView mNameTextView; + private TextView mCountTextView; + private TextView mResultTextView; + + private boolean isSelected = false; + private Drawable selectedBackground; + private Drawable normalBackground; + + // 添加GiftBean数据引用 + private GiftBean giftBean; + + private ObjectAnimator pulseAnimator; + + public GiftCardView(Context context) { + this(context, null); + } + + public GiftCardView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public GiftCardView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initViews(); + initAttributes(attrs); + } + + private void initViews() { + LayoutInflater.from(getContext()).inflate(R.layout.view_gift_card, this, true); + + mIconImageView = findViewById(R.id.img_gift_icon); + mNameTextView = findViewById(R.id.tv_gift_name); + mCountTextView = findViewById(R.id.tv_gift_count); + mResultTextView= findViewById(R.id.result); + + // 设置默认点击事件 + setOnClickListener(v -> { + if (getOnGiftClickListener() != null) { + getOnGiftClickListener().onGiftClick(this); + } + }); + } + + private void initAttributes(AttributeSet attrs) { + TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.GiftCardView); + + try { + // 获取自定义属性 + String name = typedArray.getString(R.styleable.GiftCardView_giftName); + String count = typedArray.getString(R.styleable.GiftCardView_giftCount); + int iconResId = typedArray.getResourceId(R.styleable.GiftCardView_giftIcon, 0); + + // 设置默认值 + if (name != null) { + setName(name); + } + if (count != null) { + setCount(count); + } + if (iconResId != 0) { + setIcon(""); + } + + // 获取选中状态相关属性 + selectedBackground = typedArray.getDrawable(R.styleable.GiftCardView_selectedBackground); + normalBackground = typedArray.getDrawable(R.styleable.GiftCardView_normalBackground); + + // 如果没有设置选中背景,则使用默认的选中效果 +// if (selectedBackground == null) { +// selectedBackground = ContextCompat.getDrawable(getContext(), R.mipmap.tkzj_x); +// } +// if (normalBackground == null) { +// normalBackground = ContextCompat.getDrawable(getContext(), R.mipmap.tkzj_w); +// } + + // 设置默认背景 + if (normalBackground != null) { + setBackground(normalBackground); + } + + } finally { + typedArray.recycle(); + } + } + /** + * 绑定GiftBean数据 + */ + public void bindGiftData(GiftBean giftBean) { + this.giftBean = giftBean; + + if (giftBean != null) { + // 设置礼物图标 + if (giftBean.getBase_image() != null && !giftBean.getBase_image().isEmpty()) { + setIcon(giftBean.getBase_image()); + // 如果是资源ID + + } else { + setIcon(""); + } + + // 设置礼物名称 + setName(giftBean.getGift_name() != null ? giftBean.getGift_name() : "未知礼物"); + + // 设置礼物数量 + setCount(giftBean.getGift_price() != null ? giftBean.getGift_price() : "0"); + setmResultTextView(giftBean.getCount()); + } + } + + /** + * 获取绑定的GiftBean数据 + */ + public GiftBean getGiftBean() { + return giftBean; + } + /** + * 设置礼物图标(URL) + */ + public void setIcon(String url) { + if (mIconImageView != null) { + if (url != null && !url.isEmpty()) { + ImageUtils.loadHeadCC(url, mIconImageView); + } else { + mIconImageView.setImageResource(R.mipmap.ic_launcher); + } + } + } + private android.animation.AnimatorSet animatorSet; + + public void startPulseAnimationWithLayer() { + if (pulseAnimator != null && pulseAnimator.isRunning()) { + pulseAnimator.cancel(); + } + pulseAnimator = ObjectAnimator.ofFloat(this, "scaleX", 0.9f, 1.1f); + pulseAnimator.setDuration(500); + pulseAnimator.setRepeatCount(ObjectAnimator.INFINITE); + pulseAnimator.setRepeatMode(ObjectAnimator.REVERSE); + ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(this, "scaleY", 0.9f, 1.1f); + scaleYAnimator.setDuration(500); + scaleYAnimator.setRepeatCount(ObjectAnimator.INFINITE); + scaleYAnimator.setRepeatMode(ObjectAnimator.REVERSE); + + // 组合动画 + animatorSet = new android.animation.AnimatorSet(); + animatorSet.playTogether(pulseAnimator, scaleYAnimator); + animatorSet.start(); + } + + public void stopPulseAnimationWithLayer() { + if (pulseAnimator != null) { + pulseAnimator.cancel(); + } + + // 停止组合动画 + if (animatorSet != null && animatorSet.isRunning()) { + animatorSet.cancel(); + } + + // 清除引用 + animatorSet = null; + pulseAnimator = null; + + // 重置缩放 + this.setScaleX(1f); + this.setScaleY(1f); + + // 强制重新绘制 + this.invalidate(); + } + /** + * 设置礼物名称 + */ + public void setName(String name) { + if (mNameTextView != null) { + mNameTextView.setText(name); + } + } + + /** + * 设置礼物数量 + */ + public void setCount(String count) { + if (mCountTextView != null) { + mCountTextView.setText(count); + } + } + + /** + * 设置选中状态 + */ + public void setSelected(boolean selected) { + isSelected = selected; + + if (selected) { + setBackground(selectedBackground); + // 可以添加额外的选中效果 +// setElevation(8f); // 提高阴影 + // 添加发光效果 +// addGlowEffect(); + } else { + setBackground(normalBackground); +// setElevation(4f); // 恢复默认阴影 +// removeGlowEffect(); + } + } + + public void setmResultTextView(int num){ + if (mResultTextView!=null) { + mResultTextView.setText("x" + num); + } + } + + public void setVisibilitymResultTextView(boolean isVisible){ + if (mResultTextView!=null) { + mResultTextView.setVisibility(isVisible?View.VISIBLE:View.GONE); + } + } + + /** + * 添加发光效果 + */ + private void addGlowEffect() { + // 使用LayerDrawable创建发光效果 + GradientDrawable glow = new GradientDrawable(); + glow.setColor(Color.TRANSPARENT); + glow.setStroke(8, Color.argb(150, 255, 255, 255)); + glow.setCornerRadius(16f); + + LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{glow, getBackground()}); + setBackground(layerDrawable); + } + + /** + * 移除发光效果 + */ + private void removeGlowEffect() { + setBackground(normalBackground); + } + + /** + * 获取当前是否选中 + */ + public boolean isSelected() { + return isSelected; + } + + /** + * 切换选中状态 + */ + public void toggleSelected() { + setSelected(!isSelected); + } + + /** + * 设置点击监听器 + */ + public void setOnGiftClickListener(OnGiftClickListener listener) { + this.onGiftClickListener = listener; + } + + /** + * 获取点击监听器 + */ + public OnGiftClickListener getOnGiftClickListener() { + return onGiftClickListener; + } + + /** + * 点击监听器接口 + */ + public interface OnGiftClickListener { + void onGiftClick(GiftCardView giftCardView); + } + + private OnGiftClickListener onGiftClickListener; +} + diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/GiftSvgaView.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/GiftSvgaView.java new file mode 100644 index 00000000..ab999753 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/GiftSvgaView.java @@ -0,0 +1,285 @@ +package com.xscm.moduleutil.widget; + +import android.content.Context; +import android.graphics.Color; +import android.util.AttributeSet; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.opensource.svgaplayer.SVGACallback; +import com.opensource.svgaplayer.SVGADrawable; +import com.opensource.svgaplayer.SVGAImageView; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +public class GiftSvgaView extends FrameLayout implements SVGACallback { + private SVGAImageView player; + private SVGAParser parser; + private boolean isAutoPlay = true; + + // 回调接口 + public interface OnAnimationListener { + void onStartAnimation(GiftSvgaView view); + void onFinishedDisplay(GiftSvgaView view); + } + + private OnAnimationListener didStartAnimation; + private OnAnimationListener didFinishedDisplay; + + public GiftSvgaView(Context context) { + this(context, null); + } + + public GiftSvgaView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public GiftSvgaView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initializeData(true); + } + + public GiftSvgaView(Context context, boolean isAutoPlay) { + super(context); + initializeData(isAutoPlay); + } + + private void initializeData(boolean isAutoPlay) { + this.isAutoPlay = isAutoPlay; + setBackgroundColor(Color.TRANSPARENT); // clearColor + setClickable(false); // userInteractionEnabled = NO + initPlayer(); + } + + private void initPlayer() { + player = new SVGAImageView(getContext()); + player.setBackgroundColor(Color.TRANSPARENT); + player.setScaleType(ImageView.ScaleType.CENTER_CROP); // UIViewContentModeScaleAspectFill + // 如果需要 ScaleAspectFit,使用 ImageView.ScaleType.FIT_CENTER + + // 设置布局参数 - 填满父视图 + LayoutParams params = new LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT + ); + addView(player, params); + + // 初始化解析器 + parser = new SVGAParser(getContext()); + player.setCallback(this); + } + + public void loadSVGAPlayerWith(String loadPath) { + loadSVGAPlayerWith(loadPath, false); + } + + public void loadSVGAPlayerWith(String loadPath, boolean inBundle) { + loadSVGAPlayerWith(loadPath, inBundle, 1); + } + + public void loadSVGAPlayerWith(String loadPath, boolean inBundle, int loop) { + if (loadPath == null || loadPath.isEmpty()) { + if (didFinishedDisplay != null) { + didFinishedDisplay.onFinishedDisplay(this); + } + return; + } + + if (player == null) { + initPlayer(); + } + + stopEffectSvgaPlay(); + player.setLoops(loop); + + if (loadPath.startsWith("https:") || loadPath.startsWith("http:")) { + // URL加载 + try { + parser.parse(new URL(loadPath), new SVGAParser.ParseCompletion() { + @Override + public void onComplete(@NotNull SVGAVideoEntity videoItem) { + SVGADrawable drawable = new SVGADrawable(videoItem); + player.setImageDrawable(drawable); + + if (isAutoPlay) { + player.startAnimation(); + if (didStartAnimation != null) { + didStartAnimation.onStartAnimation(GiftSvgaView.this); + } + } + } + + @Override + public void onError() { + if (didFinishedDisplay != null) { + didFinishedDisplay.onFinishedDisplay(GiftSvgaView.this); + } + } + }); + } catch (Exception e) { + e.printStackTrace(); + if (didFinishedDisplay != null) { + didFinishedDisplay.onFinishedDisplay(this); + } + } + } else if (inBundle) { + // 从Assets加载 + try { + parser.parse(loadPath, new SVGAParser.ParseCompletion() { + @Override + public void onComplete(@NotNull SVGAVideoEntity videoItem) { + SVGADrawable drawable = new SVGADrawable(videoItem); + player.setImageDrawable(drawable); + + if (isAutoPlay) { + player.startAnimation(); + if (didStartAnimation != null) { + didStartAnimation.onStartAnimation(GiftSvgaView.this); + } + } + } + + @Override + public void onError() { + if (didFinishedDisplay != null) { + didFinishedDisplay.onFinishedDisplay(GiftSvgaView.this); + } + } + }); + } catch (Exception e) { + e.printStackTrace(); + if (didFinishedDisplay != null) { + didFinishedDisplay.onFinishedDisplay(this); + } + } + } else { + // 从文件路径加载 + try { + File file = new File(loadPath); + if (!file.exists() || file.length() < 4) { + if (didFinishedDisplay != null) { + didFinishedDisplay.onFinishedDisplay(this); + } + return; + } + + InputStream inputStream = new FileInputStream(file); + parser.parse(inputStream, loadPath, new SVGAParser.ParseCompletion() { + @Override + public void onComplete(@NotNull SVGAVideoEntity videoItem) { + SVGADrawable drawable = new SVGADrawable(videoItem); + player.setImageDrawable(drawable); + + if (isAutoPlay) { + player.startAnimation(); + if (didStartAnimation != null) { + didStartAnimation.onStartAnimation(GiftSvgaView.this); + } + } + } + + @Override + public void onError() { + if (didFinishedDisplay != null) { + didFinishedDisplay.onFinishedDisplay(GiftSvgaView.this); + } + } + }, true); + } catch (IOException e) { + e.printStackTrace(); + if (didFinishedDisplay != null) { + didFinishedDisplay.onFinishedDisplay(this); + } + } + } + } + + // Public方法 + public void startEffectSvgaPlay() { + if (player != null && player.getDrawable() != null) { + player.startAnimation(); + } + } + + public void pauseEffectSvgaPlay() { + if (player != null) { + player.pauseAnimation(); + } + } + + public void stopEffectSvgaPlay() { + if (player != null) { + player.stopAnimation(); + player.clearAnimation(); + player.setImageDrawable( null); + } + } + + public void destroySvga() { + stopEffectSvgaPlay(); + if (player != null) { + removeView(player); + player = null; + } + parser = null; + } + + // SVGACallback接口实现 + @Override + public void onPause() { + // 暂停回调 + } + + @Override + public void onFinished() { + if (didFinishedDisplay != null) { + didFinishedDisplay.onFinishedDisplay(this); + } + } + + @Override + public void onRepeat() { + // 重复回调 + } + + @Override + public void onStep(int frame, double percentage) { + // 步骤回调 + } + + // Getter和Setter方法 + public void setDidStartAnimation(OnAnimationListener listener) { + this.didStartAnimation = listener; + } + + public void setDidFinishedDisplay(OnAnimationListener listener) { + this.didFinishedDisplay = listener; + if (player != null) { + player.setCallback(this); + } + } + + public boolean isAutoPlay() { + return isAutoPlay; + } + + public void setAutoPlay(boolean autoPlay) { + isAutoPlay = autoPlay; + } + + public SVGAImageView getPlayer() { + return player; + } + + public SVGAParser getParser() { + return parser; + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/QXGiftDriftView.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/QXGiftDriftView.java new file mode 100644 index 00000000..8dc87683 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/QXGiftDriftView.java @@ -0,0 +1,273 @@ +package com.xscm.moduleutil.widget; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Color; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.view.animation.TranslateAnimation; +import android.widget.ImageView; +import android.widget.TextView; + +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.event.MqttBean; + +import java.util.ArrayList; +import java.util.List; + +public class QXGiftDriftView extends ViewGroup { + + private static QXGiftDriftView instance; + + private ImageView bgImageView; + private TextView titleLabel; + private ImageView giftImageView; + private TextView countLabel; + private boolean isPlaying=false; + private boolean isClose; + + private List dataArray = new ArrayList<>(); + private MqttBean.ListBean model; + + private Context context; + private int screenWidth; + + public static QXGiftDriftView getInstance(Context context) { + if (instance == null) { + instance = new QXGiftDriftView(context); + } + return instance; + } + + private QXGiftDriftView(Context context) { + super(context); + this.context = context; + + // 获取屏幕宽度 + screenWidth = context.getResources().getDisplayMetrics().widthPixels; + + // 初始化视图 + initSubviews(); + + // 从SharedPreferences读取设置 + SharedPreferences prefs = context.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE); + isClose = prefs.getBoolean("kIsCloseDrifPop", false); + } + + private void initSubviews() { + // 设置视图尺寸 + int width = scaleWidth(316); + int height = scaleWidth(50); + setLayoutParams(new LayoutParams(width, height)); + + // 背景图片 + bgImageView = new ImageView(context); + bgImageView.setImageResource(R.mipmap.gift_p_b); + addView(bgImageView); + + // 标题标签 + titleLabel = new TextView(context); + titleLabel.setTextSize(14); + titleLabel.setTextColor(Color.WHITE); + addView(titleLabel); + + // 礼物图片 + giftImageView = new ImageView(context); + giftImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + addView(giftImageView); + + // 数量标签 + countLabel = new TextView(context); + countLabel.setTextSize(14); + countLabel.setTextColor(Color.WHITE); + addView(countLabel); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + // 布局子视图 + int width = getWidth(); + int height = getHeight(); + + // 背景图片填满整个视图 + bgImageView.layout(0, 0, width, height); + + // 标题标签居中偏左 + int titleWidth = titleLabel.getMeasuredWidth(); + int titleHeight = titleLabel.getMeasuredHeight(); + int titleLeft = (width - titleWidth) / 2 - scaleWidth(30); + int titleTop = (height - titleHeight) / 2; + titleLabel.layout(titleLeft, titleTop, titleLeft + titleWidth, titleTop + titleHeight); + + // 礼物图片在标题右侧 + int giftSize = scaleWidth(20); + int giftLeft = titleLeft + titleWidth + scaleWidth(5); + int giftTop = titleTop + (titleHeight - giftSize) / 2; + giftImageView.layout(giftLeft, giftTop, giftLeft + giftSize, giftTop + giftSize); + + // 数量标签在礼物图片右侧 + int countWidth = countLabel.getMeasuredWidth(); + int countLeft = giftLeft + giftSize; + countLabel.layout(countLeft, titleTop, countLeft + countWidth, titleTop + titleHeight); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = scaleWidth(316); + int height = scaleWidth(50); + setMeasuredDimension(width, height); + + // 测量子视图 + measureChildren(widthMeasureSpec, heightMeasureSpec); + } + + public void addGiftModel(MqttBean.ListBean model) { + if (isClose) { + return; + } + dataArray.add(model); + giftAction(); + } + + public void addGiftModelList(List list) { + dataArray.addAll(list); + giftAction(); + } + + private void giftAction() { + if (isPlaying) { + return; + } + + if (dataArray.isEmpty()) { + return; + } + + isPlaying = true; + model = dataArray.get(0); + + // 添加到窗口(这里需要根据实际情况获取根布局) + ViewGroup rootView = (ViewGroup) ((Activity) context).getWindow().getDecorView(); + rootView.addView(QXGiftDriftView.getInstance( context)); + + // 设置初始位置(屏幕右侧外) + setX(screenWidth); + + // 进入动画 + TranslateAnimation enterAnim = new TranslateAnimation( + Animation.ABSOLUTE, screenWidth, + Animation.ABSOLUTE, (screenWidth - scaleWidth(316)) / 2, + Animation.ABSOLUTE, 0, + Animation.ABSOLUTE, 0 + ); + enterAnim.setDuration(1500); + enterAnim.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) {} + + @Override + public void onAnimationEnd(Animation animation) { + // 停留后退出 + postDelayed(() -> { + TranslateAnimation exitAnim = new TranslateAnimation( + Animation.ABSOLUTE, (screenWidth - scaleWidth(316)) / 2, + Animation.ABSOLUTE, -screenWidth, + Animation.ABSOLUTE, 0, + Animation.ABSOLUTE, 0 + ); + exitAnim.setDuration(2000); + exitAnim.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) {} + + @Override + public void onAnimationEnd(Animation animation) { + // 移除视图并处理下一个 + ViewGroup rootView = (ViewGroup) getParent(); + if (rootView != null) { + rootView.removeView(QXGiftDriftView.getInstance( context)); + } + + if (!dataArray.isEmpty()) { + dataArray.remove(0); + } + isPlaying = false; + + if (!dataArray.isEmpty()) { + giftAction(); + } + } + + @Override + public void onAnimationRepeat(Animation animation) {} + }); + startAnimation(exitAnim); + }, 1000); // 停留1秒 + } + + @Override + public void onAnimationRepeat(Animation animation) {} + }); + startAnimation(enterAnim); + } + + public void setModel(MqttBean.ListBean model) { + this.model = model; + + String text = String.format("%s送给%s", model.getFromUserName(), model.getToUserName()); + // 这里需要使用SpannableString来实现富文本效果 + // 简化处理,直接设置文本 + titleLabel.setText(text); + + // 加载图片 - 使用图片加载库如Glide + // Glide.with(context).load(model.getGiftPicture()).into(giftImageView); + + countLabel.setText(String.format("X%s", model.getNumber())); + } + + public void drifPopIsClose(boolean isClose) { + this.isClose = isClose; + setVisibility(isClose ? View.GONE : View.VISIBLE); + + SharedPreferences prefs = context.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE); + prefs.edit().putBoolean("kIsCloseDrifPop", isClose).apply(); + + if (isClose) { + ViewGroup rootView = (ViewGroup) getParent(); + if (rootView != null) { + rootView.removeView(this); + } + dataArray.clear(); + isPlaying = false; + } + } + + private int scaleWidth(int width) { + // 根据屏幕密度进行缩放 + float density = context.getResources().getDisplayMetrics().density; + return (int) (width * density); + } + + // QXGiftScrollModel 类(需要单独定义) + public static class QXGiftScrollModel { + private String fromUserName; + private String toUserName; + private String giftPicture; + private String number; + + // getters and setters + public String getFromUserName() { return fromUserName; } + public void setFromUserName(String fromUserName) { this.fromUserName = fromUserName; } + + public String getToUserName() { return toUserName; } + public void setToUserName(String toUserName) { this.toUserName = toUserName; } + + public String getGiftPicture() { return giftPicture; } + public void setGiftPicture(String giftPicture) { this.giftPicture = giftPicture; } + + public String getNumber() { return number; } + public void setNumber(String number) { this.number = number; } + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/QXGiftPlayerManager.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/QXGiftPlayerManager.java new file mode 100644 index 00000000..8fbcbcc8 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/QXGiftPlayerManager.java @@ -0,0 +1,144 @@ +package com.xscm.moduleutil.widget; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import com.xscm.moduleutil.bean.GiftBean; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class QXGiftPlayerManager { + private static QXGiftPlayerManager instance; + private View bgEffectView; + + private GiftAnimView fullEffectView; + private GiftAnimView chatEffectView; + private Context context; + + private QXGiftPlayerManager(Context context) { + this.context = context.getApplicationContext(); + } + + public static synchronized QXGiftPlayerManager getInstance(Context context) { + if (instance == null) { + instance = new QXGiftPlayerManager(context); + } + return instance; + } + public View getDefaultBgEffectView() { + if (bgEffectView == null) { + initBgEffectView(); + } + return bgEffectView; + } + + public GiftAnimView getDefaultFullEffectView() { + if (fullEffectView == null) { + initFullEffectView(); + } + return fullEffectView; + } + + public GiftAnimView getDefaultChatEffectView() { + if (chatEffectView == null) { + initChatEffectView(); + } + return chatEffectView; + } + + private void initBgEffectView() { + bgEffectView = new FrameLayout(context); + bgEffectView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + )); + bgEffectView.setBackgroundColor(0x00000000); + bgEffectView.setClickable(false); // userInteractionEnabled = NO + + // 添加全屏特效视图和聊天特效视图 + ((ViewGroup) bgEffectView).addView(getDefaultFullEffectView()); + ((ViewGroup) bgEffectView).addView(getDefaultChatEffectView()); + } + public void displayFullEffectView(String gift) { + getDefaultFullEffectView().displayEffectView(gift); + } + + public void displayFullEffectView1(List stringList){ + getDefaultFullEffectView().displayEffectView1(stringList); + } + + public void displayChatEffectView(String gift) { + getDefaultChatEffectView().displayEffectView(gift); + } + + + + public void openOrCloseEffectViewWith(boolean isShow) { + getDefaultFullEffectView().openOrCloseEffectViewWith(isShow); + getDefaultChatEffectView().openOrCloseEffectViewWith(isShow); + } + + public void destroyEffectSvga() { + if (fullEffectView != null) { + fullEffectView.destroyEffectView(); + if (bgEffectView != null) { + ((ViewGroup) bgEffectView).removeView(fullEffectView); + } + fullEffectView = null; + } + + if (chatEffectView != null) { + chatEffectView.destroyEffectView(); + if (bgEffectView != null) { + ((ViewGroup) bgEffectView).removeView(chatEffectView); + } + chatEffectView = null; + } + + if (bgEffectView != null) { + bgEffectView = null; + } + } + + public void stopPlay() { + if (fullEffectView != null) { + fullEffectView.stopPlay(); + } + if (chatEffectView != null) { + chatEffectView.stopPlay(); + } + } + + private void initFullEffectView() { + fullEffectView = new GiftAnimView(context); + fullEffectView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + )); + // 创建专用线程池替代GCD队列 + ExecutorService queue = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(), + Executors.defaultThreadFactory()); + fullEffectView.setQueue(queue); + } + + private void initChatEffectView() { + chatEffectView = new GiftAnimView(context); + chatEffectView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + )); + // 创建专用线程池替代GCD队列 + ExecutorService queue = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(), + Executors.defaultThreadFactory()); + chatEffectView.setQueue(queue); + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/RoomSingWheatView.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/RoomSingWheatView.java new file mode 100644 index 00000000..c0ef584d --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/RoomSingWheatView.java @@ -0,0 +1,169 @@ +package com.xscm.moduleutil.widget; + +import android.content.Context; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.opensource.svgaplayer.SVGAImageView; +import com.xscm.moduleutil.R; +import com.xscm.moduleutil.bean.room.RoomPitBean; +import com.xscm.moduleutil.utils.ImageUtils; + +public class RoomSingWheatView extends LinearLayout { + + public ImageView mRiv; + public ImageView mIvGift; + public WheatCharmView mCharmView; + public TextView mTvName; + public ImageView mIvSex; + public AvatarFrameView mIvFrame; + public AvatarFrameView mIvRipple; + public ExpressionImgView mIvFace; + public ImageView mIvShutup; + public TextView tvTime; + public TextView mTvNo; + + public TextView tv_time_pk; + + public RoomPitBean pitBean;//麦位数据 + public String roomId;//房间id + + public static final String WHEAT_BOSS = "8";//老板位 + public static final String WHEAT_HOST = "9";//主持位 + + public float oX; + public float oY; + + boolean closePhone = false;//自己麦位关闭话筒,用于判断声纹显示 + + public String pitNumber; + public int pitImageVId; + +// public ImageView iv_on_line; + private boolean showGiftAnim = true;//显示麦位动画 + private ImageView iv_tag_type; + + private TextView tv_zhul; + + public RoomSingWheatView(@NonNull Context context) { + this(context, null); + } + + public RoomSingWheatView(@NonNull Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public RoomSingWheatView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initView(context); + } + + private void initView(Context context) { + // 确保布局被正确加载 + inflate(context, getLayoutId(), this); + + // 初始化所有视图组件 + mRiv = findViewById(R.id.riv); + mIvGift = findViewById(R.id.iv_gift); + mCharmView = findViewById(R.id.charm_view); + mTvName = findViewById(R.id.tv_name); + mIvSex = findViewById(R.id.iv_sex); + mIvFrame = findViewById(R.id.iv_frame); + mIvRipple = findViewById(R.id.iv_ripple); + mIvFace = findViewById(R.id.iv_face); + mIvShutup = findViewById(R.id.iv_shutup); + tvTime = findViewById(R.id.tv_time); + tv_time_pk = findViewById(R.id.tv_time_pk); + mTvNo = findViewById(R.id.tv_no); +// iv_on_line = findViewById(R.id.iv_online); + iv_tag_type = findViewById(R.id.iv_tag_type); + tv_zhul = findViewById(R.id.tv_zhul); + + // 设置初始位置 + if (mIvGift != null) { + oX = mIvGift.getX(); + oY = mIvGift.getY(); + } + } + + protected int getLayoutId() { + return R.layout.room_view_sing_wheat; + } + + public void setData(RoomPitBean bean) { + this.pitBean = bean; + if (bean == null) return; + + // 添加空值检查,防止NPE + if (mTvName == null) { + // 可能布局未正确加载,尝试重新初始化 + initView(getContext()); + if (mTvName == null) { + // 如果仍然为null,记录日志并返回 + android.util.Log.e("RoomSingWheatView", "mTvName is still null after re-initialization"); + return; + } + } + + if (isOn()) { + //开启声浪 + mIvRipple.startLoopingSvga("ripple3695.svga"); + mIvRipple.setVisibility(VISIBLE); + mTvName.setText(bean.getNickname()); + ImageUtils.loadHeadCC(bean.getAvatar(), mRiv); + + if (TextUtils.isEmpty(pitBean.getDress())) { + if (mIvFrame != null) mIvFrame.setVisibility(INVISIBLE); + } else { + if (mIvFrame != null) { + mIvFrame.setVisibility(VISIBLE); + mIvFrame.setSource(pitBean.getDress(), 3); + } + } + } else { + String pitText = "-1".equals(pitNumber) ? "" : + "9".equals(pitNumber) ? "主持位" : + "10".equals(pitNumber) ? "嘉宾位" : + pitNumber + "号麦位"; + mTvName.setText(pitText); + + if (mIvFrame != null) mIvFrame.setVisibility(INVISIBLE); + if (mIvFace != null) mIvFace.remove(); + //停止声浪 + mIvRipple.stopSvga(); + mIvRipple.setVisibility(GONE); + } + + // 更新魅力值视图 + if (mCharmView != null) { + if (pitBean.getNickname() == null || pitBean.getNickname().isEmpty()) { + mCharmView.setVisibility(GONE); + } else { + mCharmView.setVisibility(VISIBLE); + } + } + + // 更新PK状态 + if (tv_time_pk != null) { + if (pitBean.is_pk() && pitBean.getUser_id() != null && + !pitBean.getUser_id().equals("0") && !pitBean.getUser_id().isEmpty()) { + tv_time_pk.setVisibility(VISIBLE); + if (mCharmView != null) mCharmView.setVisibility(GONE); + } else { + tv_time_pk.setVisibility(GONE); + if (mCharmView != null) mCharmView.setVisibility(VISIBLE); + } + } + } + + private boolean isOn() { + return pitBean != null && !TextUtils.isEmpty(pitBean.getUser_id()) && !"0".equals(pitBean.getUser_id()); + } +} diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/SharedViewModel.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/SharedViewModel.java new file mode 100644 index 00000000..9b85527c --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/SharedViewModel.java @@ -0,0 +1,70 @@ +package com.xscm.moduleutil.widget; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +import com.xscm.moduleutil.bean.room.RoomInfoResp; +import com.xscm.moduleutil.event.QXRoomSeatViewType; + +// 在 common 模块中或相应模块中 +public class SharedViewModel extends ViewModel { + // 给roomFragment传递数据 + private final MutableLiveData dataForFragment = new MutableLiveData<>(); + private final MutableLiveData fragmentReady = new MutableLiveData<>(false); + private MutableLiveData seatViewTypeData = new MutableLiveData<>(); + //给子fragment传递数据 + private MutableLiveData childFragmentData = new MutableLiveData<>(); + + // 为子Fragment设置数据的方法 + public void setChildFragmentData(RoomInfoResp data) { + childFragmentData.setValue(data); + } + + // 获取子Fragment数据的LiveData + public LiveData getChildFragmentData() { + return childFragmentData; + } + public void setSeatViewType(QXRoomSeatViewType type) { + seatViewTypeData.setValue(type); + } + + public LiveData getSeatViewType() { + return seatViewTypeData; + } + public LiveData getDataForFragment() { + return dataForFragment; + } + + public void setDataForFragment(RoomInfoResp data) { + dataForFragment.setValue(data); + } + + public LiveData getFragmentReady() { + return fragmentReady; + } + + public void setFragmentReady(boolean ready) { + fragmentReady.setValue(ready); + } + + // 清除数据,避免重复接收 + + // 清理所有数据的方法 + public void clearAllData() { + dataForFragment.setValue(null); + childFragmentData.setValue(null); + seatViewTypeData.setValue(null); + fragmentReady.setValue(false); + } + + // 清理子Fragment数据 + public void clearChildFragmentData() { + childFragmentData.setValue(null); + } + + // 清理主Fragment数据 + public void clearFragmentData() { + dataForFragment.setValue(null); + } +} \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/img/BubbleBackgroundHelper.java b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/img/BubbleBackgroundHelper.java new file mode 100644 index 00000000..0d53a0f2 --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/img/BubbleBackgroundHelper.java @@ -0,0 +1,137 @@ +package com.xscm.moduleutil.widget.img; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.NinePatchDrawable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.target.CustomTarget; +import com.bumptech.glide.request.transition.Transition; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +/** + * Created by xscm on 2021/5/27. + * 创建类似.9图效果的拉伸背景 + */ +public class BubbleBackgroundHelper { + + /** + * 创建类似.9图效果的拉伸背景 + */ + public static Drawable createStretchableBubble(Context context, Bitmap originalBitmap, + int leftBorder, int topBorder, + int rightBorder, int bottomBorder) { + try { + // 将 Bitmap 转换为 NinePatchDrawable + byte[] chunk = createNinePatchChunk( + originalBitmap.getWidth(), + originalBitmap.getHeight(), + leftBorder, topBorder, rightBorder, bottomBorder + ); + + NinePatchDrawable drawable = new NinePatchDrawable( + context.getResources(), + originalBitmap, + chunk, + new Rect(), + null + ); + + return drawable; + } catch (Exception e) { + e.printStackTrace(); + // 如果失败,返回原始 BitmapDrawable + return new BitmapDrawable(context.getResources(), originalBitmap); + } + } + + /** + * 创建 NinePatch 的 chunk 数据 + */ + private static byte[] createNinePatchChunk(int bitmapWidth, int bitmapHeight, + int leftBorder, int topBorder, + int rightBorder, int bottomBorder) { + ByteBuffer buffer = ByteBuffer.allocate(84).order(ByteOrder.nativeOrder()); + + // 写入魔数 + buffer.put((byte) 0x01); + buffer.put((byte) 0x02); + buffer.put((byte) 0x02); + buffer.put((byte) 0x02); + + // 水平拉伸区域数量 + buffer.putInt(1); + // 垂直拉伸区域数量 + buffer.putInt(1); + + // 颜色数量 + buffer.putInt(0); + + // 跳过填充 + buffer.putInt(0); + buffer.putInt(0); + + // 水平拉伸区域 + buffer.putInt(leftBorder); + buffer.putInt(bitmapWidth - rightBorder); + + // 垂直拉伸区域 + buffer.putInt(topBorder); + buffer.putInt(bitmapHeight - bottomBorder); + + // 填充剩余部分 + for (int i = 0; i < 9; i++) { + buffer.putInt(0); + } + + return buffer.array(); + } + + /** + * 加载网络图片并创建拉伸背景 + */ + public static void loadBubbleBackground(Context context, String imageUrl, + OnBubbleBackgroundLoadedListener listener) { + Glide.with(context) + .asBitmap() + .load(imageUrl) + .into(new CustomTarget() { + @Override + public void onResourceReady(@NonNull Bitmap resource, + @Nullable Transition transition) { + // 假设气泡的四个角都是 30px(根据你的图片调整) + int borderSize = 10; + Drawable bubbleDrawable = createStretchableBubble( + context, resource, + borderSize, borderSize, borderSize, borderSize + ); + + if (listener != null) { + listener.onBackgroundLoaded(bubbleDrawable); + } + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + // 清理资源 + } + + @Override + public void onLoadFailed(@Nullable Drawable errorDrawable) { + if (listener != null) { + listener.onLoadFailed(); + } + } + }); + } + + public interface OnBubbleBackgroundLoadedListener { + void onBackgroundLoaded(Drawable bubbleDrawable); + void onLoadFailed(); + } +} \ No newline at end of file diff --git a/moduleUtil/src/main/java/com/xscm/moduleutil/widget/room/PassRoomException.kt b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/room/PassRoomException.kt new file mode 100644 index 00000000..cea4259d --- /dev/null +++ b/moduleUtil/src/main/java/com/xscm/moduleutil/widget/room/PassRoomException.kt @@ -0,0 +1,8 @@ +package com.xscm.moduleutil.widget.room + +import java.io.IOException + +/** + * 自定义异常信息显示 + */ +data class PassRoomException(var msg: String,var code: Int) : IOException() \ No newline at end of file diff --git a/moduleUtil/src/main/res/anim/slide_in_right.xml b/moduleUtil/src/main/res/anim/slide_in_right.xml new file mode 100644 index 00000000..c301a7ac --- /dev/null +++ b/moduleUtil/src/main/res/anim/slide_in_right.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/anim/slide_out_right.xml b/moduleUtil/src/main/res/anim/slide_out_right.xml new file mode 100644 index 00000000..3bebee9f --- /dev/null +++ b/moduleUtil/src/main/res/anim/slide_out_right.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/ac_left_gift_bg.png b/moduleUtil/src/main/res/drawable-xxxhdpi/ac_left_gift_bg.png new file mode 100644 index 00000000..5f0eff08 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/ac_left_gift_bg.png differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/ac_lock_gift_bg.png b/moduleUtil/src/main/res/drawable-xxxhdpi/ac_lock_gift_bg.png new file mode 100644 index 00000000..b67b241c Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/ac_lock_gift_bg.png differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/ac_lock_gift_light_bg.png b/moduleUtil/src/main/res/drawable-xxxhdpi/ac_lock_gift_light_bg.png new file mode 100644 index 00000000..f3258ccd Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/ac_lock_gift_light_bg.png differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/ac_meet_gift_name_bg.png b/moduleUtil/src/main/res/drawable-xxxhdpi/ac_meet_gift_name_bg.png new file mode 100644 index 00000000..ff17a584 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/ac_meet_gift_name_bg.png differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/ac_time_down_bg.png b/moduleUtil/src/main/res/drawable-xxxhdpi/ac_time_down_bg.png new file mode 100644 index 00000000..ec5d9a47 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/ac_time_down_bg.png differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/bg_room_gift.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/bg_room_gift.webp new file mode 100644 index 00000000..3adf2979 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/bg_room_gift.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/custom.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/custom.webp new file mode 100644 index 00000000..a3a0d522 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/custom.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/detail_icon_go.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/detail_icon_go.webp new file mode 100644 index 00000000..a1139bb3 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/detail_icon_go.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/gift_background.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/gift_background.webp new file mode 100644 index 00000000..4d8a8a26 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/gift_background.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/group.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/group.webp new file mode 100644 index 00000000..50bb34d6 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/group.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/ic_agreement_selected.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/ic_agreement_selected.webp new file mode 100644 index 00000000..c9f19032 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/ic_agreement_selected.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/ic_agreement_unselect.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/ic_agreement_unselect.webp new file mode 100644 index 00000000..971318af Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/ic_agreement_unselect.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/icon_btn_radio_0.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/icon_btn_radio_0.webp new file mode 100644 index 00000000..236dd396 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/icon_btn_radio_0.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/icon_btn_radio_1.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/icon_btn_radio_1.webp new file mode 100644 index 00000000..a9318d80 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/icon_btn_radio_1.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/icon_pay_select.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/icon_pay_select.webp new file mode 100644 index 00000000..2080b80f Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/icon_pay_select.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/icon_pay_unselect.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/icon_pay_unselect.webp new file mode 100644 index 00000000..971318af Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/icon_pay_unselect.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/image_yq.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/image_yq.webp new file mode 100644 index 00000000..fef15712 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/image_yq.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/img_emperor.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/img_emperor.webp new file mode 100644 index 00000000..e7d0b1c0 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/img_emperor.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/me_avatar_bg.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/me_avatar_bg.webp new file mode 100644 index 00000000..8ed29c18 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/me_avatar_bg.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/meinfo_skill_star_normal.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/meinfo_skill_star_normal.webp new file mode 100644 index 00000000..36875453 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/meinfo_skill_star_normal.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/meinfo_skill_star_selected.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/meinfo_skill_star_selected.webp new file mode 100644 index 00000000..65d03df2 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/meinfo_skill_star_selected.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/phonetic.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/phonetic.webp new file mode 100644 index 00000000..6a279dee Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/phonetic.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_btn_bg_nor.png b/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_btn_bg_nor.png new file mode 100644 index 00000000..b3a3f653 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_btn_bg_nor.png differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_btn_bg_sel.png b/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_btn_bg_sel.png new file mode 100644 index 00000000..c2ada8d3 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_btn_bg_sel.png differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_next_btn_bg.png b/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_next_btn_bg.png new file mode 100644 index 00000000..7a7b494c Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_next_btn_bg.png differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_time_btn_bg_nor.png b/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_time_btn_bg_nor.png new file mode 100644 index 00000000..d2372a8a Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_time_btn_bg_nor.png differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_time_btn_bg_sel.png b/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_time_btn_bg_sel.png new file mode 100644 index 00000000..ace098aa Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/red_bag_time_btn_bg_sel.png differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/room_ic_wheat_default.png b/moduleUtil/src/main/res/drawable-xxxhdpi/room_ic_wheat_default.png new file mode 100644 index 00000000..d59d2839 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/room_ic_wheat_default.png differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/room_redbag_back.png b/moduleUtil/src/main/res/drawable-xxxhdpi/room_redbag_back.png new file mode 100644 index 00000000..91d3bfab Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/room_redbag_back.png differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/room_redbag_help.png b/moduleUtil/src/main/res/drawable-xxxhdpi/room_redbag_help.png new file mode 100644 index 00000000..eb049052 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/room_redbag_help.png differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00000.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00000.webp new file mode 100644 index 00000000..4088c105 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00000.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00001.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00001.webp new file mode 100644 index 00000000..aa3bde0a Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00001.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00002.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00002.webp new file mode 100644 index 00000000..56bdcc98 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00002.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00003.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00003.webp new file mode 100644 index 00000000..cb880fe5 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00003.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00004.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00004.webp new file mode 100644 index 00000000..ab5c1d8c Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00004.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00005.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00005.webp new file mode 100644 index 00000000..55b807ab Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00005.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00006.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00006.webp new file mode 100644 index 00000000..dc4e840e Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00006.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00007.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00007.webp new file mode 100644 index 00000000..c72edb32 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00007.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00008.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00008.webp new file mode 100644 index 00000000..409e1d1a Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00008.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00009.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00009.webp new file mode 100644 index 00000000..a7a94fa3 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00009.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00010.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00010.webp new file mode 100644 index 00000000..d3d05d4c Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00010.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00011.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00011.webp new file mode 100644 index 00000000..feb52131 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00011.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00012.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00012.webp new file mode 100644 index 00000000..270a972a Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00012.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00013.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00013.webp new file mode 100644 index 00000000..1f933aa5 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00013.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00014.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00014.webp new file mode 100644 index 00000000..90491828 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00014.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00015.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00015.webp new file mode 100644 index 00000000..3f6d9ac8 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00015.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00016.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00016.webp new file mode 100644 index 00000000..aea576dd Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00016.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00017.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00017.webp new file mode 100644 index 00000000..9c34b78f Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00017.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00018.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00018.webp new file mode 100644 index 00000000..86c96e3a Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00018.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00019.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00019.webp new file mode 100644 index 00000000..d7c94f63 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00019.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00020.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00020.webp new file mode 100644 index 00000000..8a651102 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00020.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00021.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00021.webp new file mode 100644 index 00000000..f968efbe Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00021.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00022.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00022.webp new file mode 100644 index 00000000..8c25a86a Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00022.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00023.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00023.webp new file mode 100644 index 00000000..63cb1fdb Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00023.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00024.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00024.webp new file mode 100644 index 00000000..54a777f7 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00024.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00025.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00025.webp new file mode 100644 index 00000000..78404573 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00025.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00026.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00026.webp new file mode 100644 index 00000000..0fd1c003 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00026.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00027.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00027.webp new file mode 100644 index 00000000..da9a70ab Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00027.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00028.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00028.webp new file mode 100644 index 00000000..b6931469 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00028.webp differ diff --git a/moduleUtil/src/main/res/drawable-xxxhdpi/star_00029.webp b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00029.webp new file mode 100644 index 00000000..c4728498 Binary files /dev/null and b/moduleUtil/src/main/res/drawable-xxxhdpi/star_00029.webp differ diff --git a/moduleUtil/src/main/res/drawable/bf_e9.xml b/moduleUtil/src/main/res/drawable/bf_e9.xml new file mode 100644 index 00000000..b1f1451b --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bf_e9.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_bttom_fff.xml b/moduleUtil/src/main/res/drawable/bg_bttom_fff.xml new file mode 100644 index 00000000..4786b09d --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_bttom_fff.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_person.xml b/moduleUtil/src/main/res/drawable/bg_person.xml new file mode 100644 index 00000000..a7b3cf23 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_person.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/moduleUtil/src/main/res/drawable/bg_r10_bott.xml b/moduleUtil/src/main/res/drawable/bg_r10_bott.xml new file mode 100644 index 00000000..bfc5aca7 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_r10_bott.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/moduleUtil/src/main/res/drawable/bg_r395_ba230a.xml b/moduleUtil/src/main/res/drawable/bg_r395_ba230a.xml new file mode 100644 index 00000000..1f0158ba --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_r395_ba230a.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_r40_fe8ec8.xml b/moduleUtil/src/main/res/drawable/bg_r40_fe8ec8.xml new file mode 100644 index 00000000..edc69fe3 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_r40_fe8ec8.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_r45_2d449f.xml b/moduleUtil/src/main/res/drawable/bg_r45_2d449f.xml new file mode 100644 index 00000000..85342633 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_r45_2d449f.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_r45_8c3ca2.xml b/moduleUtil/src/main/res/drawable/bg_r45_8c3ca2.xml new file mode 100644 index 00000000..6895316c --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_r45_8c3ca2.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_r45_a27f40.xml b/moduleUtil/src/main/res/drawable/bg_r45_a27f40.xml new file mode 100644 index 00000000..c5aa4f84 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_r45_a27f40.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_r4_eff2f8.xml b/moduleUtil/src/main/res/drawable/bg_r4_eff2f8.xml new file mode 100644 index 00000000..d16b5c8f --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_r4_eff2f8.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_r6_000ff.xml b/moduleUtil/src/main/res/drawable/bg_r6_000ff.xml new file mode 100644 index 00000000..cbc129ed --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_r6_000ff.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_r8_c51a0c.xml b/moduleUtil/src/main/res/drawable/bg_r8_c51a0c.xml new file mode 100644 index 00000000..1542f872 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_r8_c51a0c.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_r8_fff.xml b/moduleUtil/src/main/res/drawable/bg_r8_fff.xml new file mode 100644 index 00000000..f20c57a9 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_r8_fff.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_r8_tm.xml b/moduleUtil/src/main/res/drawable/bg_r8_tm.xml new file mode 100644 index 00000000..1f053f32 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_r8_tm.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_radio_selector.xml b/moduleUtil/src/main/res/drawable/bg_radio_selector.xml new file mode 100644 index 00000000..db0541ff --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_radio_selector.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_red_16_envel.xml b/moduleUtil/src/main/res/drawable/bg_red_16_envel.xml new file mode 100644 index 00000000..31ac67ae --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_red_16_envel.xml @@ -0,0 +1,21 @@ + + + + + + #4d000000 + 0 + 4 + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_red_xian.xml b/moduleUtil/src/main/res/drawable/bg_red_xian.xml new file mode 100644 index 00000000..5e2b9079 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_red_xian.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_round_corner.xml b/moduleUtil/src/main/res/drawable/bg_round_corner.xml new file mode 100644 index 00000000..298a6173 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_round_corner.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/moduleUtil/src/main/res/drawable/bg_rounded_top_white.xml b/moduleUtil/src/main/res/drawable/bg_rounded_top_white.xml new file mode 100644 index 00000000..857b7690 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_rounded_top_white.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/bg_xlh_huod_bj.xml b/moduleUtil/src/main/res/drawable/bg_xlh_huod_bj.xml new file mode 100644 index 00000000..f94de2fc --- /dev/null +++ b/moduleUtil/src/main/res/drawable/bg_xlh_huod_bj.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/circle_background.xml b/moduleUtil/src/main/res/drawable/circle_background.xml new file mode 100644 index 00000000..e93365e2 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/circle_background.xml @@ -0,0 +1,5 @@ + + + + diff --git a/moduleUtil/src/main/res/drawable/ease_row_pubilc_sys_bg.xml b/moduleUtil/src/main/res/drawable/ease_row_pubilc_sys_bg.xml new file mode 100644 index 00000000..b2f611f8 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/ease_row_pubilc_sys_bg.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/home_bbar_xz.xml b/moduleUtil/src/main/res/drawable/home_bbar_xz.xml new file mode 100644 index 00000000..218841d6 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/home_bbar_xz.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/moduleUtil/src/main/res/drawable/jiaoy_tv_x.xml b/moduleUtil/src/main/res/drawable/jiaoy_tv_x.xml new file mode 100644 index 00000000..0ace894e --- /dev/null +++ b/moduleUtil/src/main/res/drawable/jiaoy_tv_x.xml @@ -0,0 +1,8 @@ + + + + #4a400c7c + 0 + 2 + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/rd_btn_new_p.xml b/moduleUtil/src/main/res/drawable/rd_btn_new_p.xml new file mode 100644 index 00000000..7544729a --- /dev/null +++ b/moduleUtil/src/main/res/drawable/rd_btn_new_p.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/drawable/selector_red_bag_condition_button.xml b/moduleUtil/src/main/res/drawable/selector_red_bag_condition_button.xml new file mode 100644 index 00000000..eb92e4ab --- /dev/null +++ b/moduleUtil/src/main/res/drawable/selector_red_bag_condition_button.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/moduleUtil/src/main/res/drawable/selector_red_bag_radio_button.xml b/moduleUtil/src/main/res/drawable/selector_red_bag_radio_button.xml new file mode 100644 index 00000000..14fa7986 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/selector_red_bag_radio_button.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/moduleUtil/src/main/res/drawable/selector_red_bag_type_button.xml b/moduleUtil/src/main/res/drawable/selector_red_bag_type_button.xml new file mode 100644 index 00000000..c4c485e9 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/selector_red_bag_type_button.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/moduleUtil/src/main/res/drawable/syzc_background.xml b/moduleUtil/src/main/res/drawable/syzc_background.xml new file mode 100644 index 00000000..1f5753b1 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/syzc_background.xml @@ -0,0 +1,5 @@ + + + + diff --git a/moduleUtil/src/main/res/drawable/text_color_radio_selector.xml b/moduleUtil/src/main/res/drawable/text_color_radio_selector.xml new file mode 100644 index 00000000..e0d8d6e3 --- /dev/null +++ b/moduleUtil/src/main/res/drawable/text_color_radio_selector.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/font/semibold.otf b/moduleUtil/src/main/res/font/semibold.otf new file mode 100644 index 00000000..5f94c235 Binary files /dev/null and b/moduleUtil/src/main/res/font/semibold.otf differ diff --git a/moduleUtil/src/main/res/layout/dialog_city_time.xml b/moduleUtil/src/main/res/layout/dialog_city_time.xml new file mode 100644 index 00000000..725aa5bd --- /dev/null +++ b/moduleUtil/src/main/res/layout/dialog_city_time.xml @@ -0,0 +1,480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/dialog_gift_lottery_fragment.xml b/moduleUtil/src/main/res/layout/dialog_gift_lottery_fragment.xml new file mode 100644 index 00000000..552697f0 --- /dev/null +++ b/moduleUtil/src/main/res/layout/dialog_gift_lottery_fragment.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/moduleUtil/src/main/res/layout/dialog_mirroe_sky.xml b/moduleUtil/src/main/res/layout/dialog_mirroe_sky.xml new file mode 100644 index 00000000..b234b1a1 --- /dev/null +++ b/moduleUtil/src/main/res/layout/dialog_mirroe_sky.xml @@ -0,0 +1,514 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/dialog_new_people.xml b/moduleUtil/src/main/res/layout/dialog_new_people.xml new file mode 100644 index 00000000..9da9e959 --- /dev/null +++ b/moduleUtil/src/main/res/layout/dialog_new_people.xml @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/dialog_new_ranking_xlh_fragment.xml b/moduleUtil/src/main/res/layout/dialog_new_ranking_xlh_fragment.xml new file mode 100644 index 00000000..aa14412a --- /dev/null +++ b/moduleUtil/src/main/res/layout/dialog_new_ranking_xlh_fragment.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/moduleUtil/src/main/res/layout/dialog_pinnacle_time.xml b/moduleUtil/src/main/res/layout/dialog_pinnacle_time.xml new file mode 100644 index 00000000..fda57903 --- /dev/null +++ b/moduleUtil/src/main/res/layout/dialog_pinnacle_time.xml @@ -0,0 +1,480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/dialog_prize_pool.xml b/moduleUtil/src/main/res/layout/dialog_prize_pool.xml new file mode 100644 index 00000000..e96932ef --- /dev/null +++ b/moduleUtil/src/main/res/layout/dialog_prize_pool.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/dialog_ranking_xlh_fragment.xml b/moduleUtil/src/main/res/layout/dialog_ranking_xlh_fragment.xml new file mode 100644 index 00000000..6ff9c6e7 --- /dev/null +++ b/moduleUtil/src/main/res/layout/dialog_ranking_xlh_fragment.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/moduleUtil/src/main/res/layout/dialog_room_auction_webview.xml b/moduleUtil/src/main/res/layout/dialog_room_auction_webview.xml new file mode 100644 index 00000000..1422b931 --- /dev/null +++ b/moduleUtil/src/main/res/layout/dialog_room_auction_webview.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/dialog_xlh_obtain.xml b/moduleUtil/src/main/res/layout/dialog_xlh_obtain.xml new file mode 100644 index 00000000..1fd778de --- /dev/null +++ b/moduleUtil/src/main/res/layout/dialog_xlh_obtain.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/dialog_xlh_record_fragment.xml b/moduleUtil/src/main/res/layout/dialog_xlh_record_fragment.xml new file mode 100644 index 00000000..dfe54bf7 --- /dev/null +++ b/moduleUtil/src/main/res/layout/dialog_xlh_record_fragment.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/moduleUtil/src/main/res/layout/fframent_data.xml b/moduleUtil/src/main/res/layout/fframent_data.xml new file mode 100644 index 00000000..1bbec3d8 --- /dev/null +++ b/moduleUtil/src/main/res/layout/fframent_data.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + diff --git a/moduleUtil/src/main/res/layout/fragment_tour_club_dialog.xml b/moduleUtil/src/main/res/layout/fragment_tour_club_dialog.xml new file mode 100644 index 00000000..93a59995 --- /dev/null +++ b/moduleUtil/src/main/res/layout/fragment_tour_club_dialog.xml @@ -0,0 +1,592 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/gift_display_layout.xml b/moduleUtil/src/main/res/layout/gift_display_layout.xml new file mode 100644 index 00000000..684d5458 --- /dev/null +++ b/moduleUtil/src/main/res/layout/gift_display_layout.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/item_gift_lottery.xml b/moduleUtil/src/main/res/layout/item_gift_lottery.xml new file mode 100644 index 00000000..9d7f7932 --- /dev/null +++ b/moduleUtil/src/main/res/layout/item_gift_lottery.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/item_gift_record.xml b/moduleUtil/src/main/res/layout/item_gift_record.xml new file mode 100644 index 00000000..35cf732f --- /dev/null +++ b/moduleUtil/src/main/res/layout/item_gift_record.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + diff --git a/moduleUtil/src/main/res/layout/item_gift_record_new.xml b/moduleUtil/src/main/res/layout/item_gift_record_new.xml new file mode 100644 index 00000000..85fd8775 --- /dev/null +++ b/moduleUtil/src/main/res/layout/item_gift_record_new.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/moduleUtil/src/main/res/layout/item_hourly_floating.xml b/moduleUtil/src/main/res/layout/item_hourly_floating.xml new file mode 100644 index 00000000..fbeb8521 --- /dev/null +++ b/moduleUtil/src/main/res/layout/item_hourly_floating.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/item_my_record.xml b/moduleUtil/src/main/res/layout/item_my_record.xml new file mode 100644 index 00000000..4ebd8bcc --- /dev/null +++ b/moduleUtil/src/main/res/layout/item_my_record.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/item_piaoping_red.xml b/moduleUtil/src/main/res/layout/item_piaoping_red.xml new file mode 100644 index 00000000..80257898 --- /dev/null +++ b/moduleUtil/src/main/res/layout/item_piaoping_red.xml @@ -0,0 +1,35 @@ + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/item_piaoping_xlh.xml b/moduleUtil/src/main/res/layout/item_piaoping_xlh.xml new file mode 100644 index 00000000..4ec4a57d --- /dev/null +++ b/moduleUtil/src/main/res/layout/item_piaoping_xlh.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/item_prize_pool.xml b/moduleUtil/src/main/res/layout/item_prize_pool.xml new file mode 100644 index 00000000..345892b8 --- /dev/null +++ b/moduleUtil/src/main/res/layout/item_prize_pool.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/item_xlh.xml b/moduleUtil/src/main/res/layout/item_xlh.xml new file mode 100644 index 00000000..a82c0dad --- /dev/null +++ b/moduleUtil/src/main/res/layout/item_xlh.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/item_xlh_gift.xml b/moduleUtil/src/main/res/layout/item_xlh_gift.xml new file mode 100644 index 00000000..04a84153 --- /dev/null +++ b/moduleUtil/src/main/res/layout/item_xlh_gift.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/moduleUtil/src/main/res/layout/view_gift_card.xml b/moduleUtil/src/main/res/layout/view_gift_card.xml new file mode 100644 index 00000000..4355f518 --- /dev/null +++ b/moduleUtil/src/main/res/layout/view_gift_card.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + diff --git a/moduleUtil/src/main/res/mipmap-hdpi/default_avatar.webp b/moduleUtil/src/main/res/mipmap-hdpi/default_avatar.webp new file mode 100644 index 00000000..61399802 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-hdpi/default_avatar.webp differ diff --git a/moduleUtil/src/main/res/mipmap-hdpi/gift_t.webp b/moduleUtil/src/main/res/mipmap-hdpi/gift_t.webp new file mode 100644 index 00000000..14b024b2 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-hdpi/gift_t.webp differ diff --git a/moduleUtil/src/main/res/mipmap-hdpi/ic_launcher_app.webp b/moduleUtil/src/main/res/mipmap-hdpi/ic_launcher_app.webp new file mode 100644 index 00000000..61399802 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-hdpi/ic_launcher_app.webp differ diff --git a/moduleUtil/src/main/res/mipmap-hdpi/ic_launcher_round1.webp b/moduleUtil/src/main/res/mipmap-hdpi/ic_launcher_round1.webp new file mode 100644 index 00000000..61399802 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-hdpi/ic_launcher_round1.webp differ diff --git a/moduleUtil/src/main/res/mipmap-hdpi/room_ic_wheat_charm.webp b/moduleUtil/src/main/res/mipmap-hdpi/room_ic_wheat_charm.webp new file mode 100644 index 00000000..cc58b528 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-hdpi/room_ic_wheat_charm.webp differ diff --git a/moduleUtil/src/main/res/mipmap-hdpi/room_status.webp b/moduleUtil/src/main/res/mipmap-hdpi/room_status.webp new file mode 100644 index 00000000..a8ea3386 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-hdpi/room_status.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/accompany_off.webp b/moduleUtil/src/main/res/mipmap-mdpi/accompany_off.webp new file mode 100644 index 00000000..ffae9ab9 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/accompany_off.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/delte.webp b/moduleUtil/src/main/res/mipmap-mdpi/delte.webp new file mode 100644 index 00000000..2210eb4d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/delte.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/gb.webp b/moduleUtil/src/main/res/mipmap-mdpi/gb.webp new file mode 100644 index 00000000..9b2af7b2 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/gb.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/hua.webp b/moduleUtil/src/main/res/mipmap-mdpi/hua.webp new file mode 100644 index 00000000..8de3a964 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/hua.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/huif.webp b/moduleUtil/src/main/res/mipmap-mdpi/huif.webp new file mode 100644 index 00000000..28bb0147 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/huif.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/huyu.webp b/moduleUtil/src/main/res/mipmap-mdpi/huyu.webp new file mode 100644 index 00000000..0b68fc40 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/huyu.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_auction.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_auction.webp new file mode 100644 index 00000000..b1045491 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_auction.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_bg_image.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_bg_image.webp new file mode 100644 index 00000000..ac44c756 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_bg_image.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_bg_music.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_bg_music.webp new file mode 100644 index 00000000..fe3441c2 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_bg_music.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_boy.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_boy.webp new file mode 100644 index 00000000..22c1a340 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_boy.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_clear_message.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_clear_message.webp new file mode 100644 index 00000000..45675e70 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_clear_message.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_close_effects.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_close_effects.webp new file mode 100644 index 00000000..e587fb3e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_close_effects.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_close_floating_screen.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_close_floating_screen.webp new file mode 100644 index 00000000..5c786a0c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_close_floating_screen.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_compere.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_compere.webp new file mode 100644 index 00000000..34c5098d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_compere.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_girl.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_girl.webp new file mode 100644 index 00000000..515ae034 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_girl.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_jiaoy.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_jiaoy.webp new file mode 100644 index 00000000..f2e0a207 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_jiaoy.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_launcher_app.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_launcher_app.webp new file mode 100644 index 00000000..82f36a48 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_launcher_app.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_leave.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_leave.webp new file mode 100644 index 00000000..9f555bab Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_leave.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_my_dress.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_my_dress.webp new file mode 100644 index 00000000..ed171f2d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_my_dress.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_open_effects.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_open_effects.webp new file mode 100644 index 00000000..13c22894 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_open_effects.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_open_floating_screen.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_open_floating_screen.webp new file mode 100644 index 00000000..cd553b43 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_open_floating_screen.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_order_mic.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_order_mic.webp new file mode 100644 index 00000000..3ee14f45 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_order_mic.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_order_mic_selected.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_order_mic_selected.webp new file mode 100644 index 00000000..40a5b593 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_order_mic_selected.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_report.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_report.webp new file mode 100644 index 00000000..59ebbcc9 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_report.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_room_setting.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_room_setting.webp new file mode 100644 index 00000000..86d41826 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_room_setting.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_share.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_share.webp new file mode 100644 index 00000000..a75f3408 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_share.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_sing.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_sing.webp new file mode 100644 index 00000000..9d1e3cc5 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_sing.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_subsidy.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_subsidy.webp new file mode 100644 index 00000000..eafadf83 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_subsidy.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/ic_welcome.webp b/moduleUtil/src/main/res/mipmap-mdpi/ic_welcome.webp new file mode 100644 index 00000000..1f30f3e6 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/ic_welcome.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/icon_arrow_right_3.webp b/moduleUtil/src/main/res/mipmap-mdpi/icon_arrow_right_3.webp new file mode 100644 index 00000000..ce83dcb2 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/icon_arrow_right_3.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/muisc_set_up.webp b/moduleUtil/src/main/res/mipmap-mdpi/muisc_set_up.webp new file mode 100644 index 00000000..c79df0b7 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/muisc_set_up.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/rank_h.webp b/moduleUtil/src/main/res/mipmap-mdpi/rank_h.webp new file mode 100644 index 00000000..442aa08a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/rank_h.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/red_tx.png b/moduleUtil/src/main/res/mipmap-mdpi/red_tx.png new file mode 100644 index 00000000..d303fcd6 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/red_tx.png differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/rewar_1.webp b/moduleUtil/src/main/res/mipmap-mdpi/rewar_1.webp new file mode 100644 index 00000000..fca43f9e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/rewar_1.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/rewar_2.webp b/moduleUtil/src/main/res/mipmap-mdpi/rewar_2.webp new file mode 100644 index 00000000..0f2b9254 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/rewar_2.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/rewar_3.webp b/moduleUtil/src/main/res/mipmap-mdpi/rewar_3.webp new file mode 100644 index 00000000..34f98097 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/rewar_3.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/room_cd_jb.webp b/moduleUtil/src/main/res/mipmap-mdpi/room_cd_jb.webp new file mode 100644 index 00000000..5bad1879 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/room_cd_jb.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/room_gift.webp b/moduleUtil/src/main/res/mipmap-mdpi/room_gift.webp new file mode 100644 index 00000000..91306732 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/room_gift.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/room_message.webp b/moduleUtil/src/main/res/mipmap-mdpi/room_message.webp new file mode 100644 index 00000000..ec5429b1 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/room_message.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/room_microphone.webp b/moduleUtil/src/main/res/mipmap-mdpi/room_microphone.webp new file mode 100644 index 00000000..96c0f339 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/room_microphone.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/room_microphone_off.webp b/moduleUtil/src/main/res/mipmap-mdpi/room_microphone_off.webp new file mode 100644 index 00000000..b1f1c6f2 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/room_microphone_off.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/room_mis.webp b/moduleUtil/src/main/res/mipmap-mdpi/room_mis.webp new file mode 100644 index 00000000..9b0f4f24 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/room_mis.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/room_notice.webp b/moduleUtil/src/main/res/mipmap-mdpi/room_notice.webp new file mode 100644 index 00000000..2edf343f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/room_notice.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/room_pk.webp b/moduleUtil/src/main/res/mipmap-mdpi/room_pk.webp new file mode 100644 index 00000000..aad4e468 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/room_pk.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/room_ranking_ist.webp b/moduleUtil/src/main/res/mipmap-mdpi/room_ranking_ist.webp new file mode 100644 index 00000000..e9dd4f4c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/room_ranking_ist.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/room_sett.webp b/moduleUtil/src/main/res/mipmap-mdpi/room_sett.webp new file mode 100644 index 00000000..3f226bae Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/room_sett.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/room_voice_g.webp b/moduleUtil/src/main/res/mipmap-mdpi/room_voice_g.webp new file mode 100644 index 00000000..56d441a0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/room_voice_g.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/room_voice_kg.webp b/moduleUtil/src/main/res/mipmap-mdpi/room_voice_kg.webp new file mode 100644 index 00000000..8908f4b6 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/room_voice_kg.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/room_xd.webp b/moduleUtil/src/main/res/mipmap-mdpi/room_xd.webp new file mode 100644 index 00000000..f050e45b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/room_xd.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/task_lq.webp b/moduleUtil/src/main/res/mipmap-mdpi/task_lq.webp new file mode 100644 index 00000000..753c16a3 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/task_lq.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/task_ylq.webp b/moduleUtil/src/main/res/mipmap-mdpi/task_ylq.webp new file mode 100644 index 00000000..18aff363 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/task_ylq.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/text_bj.webp b/moduleUtil/src/main/res/mipmap-mdpi/text_bj.webp new file mode 100644 index 00000000..64ddb59f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/text_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-mdpi/tiaoyint.webp b/moduleUtil/src/main/res/mipmap-mdpi/tiaoyint.webp new file mode 100644 index 00000000..f39ccb40 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-mdpi/tiaoyint.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/ganga.webp b/moduleUtil/src/main/res/mipmap-xhdpi/ganga.webp new file mode 100644 index 00000000..b772f675 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/ganga.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/gift_show_b.webp b/moduleUtil/src/main/res/mipmap-xhdpi/gift_show_b.webp new file mode 100644 index 00000000..04c9dec0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/gift_show_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/hourly_d.png b/moduleUtil/src/main/res/mipmap-xhdpi/hourly_d.png new file mode 100644 index 00000000..b3c8c528 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/hourly_d.png differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/hourly_xlh_sta.webp b/moduleUtil/src/main/res/mipmap-xhdpi/hourly_xlh_sta.webp new file mode 100644 index 00000000..b35e97ea Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/hourly_xlh_sta.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/hourly_xlh_status.png b/moduleUtil/src/main/res/mipmap-xhdpi/hourly_xlh_status.png new file mode 100644 index 00000000..551d1088 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/hourly_xlh_status.png differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/huanhu.webp b/moduleUtil/src/main/res/mipmap-xhdpi/huanhu.webp new file mode 100644 index 00000000..abb77754 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/huanhu.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/ic_launcher_app.webp b/moduleUtil/src/main/res/mipmap-xhdpi/ic_launcher_app.webp new file mode 100644 index 00000000..c09ebc05 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/ic_launcher_app.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/jianjiao.webp b/moduleUtil/src/main/res/mipmap-xhdpi/jianjiao.webp new file mode 100644 index 00000000..3309681c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/jianjiao.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/momoda.webp b/moduleUtil/src/main/res/mipmap-xhdpi/momoda.webp new file mode 100644 index 00000000..e61f4e51 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/momoda.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/rank_im_t1.webp b/moduleUtil/src/main/res/mipmap-xhdpi/rank_im_t1.webp new file mode 100644 index 00000000..e5f5eab0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/rank_im_t1.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/rank_im_t2.webp b/moduleUtil/src/main/res/mipmap-xhdpi/rank_im_t2.webp new file mode 100644 index 00000000..40ef2ba1 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/rank_im_t2.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/rank_im_t3.webp b/moduleUtil/src/main/res/mipmap-xhdpi/rank_im_t3.webp new file mode 100644 index 00000000..a47b6047 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/rank_im_t3.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/room_gift_wheat_bg.webp b/moduleUtil/src/main/res/mipmap-xhdpi/room_gift_wheat_bg.webp new file mode 100644 index 00000000..04c9dec0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/room_gift_wheat_bg.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/room_settr.webp b/moduleUtil/src/main/res/mipmap-xhdpi/room_settr.webp new file mode 100644 index 00000000..834f841f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/room_settr.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/top1.png b/moduleUtil/src/main/res/mipmap-xhdpi/top1.png new file mode 100644 index 00000000..d72b1dd6 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/top1.png differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/top2.png b/moduleUtil/src/main/res/mipmap-xhdpi/top2.png new file mode 100644 index 00000000..1f22194b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/top2.png differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/top3.png b/moduleUtil/src/main/res/mipmap-xhdpi/top3.png new file mode 100644 index 00000000..1722d49b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/top3.png differ diff --git a/moduleUtil/src/main/res/mipmap-xhdpi/xiaosheng.webp b/moduleUtil/src/main/res/mipmap-xhdpi/xiaosheng.webp new file mode 100644 index 00000000..1e246980 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xhdpi/xiaosheng.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/dcl.png b/moduleUtil/src/main/res/mipmap-xxhdpi/dcl.png new file mode 100644 index 00000000..c481a850 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/dcl.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/dcl2.png b/moduleUtil/src/main/res/mipmap-xxhdpi/dcl2.png new file mode 100644 index 00000000..2e39dad4 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/dcl2.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/dcl3.png b/moduleUtil/src/main/res/mipmap-xxhdpi/dcl3.png new file mode 100644 index 00000000..3b8f44c0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/dcl3.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/dcl4.png b/moduleUtil/src/main/res/mipmap-xxhdpi/dcl4.png new file mode 100644 index 00000000..fd420efa Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/dcl4.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/dcl5.png b/moduleUtil/src/main/res/mipmap-xxhdpi/dcl5.png new file mode 100644 index 00000000..3b8f44c0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/dcl5.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/dcl6.png b/moduleUtil/src/main/res/mipmap-xxhdpi/dcl6.png new file mode 100644 index 00000000..2e39dad4 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/dcl6.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/eye_close.webp b/moduleUtil/src/main/res/mipmap-xxhdpi/eye_close.webp new file mode 100644 index 00000000..850273ed Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/eye_close.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/eye_visible.webp b/moduleUtil/src/main/res/mipmap-xxhdpi/eye_visible.webp new file mode 100644 index 00000000..81150180 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/eye_visible.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/hourly_djs.png b/moduleUtil/src/main/res/mipmap-xxhdpi/hourly_djs.png new file mode 100644 index 00000000..9cde5882 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/hourly_djs.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/hourly_num.png b/moduleUtil/src/main/res/mipmap-xxhdpi/hourly_num.png new file mode 100644 index 00000000..dc600c80 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/hourly_num.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/hourly_top_bj.webp b/moduleUtil/src/main/res/mipmap-xxhdpi/hourly_top_bj.webp new file mode 100644 index 00000000..a367eb04 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/hourly_top_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/hourly_wh.png b/moduleUtil/src/main/res/mipmap-xxhdpi/hourly_wh.png new file mode 100644 index 00000000..dff1bf39 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/hourly_wh.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/ic_launcher_app.webp b/moduleUtil/src/main/res/mipmap-xxhdpi/ic_launcher_app.webp new file mode 100644 index 00000000..7849d4b3 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/ic_launcher_app.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/ic_room_huangguan.webp b/moduleUtil/src/main/res/mipmap-xxhdpi/ic_room_huangguan.webp new file mode 100644 index 00000000..5fa331b2 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/ic_room_huangguan.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/ic_room_xq_wno_female.webp b/moduleUtil/src/main/res/mipmap-xxhdpi/ic_room_xq_wno_female.webp new file mode 100644 index 00000000..58804bca Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/ic_room_xq_wno_female.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/ic_room_xq_wno_male.webp b/moduleUtil/src/main/res/mipmap-xxhdpi/ic_room_xq_wno_male.webp new file mode 100644 index 00000000..01069739 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/ic_room_xq_wno_male.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/room_ic_owner_offline.webp b/moduleUtil/src/main/res/mipmap-xxhdpi/room_ic_owner_offline.webp new file mode 100644 index 00000000..d645a27d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/room_ic_owner_offline.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxhdpi/zyx.png b/moduleUtil/src/main/res/mipmap-xxhdpi/zyx.png new file mode 100644 index 00000000..a0e9f949 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxhdpi/zyx.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/a1img_9.9.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/a1img_9.9.png new file mode 100644 index 00000000..abc75f54 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/a1img_9.9.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/action_js.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/action_js.webp new file mode 100644 index 00000000..a30458a3 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/action_js.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/activity_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/activity_bj.webp new file mode 100644 index 00000000..c2d9fe9b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/activity_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/app_name_bg.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/app_name_bg.webp new file mode 100644 index 00000000..a952911d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/app_name_bg.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/auction.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction.webp new file mode 100644 index 00000000..5edc9eab Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_1.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_1.webp new file mode 100644 index 00000000..ebaf0615 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_1.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_2.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_2.webp new file mode 100644 index 00000000..a3101467 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_2.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_3.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_3.webp new file mode 100644 index 00000000..e688a168 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_3.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_bj1.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_bj1.webp new file mode 100644 index 00000000..eec53932 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_bj1.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_bj2.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_bj2.webp new file mode 100644 index 00000000..cccf29a1 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_bj2.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_bj3.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_bj3.webp new file mode 100644 index 00000000..fd77580d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_bj3.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_cg.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_cg.webp new file mode 100644 index 00000000..cafc32f3 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_cg.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_jt.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_jt.webp new file mode 100644 index 00000000..4585f42a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_jt.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_sb.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_sb.webp new file mode 100644 index 00000000..65086f4e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_sb.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_za.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_za.webp new file mode 100644 index 00000000..60eefdee Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/auction_za.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/bangdan.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/bangdan.webp new file mode 100644 index 00000000..818630c1 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/bangdan.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/bangdan3.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/bangdan3.webp new file mode 100644 index 00000000..2b3bf05a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/bangdan3.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/bangdan4.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/bangdan4.webp new file mode 100644 index 00000000..9d7f5cf5 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/bangdan4.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/become.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/become.webp new file mode 100644 index 00000000..55c5a95a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/become.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/bg_wz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/bg_wz.webp new file mode 100644 index 00000000..0fe5aa56 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/bg_wz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/bj.webp new file mode 100644 index 00000000..3019eb27 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/but_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/but_bj.webp new file mode 100644 index 00000000..dfee162c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/but_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/cabin_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/cabin_bj.webp new file mode 100644 index 00000000..53f67b9b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/cabin_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/cancel.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/cancel.webp new file mode 100644 index 00000000..b9228a62 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/cancel.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/changpian.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/changpian.webp new file mode 100644 index 00000000..289ff838 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/changpian.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/check_boy.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/check_boy.webp new file mode 100644 index 00000000..dfb80355 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/check_boy.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/check_boy1.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/check_boy1.webp new file mode 100644 index 00000000..bce15728 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/check_boy1.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/check_girl.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/check_girl.webp new file mode 100644 index 00000000..e2ba2bb7 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/check_girl.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/check_girl1.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/check_girl1.webp new file mode 100644 index 00000000..842e888e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/check_girl1.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/chou_w.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/chou_w.webp new file mode 100644 index 00000000..b0e2fa8d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/chou_w.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/chou_x.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/chou_x.webp new file mode 100644 index 00000000..b0aa5846 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/chou_x.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/clogs_car.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/clogs_car.webp new file mode 100644 index 00000000..875f2d71 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/clogs_car.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/collect.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/collect.webp new file mode 100644 index 00000000..c4c3aadd Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/collect.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/collected.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/collected.webp new file mode 100644 index 00000000..0ed830da Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/collected.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/common_et_clear_icon.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/common_et_clear_icon.png new file mode 100644 index 00000000..3eeefacc Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/common_et_clear_icon.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/common_switch_login_icon.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/common_switch_login_icon.webp new file mode 100644 index 00000000..c7480337 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/common_switch_login_icon.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/concern_dialog.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/concern_dialog.webp new file mode 100644 index 00000000..031026e8 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/concern_dialog.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/copy.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/copy.webp new file mode 100644 index 00000000..6a1a85b1 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/copy.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/cp_room_tb.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/cp_room_tb.webp new file mode 100644 index 00000000..d59192ca Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/cp_room_tb.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/cr_album.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/cr_album.webp new file mode 100644 index 00000000..1a674e4d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/cr_album.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/create_album.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/create_album.webp new file mode 100644 index 00000000..225766e0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/create_album.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/cz_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/cz_bj.webp new file mode 100644 index 00000000..66d193de Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/cz_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/dashu.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/dashu.webp new file mode 100644 index 00000000..12a0f88f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/dashu.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/dele_foot.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/dele_foot.webp new file mode 100644 index 00000000..f326809a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/dele_foot.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/dengj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/dengj.webp new file mode 100644 index 00000000..1189c8ff Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/dengj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/dengt.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/dengt.webp new file mode 100644 index 00000000..f624729a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/dengt.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/diany.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/diany.webp new file mode 100644 index 00000000..a9cb0517 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/diany.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/dianyf.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/dianyf.webp new file mode 100644 index 00000000..7e60b10c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/dianyf.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/dongtai_hudong_dianzan.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/dongtai_hudong_dianzan.webp new file mode 100644 index 00000000..1cb80c50 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/dongtai_hudong_dianzan.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/dongtai_hudong_pinglun.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/dongtai_hudong_pinglun.webp new file mode 100644 index 00000000..08b961ad Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/dongtai_hudong_pinglun.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/dongtai_hudong_yidianzan.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/dongtai_hudong_yidianzan.webp new file mode 100644 index 00000000..b242ee1d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/dongtai_hudong_yidianzan.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/f_h.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/f_h.webp new file mode 100644 index 00000000..b74ef255 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/f_h.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/fail.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/fail.webp new file mode 100644 index 00000000..dd8ad198 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/fail.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/fangz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/fangz.webp new file mode 100644 index 00000000..59faaf67 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/fangz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/firsh_bj.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/firsh_bj.png new file mode 100644 index 00000000..3fdac73e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/firsh_bj.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/frb_bg.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/frb_bg.webp new file mode 100644 index 00000000..ac968447 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/frb_bg.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gg.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gg.webp new file mode 100644 index 00000000..ee52746f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gg.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_bj.webp new file mode 100644 index 00000000..c628282c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_mh.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_mh.webp new file mode 100644 index 00000000..79d98890 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_mh.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_name_skzd.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_name_skzd.webp new file mode 100644 index 00000000..bb85a639 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_name_skzd.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_name_syzc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_name_syzc.webp new file mode 100644 index 00000000..040838b6 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_name_syzc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_name_tkzj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_name_tkzj.webp new file mode 100644 index 00000000..43d21726 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_name_tkzj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_p_b.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_p_b.webp new file mode 100644 index 00000000..7d7c2ece Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_p_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_sjzd.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_sjzd.webp new file mode 100644 index 00000000..eec4af4d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_sjzd.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_syzc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_syzc.webp new file mode 100644 index 00000000..dfe9f091 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_syzc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_tkzj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_tkzj.webp new file mode 100644 index 00000000..c6538d39 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_tkzj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_wf.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_wf.webp new file mode 100644 index 00000000..244b99d7 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gift_wf.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gly.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gly.webp new file mode 100644 index 00000000..1dc62ed5 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gly.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/go_cz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/go_cz.webp new file mode 100644 index 00000000..956deec1 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/go_cz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/go_lock.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/go_lock.webp new file mode 100644 index 00000000..b3e9cd0f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/go_lock.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/go_sl.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/go_sl.webp new file mode 100644 index 00000000..28218bfc Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/go_sl.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/go_wc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/go_wc.webp new file mode 100644 index 00000000..79c7010d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/go_wc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/go_yq.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/go_yq.webp new file mode 100644 index 00000000..985175b9 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/go_yq.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gongxiang.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gongxiang.webp new file mode 100644 index 00000000..dc2ba12f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gongxiang.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gsui.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gsui.webp new file mode 100644 index 00000000..86bebf1a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gsui.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/guanx.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/guanx.webp new file mode 100644 index 00000000..11bd9646 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/guanx.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/guanxiw_z.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/guanxiw_z.webp new file mode 100644 index 00000000..1c0a5980 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/guanxiw_z.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gux_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gux_bj.webp new file mode 100644 index 00000000..7dd2e722 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gux_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/guxi_k.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/guxi_k.webp new file mode 100644 index 00000000..c4937018 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/guxi_k.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/guxi_w.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/guxi_w.webp new file mode 100644 index 00000000..01ca56fb Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/guxi_w.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gx_xz_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gx_xz_bj.webp new file mode 100644 index 00000000..c9cbbf0b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gx_xz_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/gz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/gz.webp new file mode 100644 index 00000000..e111ba06 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/gz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/h_bj_b.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/h_bj_b.webp new file mode 100644 index 00000000..2f292a74 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/h_bj_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/heab_t.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/heab_t.webp new file mode 100644 index 00000000..4af1ceb7 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/heab_t.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/head_cc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/head_cc.webp new file mode 100644 index 00000000..9cfc7257 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/head_cc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/headline_b.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/headline_b.webp new file mode 100644 index 00000000..f1a97e0b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/headline_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/headline_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/headline_bj.webp new file mode 100644 index 00000000..bb3573b5 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/headline_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/heave_b.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/heave_b.webp new file mode 100644 index 00000000..b84fbedf Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/heave_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/heaven_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/heaven_bj.webp new file mode 100644 index 00000000..03262c1b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/heaven_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/hg.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/hg.webp new file mode 100644 index 00000000..d0c4287e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/hg.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/home_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/home_bj.webp new file mode 100644 index 00000000..8f7d78ea Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/home_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/home_gg.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/home_gg.png new file mode 100644 index 00000000..0b807d74 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/home_gg.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/home_phb.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/home_phb.webp new file mode 100644 index 00000000..2ab555ec Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/home_phb.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/home_rm.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/home_rm.png new file mode 100644 index 00000000..cb6d6c3c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/home_rm.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/home_xx.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/home_xx.png new file mode 100644 index 00000000..90703037 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/home_xx.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/hourl_top1.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/hourl_top1.webp new file mode 100644 index 00000000..f4a43622 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/hourl_top1.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/hourl_top2.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/hourl_top2.webp new file mode 100644 index 00000000..b01dab61 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/hourl_top2.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/hourl_top3.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/hourl_top3.webp new file mode 100644 index 00000000..e68d1a9a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/hourl_top3.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_home_rank.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_home_rank.webp new file mode 100644 index 00000000..c544a856 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_home_rank.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_launcher_app.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_launcher_app.webp new file mode 100644 index 00000000..c0315c91 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_launcher_app.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_paidui_home.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_paidui_home.webp new file mode 100644 index 00000000..4b67ea34 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_paidui_home.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_question_mark.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_question_mark.webp new file mode 100644 index 00000000..6b5e021c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_question_mark.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_topbar_back_dark.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_topbar_back_dark.webp new file mode 100644 index 00000000..7aac55e1 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/ic_topbar_back_dark.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_login_code.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_login_code.webp new file mode 100644 index 00000000..5db27fc4 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_login_code.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_login_lick.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_login_lick.webp new file mode 100644 index 00000000..9d31198b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_login_lick.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_login_user_new.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_login_user_new.webp new file mode 100644 index 00000000..347cc2e8 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_login_user_new.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_me_trend_select.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_me_trend_select.webp new file mode 100644 index 00000000..a6637fdd Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_me_trend_select.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_me_trend_unselect.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_me_trend_unselect.webp new file mode 100644 index 00000000..349e97a9 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_me_trend_unselect.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_my_select.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_my_select.webp new file mode 100644 index 00000000..15423695 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_my_select.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_my_un_select.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_my_un_select.webp new file mode 100644 index 00000000..5000a9eb Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_my_un_select.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_news_select.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_news_select.webp new file mode 100644 index 00000000..25768a61 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_news_select.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_news_un_select.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_news_un_select.webp new file mode 100644 index 00000000..35f680cd Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/icon_news_un_select.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/im_delete.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/im_delete.webp new file mode 100644 index 00000000..ea57092d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/im_delete.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/im_share.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/im_share.webp new file mode 100644 index 00000000..b5d2694b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/im_share.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/im_transfer.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/im_transfer.webp new file mode 100644 index 00000000..8581d276 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/im_transfer.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/im_zs.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/im_zs.webp new file mode 100644 index 00000000..e13530ce Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/im_zs.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/imh_app_update.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/imh_app_update.webp new file mode 100644 index 00000000..acf0e0e2 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/imh_app_update.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/index_close_youth.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/index_close_youth.png new file mode 100644 index 00000000..278f3182 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/index_close_youth.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/index_icon_search.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/index_icon_search.png new file mode 100644 index 00000000..7f222921 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/index_icon_search.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/index_img_room_mask.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/index_img_room_mask.png new file mode 100644 index 00000000..cf146e60 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/index_img_room_mask.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/index_level_search_o.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/index_level_search_o.webp new file mode 100644 index 00000000..9734a821 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/index_level_search_o.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/index_youth.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/index_youth.webp new file mode 100644 index 00000000..af24f6c9 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/index_youth.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/invite_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/invite_bj.webp new file mode 100644 index 00000000..27cb815d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/invite_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/invite_k.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/invite_k.webp new file mode 100644 index 00000000..336b5dc8 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/invite_k.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/invite_tx.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/invite_tx.webp new file mode 100644 index 00000000..0251c1f4 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/invite_tx.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jb.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jb.webp new file mode 100644 index 00000000..cd12a3ea Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jb.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiangc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiangc.webp new file mode 100644 index 00000000..4a13bb4b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiangc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_k_l.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_k_l.webp new file mode 100644 index 00000000..37a3a2d5 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_k_l.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_k_r.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_k_r.webp new file mode 100644 index 00000000..2154ed6f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_k_r.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_kgx.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_kgx.webp new file mode 100644 index 00000000..a1aad020 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_kgx.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_p1.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_p1.webp new file mode 100644 index 00000000..d96a0c33 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_p1.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_p2.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_p2.webp new file mode 100644 index 00000000..b506e34b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiao_p2.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_bj.webp new file mode 100644 index 00000000..95e46080 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_djs.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_djs.webp new file mode 100644 index 00000000..251fc02d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_djs.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_js.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_js.webp new file mode 100644 index 00000000..af580280 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_js.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_ks.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_ks.png new file mode 100644 index 00000000..6d9f64f2 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_ks.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_n.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_n.webp new file mode 100644 index 00000000..9b029c83 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_n.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_tv_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_tv_bj.webp new file mode 100644 index 00000000..2f5fd4b8 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_tv_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_x.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_x.webp new file mode 100644 index 00000000..0e9902b6 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_x.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_xian.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_xian.webp new file mode 100644 index 00000000..0209677d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_xian.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_yc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_yc.webp new file mode 100644 index 00000000..13070563 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiaoy_yc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jijang.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jijang.webp new file mode 100644 index 00000000..04cfe68b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jijang.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jiks.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiks.png new file mode 100644 index 00000000..6e8ff70b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jiks.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jilu.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jilu.webp new file mode 100644 index 00000000..50137360 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jilu.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jinb_tg.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jinb_tg.webp new file mode 100644 index 00000000..12b2e89f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jinb_tg.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jt_right.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jt_right.webp new file mode 100644 index 00000000..341d5269 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jt_right.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jub.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/jub.webp new file mode 100644 index 00000000..c3bf738f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jub.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/jxz.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/jxz.png new file mode 100644 index 00000000..f7185e21 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/jxz.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/kagx.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/kagx.webp new file mode 100644 index 00000000..c4cec0b5 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/kagx.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/ke_bg.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/ke_bg.png new file mode 100644 index 00000000..261800f6 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/ke_bg.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/ktv.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/ktv.webp new file mode 100644 index 00000000..1b383a78 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/ktv.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/laoren.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/laoren.webp new file mode 100644 index 00000000..a39a62d4 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/laoren.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/liang.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/liang.webp new file mode 100644 index 00000000..5ee2b37e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/liang.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/lianj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/lianj.webp new file mode 100644 index 00000000..cce9e08d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/lianj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/line9.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/line9.webp new file mode 100644 index 00000000..54ef84e2 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/line9.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/liwu.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/liwu.webp new file mode 100644 index 00000000..be62c908 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/liwu.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/lock.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/lock.webp new file mode 100644 index 00000000..bd69e94d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/lock.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/log_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/log_bj.webp new file mode 100644 index 00000000..9d5f9333 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/log_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/login_btn_bg.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/login_btn_bg.webp new file mode 100644 index 00000000..b524c499 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/login_btn_bg.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/login_log.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/login_log.webp new file mode 100644 index 00000000..8175b1ea Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/login_log.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/login_title.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/login_title.webp new file mode 100644 index 00000000..76799570 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/login_title.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/me_edit.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_edit.webp new file mode 100644 index 00000000..b79e252d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_edit.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/me_my_bag.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_my_bag.webp new file mode 100644 index 00000000..e5698b10 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_my_bag.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/me_show_store.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_show_store.webp new file mode 100644 index 00000000..209a73f6 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_show_store.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/me_test.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_test.webp new file mode 100644 index 00000000..08de7ab4 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_test.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/me_union_icon.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_union_icon.webp new file mode 100644 index 00000000..400697eb Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_union_icon.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/me_wallet.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_wallet.webp new file mode 100644 index 00000000..4d37de33 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_wallet.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/me_wallet_icon.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_wallet_icon.webp new file mode 100644 index 00000000..fe1f5e90 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/me_wallet_icon.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/mess.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/mess.webp new file mode 100644 index 00000000..e76953dd Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/mess.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/mony_cz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/mony_cz.webp new file mode 100644 index 00000000..5b355957 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/mony_cz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/mony_tx.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/mony_tx.webp new file mode 100644 index 00000000..23a13b6f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/mony_tx.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/mu_yc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/mu_yc.webp new file mode 100644 index 00000000..7c417722 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/mu_yc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/muis_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/muis_bj.webp new file mode 100644 index 00000000..76506a79 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/muis_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/mx.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/mx.webp new file mode 100644 index 00000000..ff949f9b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/mx.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/my_bag_item.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/my_bag_item.webp new file mode 100644 index 00000000..cba558b0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/my_bag_item.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/my_dan.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/my_dan.webp new file mode 100644 index 00000000..d428212f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/my_dan.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/my_home.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/my_home.webp new file mode 100644 index 00000000..730a924e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/my_home.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/nan.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/nan.webp new file mode 100644 index 00000000..866d3d8c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/nan.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/new_people_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/new_people_bj.webp new file mode 100644 index 00000000..d8fc7169 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/new_people_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/no_follow.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/no_follow.webp new file mode 100644 index 00000000..1c7d873d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/no_follow.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/not_liang.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/not_liang.webp new file mode 100644 index 00000000..1e09ab4a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/not_liang.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/not_unlocked.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/not_unlocked.webp new file mode 100644 index 00000000..aa446544 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/not_unlocked.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/notifi.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/notifi.webp new file mode 100644 index 00000000..3da47995 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/notifi.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/num_1.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/num_1.webp new file mode 100644 index 00000000..ef97d4b7 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/num_1.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/num_11.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/num_11.webp new file mode 100644 index 00000000..3f951d58 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/num_11.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/num_2.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/num_2.webp new file mode 100644 index 00000000..c6fed70b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/num_2.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/num_22.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/num_22.webp new file mode 100644 index 00000000..efea944c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/num_22.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/nv.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/nv.webp new file mode 100644 index 00000000..dd55717b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/nv.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/nvhai.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/nvhai.webp new file mode 100644 index 00000000..033f24b2 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/nvhai.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/paih.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/paih.webp new file mode 100644 index 00000000..d2913890 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/paih.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/paimai.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/paimai.webp new file mode 100644 index 00000000..fac399fe Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/paimai.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/personality.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/personality.webp new file mode 100644 index 00000000..d86ef41a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/personality.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/ping.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/ping.webp new file mode 100644 index 00000000..b97d579b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/ping.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_djs.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_djs.webp new file mode 100644 index 00000000..263333f8 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_djs.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_left.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_left.webp new file mode 100644 index 00000000..aad55a84 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_left.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_pj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_pj.webp new file mode 100644 index 00000000..765739cf Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_pj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_right.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_right.webp new file mode 100644 index 00000000..2367df67 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_right.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_sb.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_sb.webp new file mode 100644 index 00000000..1325eb36 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_sb.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_sl.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_sl.webp new file mode 100644 index 00000000..26b36570 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_sl.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_stop.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_stop.webp new file mode 100644 index 00000000..a30458a3 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_stop.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_time_f.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_time_f.webp new file mode 100644 index 00000000..66c601f3 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_time_f.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_time_t.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_time_t.webp new file mode 100644 index 00000000..dd0af59a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_time_t.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_vs.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_vs.webp new file mode 100644 index 00000000..bc28b73b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/pk_vs.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/pp.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/pp.webp new file mode 100644 index 00000000..8e6cbbcd Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/pp.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/qgrml.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/qgrml.webp new file mode 100644 index 00000000..9dd4de0b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/qgrml.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/qipaokang.9.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/qipaokang.9.png new file mode 100644 index 00000000..0950ca89 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/qipaokang.9.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/qm_b.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/qm_b.webp new file mode 100644 index 00000000..3adf2979 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/qm_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/qq.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/qq.webp new file mode 100644 index 00000000..f3b9ac96 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/qq.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/quan.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/quan.webp new file mode 100644 index 00000000..defd3071 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/quan.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/re_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/re_bj.webp new file mode 100644 index 00000000..b0632b19 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/re_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/real_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/real_bj.webp new file mode 100644 index 00000000..b1c55fb7 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/real_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/real_img.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/real_img.webp new file mode 100644 index 00000000..ae4b5932 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/real_img.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/real_q.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/real_q.webp new file mode 100644 index 00000000..cea6852f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/real_q.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/red.webp new file mode 100644 index 00000000..cfd2db08 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_bj.webp new file mode 100644 index 00000000..25c06b8e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red_bj_h.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_bj_h.webp new file mode 100644 index 00000000..ba61aafc Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_bj_h.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red_bott_b.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_bott_b.webp new file mode 100644 index 00000000..0791be61 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_bott_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red_en.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_en.webp new file mode 100644 index 00000000..c011c4ef Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_en.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red_f_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_f_bj.webp new file mode 100644 index 00000000..684d841e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_f_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red_im_bot.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_im_bot.png new file mode 100644 index 00000000..698dc672 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_im_bot.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red_k.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_k.webp new file mode 100644 index 00000000..99b829b9 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_k.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red_k_top.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_k_top.webp new file mode 100644 index 00000000..d6803626 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_k_top.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red_kl_b.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_kl_b.png new file mode 100644 index 00000000..0ee0af4a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_kl_b.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red_liet_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_liet_bj.webp new file mode 100644 index 00000000..af216fdc Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_liet_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red_pp.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_pp.webp new file mode 100644 index 00000000..0ebd0eb9 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_pp.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red_text.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_text.webp new file mode 100644 index 00000000..0b3276e1 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_text.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/red_top_b.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_top_b.webp new file mode 100644 index 00000000..485b7a10 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/red_top_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/regit_t.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/regit_t.webp new file mode 100644 index 00000000..b95bab6a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/regit_t.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/release_n.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/release_n.webp new file mode 100644 index 00000000..3ed7a01d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/release_n.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/ren.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/ren.webp new file mode 100644 index 00000000..cee8c465 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/ren.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/renz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/renz.webp new file mode 100644 index 00000000..ca06ab05 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/renz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/reyi.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/reyi.webp new file mode 100644 index 00000000..0ce226b0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/reyi.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_auction_jp.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_auction_jp.webp new file mode 100644 index 00000000..f6fdd2b1 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_auction_jp.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_bj.webp new file mode 100644 index 00000000..91cf3329 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_bt.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_bt.webp new file mode 100644 index 00000000..b027ccde Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_bt.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_charm_b.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_charm_b.webp new file mode 100644 index 00000000..79a55612 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_charm_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_colse.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_colse.webp new file mode 100644 index 00000000..f10a725c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_colse.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_dialog_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_dialog_bj.webp new file mode 100644 index 00000000..45c92b6b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_dialog_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_dian.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_dian.webp new file mode 100644 index 00000000..fa35a01e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_dian.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gb.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gb.webp new file mode 100644 index 00000000..1467981c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gb.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gift_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gift_bj.webp new file mode 100644 index 00000000..c628282c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gift_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gift_bjx.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gift_bjx.webp new file mode 100644 index 00000000..51ca52a5 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gift_bjx.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gift_select_bg.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gift_select_bg.webp new file mode 100644 index 00000000..bd0004ac Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gift_select_bg.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gz.webp new file mode 100644 index 00000000..84af9343 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_gz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ic_banner_point_normal.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ic_banner_point_normal.webp new file mode 100644 index 00000000..6002a882 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ic_banner_point_normal.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ic_banner_point_select.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ic_banner_point_select.webp new file mode 100644 index 00000000..94306aa9 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ic_banner_point_select.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ic_wheat_default.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ic_wheat_default.png new file mode 100644 index 00000000..d59d2839 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ic_wheat_default.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ic_wheat_default_suo.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ic_wheat_default_suo.webp new file mode 100644 index 00000000..6d12875a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ic_wheat_default_suo.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_jb.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_jb.webp new file mode 100644 index 00000000..08c955bb Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_jb.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_kg.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_kg.webp new file mode 100644 index 00000000..8875e40a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_kg.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_lh.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_lh.webp new file mode 100644 index 00000000..60965d15 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_lh.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_lt.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_lt.webp new file mode 100644 index 00000000..27a3c7f6 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_lt.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_music_win_list.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_music_win_list.webp new file mode 100644 index 00000000..31c4f9ef Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_music_win_list.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_music_win_next.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_music_win_next.webp new file mode 100644 index 00000000..c3c2dffb Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_music_win_next.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_music_win_puase.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_music_win_puase.webp new file mode 100644 index 00000000..ed0f8a4b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_music_win_puase.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_music_win_start.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_music_win_start.webp new file mode 100644 index 00000000..f3d0b6cf Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_music_win_start.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_mx.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_mx.webp new file mode 100644 index 00000000..8dfea5f7 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_mx.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_rank_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_rank_bj.webp new file mode 100644 index 00000000..3447677c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_rank_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_rig_jt.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_rig_jt.webp new file mode 100644 index 00000000..9f475029 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_rig_jt.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_sl.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_sl.webp new file mode 100644 index 00000000..9f1a3d3e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_sl.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_sound_effects.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_sound_effects.webp new file mode 100644 index 00000000..251c076b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_sound_effects.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_t.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_t.webp new file mode 100644 index 00000000..0b50cafb Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_t.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_user_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_user_bj.webp new file mode 100644 index 00000000..3adf2979 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_user_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_wheat_feeding.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_wheat_feeding.webp new file mode 100644 index 00000000..1e956c54 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_wheat_feeding.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_wheat_feeding_up.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_wheat_feeding_up.webp new file mode 100644 index 00000000..e9ede2d6 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_wheat_feeding_up.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_xsb.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_xsb.png new file mode 100644 index 00000000..3ceede08 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_xsb.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ygz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ygz.webp new file mode 100644 index 00000000..fd473b39 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/room_ygz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/sanwei.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/sanwei.webp new file mode 100644 index 00000000..1b0a6c64 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/sanwei.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/sect_false.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/sect_false.webp new file mode 100644 index 00000000..3a42c305 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/sect_false.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/sect_true.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/sect_true.webp new file mode 100644 index 00000000..6ccbe04b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/sect_true.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/setting.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/setting.webp new file mode 100644 index 00000000..86f69071 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/setting.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/setting_t.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/setting_t.webp new file mode 100644 index 00000000..2a019455 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/setting_t.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/shanc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/shanc.webp new file mode 100644 index 00000000..8256a61d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/shanc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/shanchu.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/shanchu.webp new file mode 100644 index 00000000..f50c0d80 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/shanchu.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/shequ_dongtai_gengduo.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/shequ_dongtai_gengduo.webp new file mode 100644 index 00000000..d4e4015d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/shequ_dongtai_gengduo.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/shij.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/shij.webp new file mode 100644 index 00000000..cba0e884 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/shij.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/shouc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/shouc.webp new file mode 100644 index 00000000..8a5d43ad Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/shouc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/shouchl.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/shouchl.webp new file mode 100644 index 00000000..4a20746c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/shouchl.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/shousz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/shousz.webp new file mode 100644 index 00000000..ede77127 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/shousz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/shouyi.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/shouyi.webp new file mode 100644 index 00000000..8d26cfeb Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/shouyi.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/showszc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/showszc.webp new file mode 100644 index 00000000..541ee95e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/showszc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/sign_icon_wechat.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/sign_icon_wechat.webp new file mode 100644 index 00000000..fe8b9013 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/sign_icon_wechat.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/sign_icon_wechat_q.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/sign_icon_wechat_q.webp new file mode 100644 index 00000000..fbe8ecb7 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/sign_icon_wechat_q.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/sign_icon_zfb.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/sign_icon_zfb.webp new file mode 100644 index 00000000..e2862f7d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/sign_icon_zfb.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/six.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/six.webp new file mode 100644 index 00000000..07b28ae5 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/six.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_bj.webp new file mode 100644 index 00000000..f8d593df Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_left_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_left_bj.webp new file mode 100644 index 00000000..d5d7ccba Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_left_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_rigth_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_rigth_bj.webp new file mode 100644 index 00000000..0ab9ae11 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_rigth_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_w.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_w.webp new file mode 100644 index 00000000..564c4259 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_w.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_x.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_x.webp new file mode 100644 index 00000000..cc806e17 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzd_x.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/skzj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzj.webp new file mode 100644 index 00000000..dc70661c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/skzj_gz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzj_gz.webp new file mode 100644 index 00000000..1a9cfaad Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzj_gz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/skzj_z_b.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzj_z_b.webp new file mode 100644 index 00000000..8f7d7d6d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzj_z_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/skzl_jc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzl_jc.webp new file mode 100644 index 00000000..93433487 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzl_jc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/skzl_jl.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzl_jl.webp new file mode 100644 index 00000000..f6291869 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/skzl_jl.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/suij.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/suij.webp new file mode 100644 index 00000000..177bc89d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/suij.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/suo.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/suo.webp new file mode 100644 index 00000000..41f580e5 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/suo.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/suound_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/suound_bj.webp new file mode 100644 index 00000000..0d08ad47 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/suound_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/suound_bjs.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/suound_bjs.webp new file mode 100644 index 00000000..19d8459c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/suound_bjs.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/sure.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/sure.webp new file mode 100644 index 00000000..86217d8b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/sure.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc.webp new file mode 100644 index 00000000..06af9abc Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_bj.webp new file mode 100644 index 00000000..e27fda4c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_gz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_gz.webp new file mode 100644 index 00000000..2d80d856 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_gz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_jc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_jc.webp new file mode 100644 index 00000000..640140fb Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_jc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_jl.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_jl.webp new file mode 100644 index 00000000..ef8996f1 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_jl.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_left_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_left_bj.webp new file mode 100644 index 00000000..0da9b78c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_left_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_rigth_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_rigth_bj.webp new file mode 100644 index 00000000..b1a7bdcf Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_rigth_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_w.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_w.webp new file mode 100644 index 00000000..5110cb5d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_w.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_x.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_x.webp new file mode 100644 index 00000000..9a08b477 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_x.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_z_b.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_z_b.webp new file mode 100644 index 00000000..7959a1bd Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/syzc_z_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tab_dy.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tab_dy.webp new file mode 100644 index 00000000..9102569d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tab_dy.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tab_main_media_selected.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tab_main_media_selected.webp new file mode 100644 index 00000000..29a4483d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tab_main_media_selected.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tab_main_media_unselected.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tab_main_media_unselected.webp new file mode 100644 index 00000000..2d65556f Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tab_main_media_unselected.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tab_x.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tab_x.webp new file mode 100644 index 00000000..9d2b7c5d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tab_x.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/task_cj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/task_cj.webp new file mode 100644 index 00000000..1315c87b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/task_cj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/task_gj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/task_gj.webp new file mode 100644 index 00000000..723922e0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/task_gj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/task_gz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/task_gz.webp new file mode 100644 index 00000000..10cbc807 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/task_gz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/task_lock.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/task_lock.webp new file mode 100644 index 00000000..c4852c8e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/task_lock.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/task_t.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/task_t.webp new file mode 100644 index 00000000..5c5371f4 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/task_t.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tianjhl.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tianjhl.webp new file mode 100644 index 00000000..08b52b5d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tianjhl.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/time_b.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/time_b.webp new file mode 100644 index 00000000..79e85080 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/time_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tk_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tk_bj.webp new file mode 100644 index 00000000..0744ae2d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tk_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzi_rigth_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzi_rigth_bj.webp new file mode 100644 index 00000000..5e7faaf5 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzi_rigth_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj.webp new file mode 100644 index 00000000..cd6dd28b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_bj.webp new file mode 100644 index 00000000..afe150e3 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_gz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_gz.webp new file mode 100644 index 00000000..d8c34662 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_gz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_left_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_left_bj.webp new file mode 100644 index 00000000..390ff4f7 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_left_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_w.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_w.webp new file mode 100644 index 00000000..51352986 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_w.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_x.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_x.webp new file mode 100644 index 00000000..872b78ac Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_x.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_z.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_z.webp new file mode 100644 index 00000000..76d2e1fd Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_z.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_z_b.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_z_b.webp new file mode 100644 index 00000000..70c9876c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tkzj_z_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tour_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tour_bj.webp new file mode 100644 index 00000000..ff54a7eb Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tour_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tour_zj_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tour_zj_bj.webp new file mode 100644 index 00000000..a39af3ef Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tour_zj_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tt_c.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tt_c.webp new file mode 100644 index 00000000..12af8619 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tt_c.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tt_q.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tt_q.webp new file mode 100644 index 00000000..7bf025a2 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tt_q.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tt_yc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tt_yc.webp new file mode 100644 index 00000000..471ed970 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tt_yc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/tx_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/tx_bj.webp new file mode 100644 index 00000000..bc190f45 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/tx_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/unlocked.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/unlocked.webp new file mode 100644 index 00000000..29b4b62b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/unlocked.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/up_t.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/up_t.webp new file mode 100644 index 00000000..6586d052 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/up_t.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/up_x.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/up_x.webp new file mode 100644 index 00000000..44a90f67 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/up_x.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/user_wait_header.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/user_wait_header.webp new file mode 100644 index 00000000..4ebd9be0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/user_wait_header.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/victory.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/victory.webp new file mode 100644 index 00000000..d33bd74b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/victory.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/wheat_consent.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/wheat_consent.webp new file mode 100644 index 00000000..235efc57 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/wheat_consent.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/wheat_refuse.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/wheat_refuse.webp new file mode 100644 index 00000000..89edc558 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/wheat_refuse.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/wx.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/wx.webp new file mode 100644 index 00000000..4f2734f4 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/wx.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/wx_zf.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/wx_zf.webp new file mode 100644 index 00000000..6c0de896 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/wx_zf.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xiaohei_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xiaohei_bj.webp new file mode 100644 index 00000000..2a5689ca Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xiaohei_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xiaox_b.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xiaox_b.webp new file mode 100644 index 00000000..3af35bf5 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xiaox_b.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xiaox_bq.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/xiaox_bq.png new file mode 100644 index 00000000..d5954974 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xiaox_bq.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xinr.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xinr.webp new file mode 100644 index 00000000..2b4f79a8 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xinr.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xinrhl.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xinrhl.webp new file mode 100644 index 00000000..0a4ebde8 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xinrhl.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh.webp new file mode 100644 index 00000000..e89bdacb Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_bd.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_bd.webp new file mode 100644 index 00000000..bd7133eb Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_bd.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_cj_item.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_cj_item.webp new file mode 100644 index 00000000..264a3b93 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_cj_item.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_cj_w.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_cj_w.webp new file mode 100644 index 00000000..b0030dd9 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_cj_w.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_g_2.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_g_2.webp new file mode 100644 index 00000000..69320e62 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_g_2.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_gb.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_gb.webp new file mode 100644 index 00000000..94454f12 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_gb.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_gift_user.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_gift_user.webp new file mode 100644 index 00000000..30001228 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_gift_user.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_gz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_gz.webp new file mode 100644 index 00000000..5a60ebb8 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_gz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_hd.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_hd.webp new file mode 100644 index 00000000..d63edac6 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_hd.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_image.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_image.webp new file mode 100644 index 00000000..b455740a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_image.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_jc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_jc.webp new file mode 100644 index 00000000..1aa64b34 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_jc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_jjks.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_jjks.webp new file mode 100644 index 00000000..cee22de9 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_jjks.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_jl.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_jl.webp new file mode 100644 index 00000000..50137360 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_jl.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_num.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_num.webp new file mode 100644 index 00000000..070afb5a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_num.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_ob.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_ob.webp new file mode 100644 index 00000000..1b8887f8 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_ob.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_rk_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_rk_bj.webp new file mode 100644 index 00000000..99889a0b Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_rk_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_xj_x.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_xj_x.webp new file mode 100644 index 00000000..b30ef5c0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_xj_x.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_xz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_xz.webp new file mode 100644 index 00000000..04e6f2e9 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_xz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_zl.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_zl.webp new file mode 100644 index 00000000..8fab8929 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_zl.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_zsks.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_zsks.webp new file mode 100644 index 00000000..459306b7 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlh_zsks.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xlhxd.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlhxd.png new file mode 100644 index 00000000..ab3a55f2 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xlhxd.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xr_ykj.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/xr_ykj.png new file mode 100644 index 00000000..e7cc646d Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xr_ykj.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xr_ykj_xz.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/xr_ykj_xz.png new file mode 100644 index 00000000..3d129abb Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xr_ykj_xz.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xt.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xt.webp new file mode 100644 index 00000000..ab834ed1 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xt.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/xuni.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/xuni.webp new file mode 100644 index 00000000..034a2f00 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/xuni.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/y_w.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/y_w.webp new file mode 100644 index 00000000..192cf3d8 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/y_w.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/y_won.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/y_won.webp new file mode 100644 index 00000000..533810a6 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/y_won.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/yic.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/yic.webp new file mode 100644 index 00000000..9a523315 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/yic.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/yigz.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/yigz.webp new file mode 100644 index 00000000..2e188b85 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/yigz.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/yishouc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/yishouc.webp new file mode 100644 index 00000000..0ed830da Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/yishouc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/ylq.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/ylq.webp new file mode 100644 index 00000000..7fd4f7d0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/ylq.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/yq_pk.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/yq_pk.webp new file mode 100644 index 00000000..6557646e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/yq_pk.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/yuansheng.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/yuansheng.webp new file mode 100644 index 00000000..a8c274fb Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/yuansheng.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/yujie.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/yujie.webp new file mode 100644 index 00000000..d2cadf77 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/yujie.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/za_bj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_bj.webp new file mode 100644 index 00000000..8ddf1aad Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_bj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/za_ljjp.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_ljjp.webp new file mode 100644 index 00000000..79712dd3 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_ljjp.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/za_m.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_m.webp new file mode 100644 index 00000000..5ba2ef23 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_m.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/za_maiw.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_maiw.webp new file mode 100644 index 00000000..7be20d17 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_maiw.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/za_maiw_b.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_maiw_b.png new file mode 100644 index 00000000..8036144e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_maiw_b.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/za_maiw_o.png b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_maiw_o.png new file mode 100644 index 00000000..988c3d18 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_maiw_o.png differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/za_p.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_p.webp new file mode 100644 index 00000000..43c7014a Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_p.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/za_s.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_s.webp new file mode 100644 index 00000000..e747ce50 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_s.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/za_t.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_t.webp new file mode 100644 index 00000000..893f253c Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/za_t.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/zc.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/zc.webp new file mode 100644 index 00000000..d3a80df0 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/zc.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/zhaop.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/zhaop.webp new file mode 100644 index 00000000..9011e26e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/zhaop.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/zhensgh.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/zhensgh.webp new file mode 100644 index 00000000..c039642e Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/zhensgh.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/zhid.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/zhid.webp new file mode 100644 index 00000000..0fa24ed2 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/zhid.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/zs.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/zs.webp new file mode 100644 index 00000000..5fd2f553 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/zs.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/zs_tb.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/zs_tb.webp new file mode 100644 index 00000000..ebffa171 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/zs_tb.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/zubj.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/zubj.webp new file mode 100644 index 00000000..481cd1d1 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/zubj.webp differ diff --git a/moduleUtil/src/main/res/mipmap-xxxhdpi/zus_tg.webp b/moduleUtil/src/main/res/mipmap-xxxhdpi/zus_tg.webp new file mode 100644 index 00000000..24bd6f99 Binary files /dev/null and b/moduleUtil/src/main/res/mipmap-xxxhdpi/zus_tg.webp differ diff --git a/moduleUtil/src/main/res/raw/red_packet_come.MP3 b/moduleUtil/src/main/res/raw/red_packet_come.MP3 new file mode 100644 index 00000000..88db62da Binary files /dev/null and b/moduleUtil/src/main/res/raw/red_packet_come.MP3 differ diff --git a/moduleUtil/src/main/res/values-v23/themes.xml b/moduleUtil/src/main/res/values-v23/themes.xml new file mode 100644 index 00000000..5f66de92 --- /dev/null +++ b/moduleUtil/src/main/res/values-v23/themes.xml @@ -0,0 +1,25 @@ + + + + + + \ No newline at end of file diff --git a/moduleroom/src/main/java/com/example/moduleroom/activity/RedResultActivity.java b/moduleroom/src/main/java/com/example/moduleroom/activity/RedResultActivity.java new file mode 100644 index 00000000..a01a3023 --- /dev/null +++ b/moduleroom/src/main/java/com/example/moduleroom/activity/RedResultActivity.java @@ -0,0 +1,113 @@ +package com.example.moduleroom.activity; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import com.alibaba.android.arouter.facade.annotation.Autowired; +import com.alibaba.android.arouter.facade.annotation.Route; +import com.example.moduleroom.R; +import com.example.moduleroom.adapter.RedAdapter; +import com.example.moduleroom.contacts.RedEnvelopesContacts; +import com.example.moduleroom.databinding.FragmentRedBinding; +import com.example.moduleroom.fragment.RedViewModel; +import com.example.moduleroom.presenter.RedEnvelopesPresenter; +import com.scwang.smartrefresh.layout.api.RefreshLayout; +import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener; +import com.xscm.moduleutil.activity.BaseMvpActivity; +import com.xscm.moduleutil.base.BaseMvpFragment; +import com.xscm.moduleutil.bean.RedpacketDetail; +import com.xscm.moduleutil.utils.ARouteConstants; +import com.xscm.moduleutil.utils.ImageUtils; +import org.jetbrains.annotations.NotNull; + +/** + * @author qx + * @data 2025/9/29 + * @description:红包最终的展示页面 + */ +@Route(path = ARouteConstants.ROOM_RED_RESULT) +public class RedResultActivity extends BaseMvpActivity implements RedEnvelopesContacts.View { + + private RedViewModel mViewModel; + private RedAdapter redAdapter; + private int page = 1; + private String redpacketId; + +// public static RedResultActivity newInstance() { +// return new RedResultActivity(); +// } + + + + @Override + protected void initData() { + redpacketId = getIntent().getStringExtra("redpacketId"); + if (redpacketId == null || redpacketId.isEmpty()) { + // 处理红包ID为空的情况 + return; + } + if (MvpPre==null){ + MvpPre = new RedEnvelopesPresenter(this, this); + } + MvpPre.getRedpacketDetail(redpacketId); + } + + @Override + protected RedEnvelopesPresenter bindPresenter() { + return new RedEnvelopesPresenter(this, this); + } + + @Override + protected void initView() { + mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this)); + redAdapter = new RedAdapter(); + mBinding.recyclerView.setAdapter(redAdapter); + // 确保最后一项完全可见 + mBinding.recyclerView.setClipToPadding(false); + mBinding.recyclerView.setPadding( + 0, + getResources().getDimensionPixelSize(com.xscm.moduleutil.R.dimen.dp_12), + 0, + getResources().getDimensionPixelSize(com.xscm.moduleutil.R.dimen.dp_12) + ); + mBinding.smartRefreshLayout.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + + @Override + public void onRefresh(@NonNull @NotNull RefreshLayout refreshLayout) { + page = 1; +// MvpPre.getRoomHourRanking(page+"", "20"); + } + + @Override + public void onLoadMore(@NonNull @NotNull RefreshLayout refreshLayout) { + page++; +// MvpPre.getRoomHourRanking(page+"", "20"); + } + }); + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_red; + } + + @Override + public void redPacketDetail(RedpacketDetail redpacketDetail) { + // 检查 Activity 是否已经销毁 + if (isFinishing() || isDestroyed()) { + return; + } + if (redpacketDetail != null) { + ImageUtils.loadHeadCC(redpacketDetail.getRedpacket_info().getAvatar(), mBinding.userAvatar); + mBinding.userName.setText(redpacketDetail.getRedpacket_info().getNickname()); + mBinding.tvRedTitle.setText(redpacketDetail.getRedpacket_info().getRemark()); + mBinding.tvJb.setText(redpacketDetail.getRedpacket_info().getCoin_type() == 1 ? "金币" : "钻石"); + if (redpacketDetail.getMy_record() != null) { + mBinding.tvRedJb.setText(redpacketDetail.getMy_record().getAmount()); + }else { + mBinding.tvRedJb.setText("0.00"); + } + mBinding.tvLq.setText("已领取"+redpacketDetail.getRecords().size() + "/" + redpacketDetail.getRedpacket_info().getTotal_count()); + redAdapter.setNewData(redpacketDetail.getRecords()); + } + } +} \ No newline at end of file diff --git a/moduleroom/src/main/java/com/example/moduleroom/activity/RoomActivity.kt b/moduleroom/src/main/java/com/example/moduleroom/activity/RoomActivity.kt new file mode 100644 index 00000000..df7a3a0c --- /dev/null +++ b/moduleroom/src/main/java/com/example/moduleroom/activity/RoomActivity.kt @@ -0,0 +1,4516 @@ +package com.example.moduleroom.activity + +import android.Manifest +import android.annotation.SuppressLint +import android.app.ActivityManager +import android.app.AlertDialog +import android.content.Context +import android.content.DialogInterface +import android.content.Intent +import android.content.pm.ActivityInfo +import android.content.res.Configuration +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.* +import android.text.Spannable +import android.text.SpannableStringBuilder +import android.text.TextUtils +import android.text.style.ForegroundColorSpan +import android.util.Log +import android.view.* +import android.view.inputmethod.InputMethodManager +import android.widget.Button +import android.widget.EditText +import android.widget.FrameLayout +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.alibaba.android.arouter.facade.annotation.Autowired +import com.alibaba.android.arouter.facade.annotation.Route +import com.alibaba.android.arouter.launcher.ARouter +import com.blankj.utilcode.util.GsonUtils +import com.blankj.utilcode.util.LogUtils +import com.blankj.utilcode.util.ThreadUtils +import com.blankj.utilcode.util.TimeUtils +import com.chad.library.adapter.base.BaseQuickAdapter +import com.example.moduleroom.R +import com.example.moduleroom.contacts.RoomContacts +import com.example.moduleroom.databinding.ActivityRoomBinding +import com.example.moduleroom.dialog.* +import com.example.moduleroom.dialog.ExitRoomBottomSheet.OnOptionSelectedListener +import com.example.moduleroom.fragment.* +import com.example.moduleroom.presenter.RoomPresenter +import com.example.moduleroom.service.ForegroundService +import com.example.moduleroom.service.RoomPlayService +import com.hjq.toast.ToastUtils +import com.liulishuo.okdownload.OkDownloadProvider +import com.orhanobut.logger.Logger +import com.petterp.floatingx.assist.helper.FxScopeHelper +import com.petterp.floatingx.listener.control.IFxControl +import com.tencent.imsdk.v2.V2TIMManager +import com.tencent.imsdk.v2.V2TIMSDKListener +import com.tencent.imsdk.v2.V2TIMUserFullInfo +import com.tencent.imsdk.v2.V2TIMValueCallback +import com.xscm.moduleutil.activity.BaseMvpActivity +import com.xscm.moduleutil.adapter.CommonPageAdapter +import com.xscm.moduleutil.adapter.LikeUserAdapter +import com.xscm.moduleutil.base.AppStateListener +import com.xscm.moduleutil.base.AppStateManager +import com.xscm.moduleutil.base.CommonAppContext +import com.xscm.moduleutil.base.RoomManager +import com.xscm.moduleutil.bean.* +import com.xscm.moduleutil.bean.RoomMessageEvent.T +import com.xscm.moduleutil.bean.RoomMessageEvent.text +import com.xscm.moduleutil.bean.room.* +import com.xscm.moduleutil.bean.room.FriendInfo.HeartList +import com.xscm.moduleutil.bean.room.RoomAuction.AuctionListBean +import com.xscm.moduleutil.bean.room.RoomAuction.AuctionUserBean +import com.xscm.moduleutil.color.ThemeableDrawableUtils +import com.xscm.moduleutil.dialog.ConfirmDialog +import com.xscm.moduleutil.dialog.RechargeDialogFragment +import com.xscm.moduleutil.dialog.giftLottery.GiftLotteryDialog +import com.xscm.moduleutil.dialog.giftLottery.TourClubDialogFragment +import com.xscm.moduleutil.event.* +import com.xscm.moduleutil.event.RoomWheatEvent +import com.xscm.moduleutil.http.BaseObserver +import com.xscm.moduleutil.http.RetrofitClient +import com.xscm.moduleutil.interfaces.OnMusicItemClickListener +import com.xscm.moduleutil.listener.MessageListenerSingleton +import com.xscm.moduleutil.listener.MessageListenerSingleton.OnMessageReceivedListener +import com.xscm.moduleutil.rtc.AgoraManager +import com.xscm.moduleutil.rtc.MusicPlayBean +import com.xscm.moduleutil.service.MyRoomSingleton +import com.xscm.moduleutil.utils.* +import com.xscm.moduleutil.utils.roomview.GiftDisplayManager +import com.xscm.moduleutil.widget.* +import com.xscm.moduleutil.widget.ViewUtils.OnViewCreatedListener +import com.xscm.moduleutil.widget.floatingView.Floa +import io.agora.musiccontentcenter.Music +import io.reactivex.disposables.Disposable +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import pub.devrel.easypermissions.AppSettingsDialog +import pub.devrel.easypermissions.EasyPermissions +import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks +import java.lang.ref.WeakReference +import java.nio.charset.StandardCharsets +import java.util.* +import java.util.stream.Collectors + +@Route(path = ARouteConstants.ROOM_DETAILS) +class RoomActivity : BaseMvpActivity(), + RoomContacts.View, PermissionCallbacks, OnMessageReceivedListener, QXRedPacketManager.QXRedPacketManagerDelegate { + private var roomFragment: RoomFragment? = null + var commonPageAdapter: CommonPageAdapter? = null + private var mRoomBean: RoomBean? = null + + //房主信息 + private var mRoomOwnerBean: RoomOwnerBean? = null + + //房间用户信息 + private var mRoomUserBean: RoomUserBean? = null + private var mPitList: List = ArrayList() + + @JvmField + @Autowired + var password: String? = null + + @JvmField + @Autowired + var roomId: String? = null + + @JvmField + @Autowired + var mRoomInfoResp: RoomInfoResp? = null + + @JvmField + @Autowired + var taskId: String? = null + + var likeUserAdapter: LikeUserAdapter? = null + var permissions: Array = arrayOf(Manifest.permission.RECORD_AUDIO) + private var isSave = false //活动是否将被系统回收 + + private var musicWindowControl: IFxControl? = null + private var customMusicFloatingView: CustomMusicFloatingView? = null + private var number = 0 + + private var floatingMagnetView: Floa? = null + private var fullScreenContainer: FrameLayout? = null + private var isFullScreen = false + private var ivExitFullscreen: ImageView? = null + var ivQuan: ImageView? = null + private var imYc = false + + @JvmField + @Autowired + var isOnline: Boolean = false + + private var silentCountDownTimer: SilentCountDownTimer? = null + private var circularProgress: CircularProgressView? = null + private var publicScreenFragment: PublicScreenEaseChatFragment? = null // 添加成员变量 + + // 添加成员变量 + private var isLayoutAdjusted = false + + // 存储当前显示的弹框引用 + private val activeDialogs: MutableList = ArrayList() + private val activeDialogFragments: MutableList = ArrayList() + + private var isMinimized = false + private var appStateListener: AppStateListener? = null + + private var qxRedPacketManager: QXRedPacketManager? = null + + + // 添加弹框到管理列表 + fun addActiveDialog(dialog: DialogInterface) { + activeDialogs.add(dialog) + } + + fun addActiveDialogFragment(dialogFragment: Fragment) { + activeDialogFragments.add(dialogFragment) + } + + + + private fun resumeRoomFromMinimize() { + // 从最小化状态恢复房间 + isMinimized = false + clearMinimizeState() + + // 恢复房间状态 + resumeRoomState() + + // 确保UI正确显示 + if (mBinding != null) { + // 恢复UI状态 + } + } + + private var bgEffectView: View? = null + + private fun setupEffectView() { + bgEffectView = null + if (bgEffectView == null) { + // 获取单例管理器 + val manager = QXGiftPlayerManager.getInstance(applicationContext) + + // 获取背景特效视图并添加到布局中 + bgEffectView = manager.defaultBgEffectView + // 找到 mBinding.svgaGift 的父容器 + val parent = mBinding!!.svgaGift.parent + if (parent is ViewGroup) { + val parentViewGroup = parent + // 检查 bgEffectView 是否已经有父视图 + val currentParent = bgEffectView?.getParent() + if (currentParent != null && currentParent is ViewGroup) { + // 如果已经有父视图,先从父视图中移除 + currentParent.removeView(bgEffectView) + } + + // 确保 bgEffectView 不为 null 并且没有父视图后再添加 + if (bgEffectView != null) { + // 将 bgEffectView 添加为 mBinding.svgaGift 的兄弟视图 + // 添加到 mBinding.svgaGift 的父容器中,位置在 mBinding.svgaGift 之前 + parentViewGroup.addView( + bgEffectView, + parentViewGroup.indexOfChild(mBinding!!.svgaGift) + ) + } + + // 设置布局参数 - 填满父视图 + val params = FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT + ) + bgEffectView?.setLayoutParams(params) + } else { + LogUtils.e("mBinding.svgaGift 没有有效的父容器") + return + } + // 获取全屏特效视图 + val fullEffectView = manager.defaultFullEffectView + + // 设置全屏特效视图的布局参数 - 居中并设置尺寸 + val fullParams = FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + fullParams.gravity = Gravity.CENTER + fullEffectView.layoutParams = fullParams + + // 获取聊天特效视图 + val chatEffectView = manager.defaultChatEffectView + + // 设置聊天特效视图的布局参数 - 底部居中并设置尺寸 + val chatParams = FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + chatParams.gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL + chatEffectView.layoutParams = chatParams + } + + // 从SharedPreferences获取是否关闭特效的设置 + val isClose = SpUtil.getOpenEffect() != 1 + QXGiftPlayerManager.getInstance(applicationContext).openOrCloseEffectViewWith(!isClose) + } + + override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { + if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_DOWN) { + // 拦截返回键,显示退出对话框而不是直接退出 + showExitRoomDialog() + return true + } + return false + } + + // 添加一个标记,用于判断用户是否主动离开应用 + private var userLeaving = false + + override fun onUserLeaveHint() { + super.onUserLeaveHint() + LogUtils.e("RoomActivity", "onUserLeaveHint") + // 当用户主动离开应用时(例如按下Home键),设置标记 + userLeaving = true + } + + override fun onPause() { + super.onPause() + LogUtils.e("RoomActivity", "onPause") + + if (mRoomInfoResp != null) { + if (mRoomInfoResp!!.room_info.type_id != "6") { + // 只有在用户主动离开应用时才执行最小化操作 + if (!userLeaving) { + // 保持Activity alive,不调用finish() + + minimizeToBackground() + + userLeaving = false // 重置标记 + } + } + userLeaving = true + } + } + + fun tob() { + val stub = mBinding!!.roomTop.stubButtons2 + stub.visibility = View.VISIBLE + val imActionJs = mBinding!!.roomTop.imActionJs.findViewById(R.id.im_action_js) + val imActionYs = mBinding!!.roomTop.imActionYs.findViewById(R.id.im_action_ys) + if (imActionJs != null && imActionYs != null) { + imActionJs.setOnClickListener { dialogEnd() } + imActionYs.setOnClickListener { + MvpPre!!.auctionDelay( + SpUtil.getauctionId() + ) + } + } + } + + fun upTop() { + mBinding!!.roomTop.stubButtons2.visibility = View.GONE + } + + private fun dialogEnd() { + // 创建并显示确认对话框 + ConfirmDialog( + this, + "提示", + "您确定要结束本次拍卖吗?", + "确认", + "取消", + { v: View? -> + // 点击“确认”按钮时执行删除操作 + MvpPre!!.auctionEnd(SpUtil.getauctionId(), roomId) + }, + { v: View? -> }, false, 0 + ).show() + } + + fun upVisibility(visible: Boolean) { + mBinding!!.roomTop.imActionJs.visibility = + if (visible) View.VISIBLE else View.INVISIBLE + mBinding!!.roomTop.imActionYs.visibility = + if (visible) View.VISIBLE else View.INVISIBLE + } + + fun upJs(visible: Boolean) { + mBinding!!.roomTop.imActionJs.visibility = + if (visible) View.VISIBLE else View.INVISIBLE + } + + fun upYs(visible: Boolean) { + mBinding!!.roomTop.imActionYs.visibility = + if (visible) View.VISIBLE else View.INVISIBLE + } + + /** 最小化 */ + private fun showExitRoomDialog() { + if (mRoomInfoResp!!.room_info.type_id.equals("6")) { + val bottomSheet = ExitRoomBottomSheet.newInstance(false, true, true); + bottomSheet.setOnOptionSelectedListener(object : OnOptionSelectedListener { + override fun onMinimize() { + } + + override fun onExitRoom() { + // 调用退出房间方法 +// MvpPre.quitRoom(roomId, SpUtil.getUserId() + ""); + + // 真正退出房间 + // 调用退出房间方法 + MessageListenerSingleton.quitGroup(roomId); + quit(); + if (mRoomInfoResp!!.getRoom_info() + .getLabel_id() != null && mRoomInfoResp!!.getRoom_info().getLabel_id() + .equals("5") + ) { + jiaR(); + return; + } else { + performExitRoom(1); + } +// performExitRoom(1) + } + + override fun onCancel() { + // 用户点击取消,不做任何事 + } + }) + + return + } + + val bottomSheet = ExitRoomBottomSheet.newInstance() + bottomSheet.setOnOptionSelectedListener(object : OnOptionSelectedListener { + override fun onMinimize() { + // 处理最小化逻辑,比如不销毁 Activity,仅移至后台 + minimizeToBackground() + } + + override fun onExitRoom() { + performExitRoom(1) + } + + override fun onCancel() { + // 用户点击取消,不做任何事 + } + }) + bottomSheet.show(supportFragmentManager, "ExitRoomBottomSheet") + addActiveDialogFragment(bottomSheet) + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + val currentFragment = + supportFragmentManager.findFragmentById(R.id.vp_room_pager) // 替换为你实际的容器 ID + if (currentFragment is RoomCabinFragment) { + currentFragment.onConfigurationChanged(newConfig) + initPublicScreenFragment() + } + } + + fun clearData() { + publicScreenFragment!!.someMethod() + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun roomInfoEvent(surfaceView: SurfaceEvent) { + if (mRoomInfoResp!!.room_info.type_id == "6") { //判断是否是电影房 + floatingMagnetView = findViewById(R.id.flaoat) //电影房 + if (mRoomInfoResp!!.user_info.is_room_owner != 1) { //判断是不是房主,1:是 如何是,不展示 0不是,展示布局 + if (surfaceView.type != 1) { + val container = + floatingMagnetView?.findViewById(R.id.fl_screenshare) + // mBinding.flaoat.setVisibility(GONE);//展示或不展示 + if (surfaceView == null) { + runOnUiThread { + mBinding!!.flaoat.visibility = View.GONE + container?.removeAllViews() + } + } else { + runOnUiThread { + mBinding!!.flaoat.visibility = View.VISIBLE + container?.removeAllViews() + container?.addView(surfaceView.surfaceView) + } + } + } else { + floatingMagnetView?.setVisibility(View.GONE) + } + } + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun hideInput(event: RoomInputHideEvent) { + if (event.hide) { + mBinding!!.vpRoomPager.isScrollContainer = false + } else { + mBinding!!.vpRoomPager.isScrollContainer = true + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun roomInfoEvent(messageEvent: ColoseCardEvent?) { + mBinding!!.flaoat.visibility = View.GONE + exitFullScreen() + } + + /** + * 释放当前房间 + */ + private fun releaseRoom() { + AgoraManager.getInstance(this).cleanup() + CommonAppContext.getInstance().isPlaying = false + CommonAppContext.getInstance().isShow = false + QXGiftPlayerManager.getInstance(applicationContext).destroyEffectSvga() + cleanupResources() + } + private lateinit var giftManager: GiftDisplayManager + private val testHandler = Handler() + private var testRunnable: Runnable? = null + + + override fun onCreate(savedInstanceState: Bundle?) { + // 在super.onCreate之前设置主题以避免闪白屏 + setTheme(com.xscm.moduleutil.R.style.BaseAppTheme) // 设置你的主主题 + super.onCreate(savedInstanceState) + // // 进入房间10s后检查是否显示提示上麦对话框 + LogUtils.e("RoomActivity", "onCreate") + + isSave = false + sDestroied = false + isMinimized = false + overridePendingTransition(0, 0) // 关闭转场动画 + startKeepLiveService() //保活 + + window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN) + sActivityRef = WeakReference(this) + + + // 检查是否有保存的最小化状态 + checkAndRestoreMinimizeState() + // 获取传递的房间数据 + // 在子线程中执行网络请求 + performNetworkRequestsAsync() + roomFragment = RoomFragment.newInstance() + supportFragmentManager + .beginTransaction() + .replace(R.id.vp_room_pager, roomFragment!!) + .commitAllowingStateLoss() + // 使用新的 OnBackPressedDispatcher API 来处理返回事件 + if (onBackPressedDispatcher != null) { + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + // 拦截返回键,显示退出对话框而不是直接退出 + showExitRoomDialog() + } + }) + } + + // 获取Application实例并设置监听器 + val app = application as CommonAppContext + appStateListener = AppStateManager.getInstance() + app.setAppStateListener(appStateListener) + + // 通知RoomActivity已创建 + if (appStateListener != null) { + appStateListener?.onRoomActivityCreated(this) + } + + + // 处理房间数据 +// handleRoomData(); + SpUtil.saveMyRoomId(roomId) + // 检查是否从最小化状态恢复 + if (isMinimized) { + // 恢复房间状态 + resumeRoomState() + } + + V2TIMManager.getInstance().addIMSDKListener(imSdkListener); + // 在 RoomActivity 中获取单例实例 + // 在onCreate中初始化红包管理器实例,以便在整个Activity生命周期中使用 + qxRedPacketManager = QXRedPacketManager.getInstance() + // 获取单例实例并设置委托 + qxRedPacketManager!!.setDelegate(this); + + + // 初始化礼物管理器 + giftManager = GiftDisplayManager.getInstance() + giftManager.setupDisplayView(mBinding!!.giftContainer) + + } + + + private val imSdkListener = object : V2TIMSDKListener() { + override fun onConnecting() {} + + override fun onConnectSuccess() { //重连成功 + if (CommonAppContext.getInstance().playId != null) { + LogUtils.e("@@@", "重连成功") + LogUtils.e("@@@", "" + CommonAppContext.getInstance().playId) + RetrofitClient.getInstance().roomUserReconnect(CommonAppContext.getInstance().playId) + } + } + + override fun onConnectFailed(code: Int, error: String?) { + LogUtils.e("@@@", "断开连接") + CommonAppContext.getInstance().onConnectFailed = true + } + + override fun onKickedOffline() { + // queren1(); + if (CommonAppContext.getInstance().playId != null) { + ToastUtils.show("您的账号已被挤下线") + try { + CommonAppContext.getInstance().clearLoginInfo() + } catch (e: ClassNotFoundException) { + throw RuntimeException(e) + } + } + } + + override fun onUserSigExpired() {} + + override fun onSelfInfoUpdated(info: V2TIMUserFullInfo?) {} + } + private fun checkAndRestoreMinimizeState() { + val prefs = getSharedPreferences("room_minimize_state", Context.MODE_PRIVATE) + var isMinimized = prefs.getBoolean("is_minimized", false) + + if (isMinimized) { + isMinimized = true + // 检查最小化时间,如果太久可能需要重新登录 + val minimizeTime = prefs.getLong(PREF_MINIMIZED_TIME, 0) + val currentTime = System.currentTimeMillis() + + // 如果最小化超过一定时间(如30分钟),可能需要重新验证 + if (currentTime - minimizeTime > 30 * 60 * 1000) { + // 清理过期的最小化状态 + clearMinimizeState() + isMinimized = false + } + } else { + isMinimized = false + } + } + + /** + * 在子线程中执行网络请求,避免阻塞主线程 + */ + private fun performNetworkRequestsAsync() { + ThreadUtils.executeByIo(object : ThreadUtils.SimpleTask() { + @Throws(Throwable::class) + override fun doInBackground(): Void? { + // 在后台线程执行网络请求前的准备工作 + // 例如:检查缓存、预处理数据等 +// prepareNetworkRequest(); + return null + } + + override fun onSuccess(result: Void?) { + runOnUiThread { + // 使用Handler确保在主线程中调用 +// MvpPre.getRoomIn(roomId, password); + if (mRoomInfoResp == null) { + // 使用Handler确保在主线程中调用 + MvpPre!!.getRoomIn(roomId, password) + + } + MvpPre!!.getRoomOnline(roomId, "1", "10") + } + } + + + override fun onFail(e: Throwable) { + LogUtils.e("Network request preparation failed: " + e.message) + // 即使准备失败,也尝试执行网络请求 + runOnUiThread { + // MvpPre.getRoomIn(roomId, password); + // 检查是否已经有房间信息,如果有则不需要再次获取 + if (mRoomInfoResp == null) { + MvpPre!!.getRoomIn(roomId, password) + } + MvpPre!!.getRoomOnline(roomId, "1", "10") + } + } + }) + } + + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onRoomTaskEvent(event: RoomTaskEvent?) { + if (taskId != null && taskId != "9") { //这是每日任务完成发送私聊信息的事件 + RetrofitClient.getInstance().dailyTasksComplete(taskId, object : BaseObserver() { + override fun onSubscribe(d: Disposable) { + } + + override fun onNext(roomSingleton: RoomSingleton) { + number++ + // 这里处理请求结果 + if (roomSingleton.is_completed == 1) { + // 任务完成,可以做一些后续操作 + taskId = null + } + } + }) + } + } + + // TODO: 发红包 + fun redDialogView() { + RedBagSendDialog(this, roomId).show() + } + + var redEnvelopesFragment: RedEnvelopesFragment? = null + var redListDialog: RedListDialog? = null + var redPacketInfo: RedPacketInfo? = null + + override fun initView() { + super.initView() + floatingMagnetView = findViewById(R.id.flaoat) + ivQuan = findViewById(R.id.iv_quan) + fullScreenContainer = findViewById(R.id.fullscreen_container) // 自定义全屏容器 + ivExitFullscreen = findViewById(R.id.iv_exit_fullscreen) + ivQuan?.setOnClickListener(View.OnClickListener { v: View? -> toggleFullScreen() }) + ivExitFullscreen?.setOnClickListener(View.OnClickListener { v: View? -> exitFullScreen() }) + + LogUtils.e("lxj", "开始时间:" + TimeUtils.date2String(Date())) + + if (taskId != null) { + if (taskId == "9") { + MyRoomSingleton.getInstance().onEnterRoom(taskId) + } + } + circularProgress = mBinding!!.giftShowProgress + circularProgress!!.progress = 0 + mBinding!!.giftShowLayout.setOnClickListener { + onGiftGiveProgressClcik() + LogUtils.e("xj", "onSubscribe2222") + } + + ThemeableDrawableUtils.setThemeableRoundedBackground( + mBinding!!.roomTop.btnFollow, + ColorManager.getInstance().primaryColorInt, + 53 + ) + mBinding!!.roomTop.btnFollow.setTextColor(ColorManager.getInstance().buttonColorInt) + initPublicScreenFragment() + + // stub = mBinding.roomTop.stubButtons.getViewStub(); + + // 为透明 View 设置触摸监听 + mBinding!!.roomTop.rlTop.setOnTouchListener { v, event -> + // 将触摸事件透传给下层的 View + false // 返回 false,表示不拦截事件 + } + + val layoutParams = mBinding!!.roomTop.root.layoutParams + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT // 使用你定义的getWidth方法 + layoutParams.height = SystemUtils.getWidth(74) // 示例高度 + mBinding!!.roomTop.root.layoutParams = layoutParams + + mBinding!!.xlhIm.setOnClickListener { + val fm = supportFragmentManager + if (fm != null && !fm.isDestroyed) { + val newDialog = TourClubDialogFragment.newInstance( + roomId + ) + newDialog.show(fm, "TourClubDialogFragment") + } + } + + mBinding!!.clXsb.visibility = View.GONE + mBinding!!.tvXlh.setOnClickListener { view -> + val fragment = HourlyChartDialog.newInstance() + fragment.show(supportFragmentManager, "HourlyChartDialog") + } + + mBinding!!.drvRed.visibility = View.GONE + mBinding!!.redBj.setOnClickListener { + if(qxRedPacketManager!!.getAllRedPackets().size==1){ + redPacketInfo = qxRedPacketManager!!.getAllRedPackets().get(0) + if (qxRedPacketManager!!.getAllRedPackets().get(0)!=null && qxRedPacketManager!!.getAllRedPackets().get(0).is_qiang==1){ + ARouter.getInstance().build(ARouteConstants.ROOM_RED_RESULT).withString("redpacketId", qxRedPacketManager!!.getAllRedPackets().get(0).getRedpacket_id()).navigation(); + }else { + redEnvelopesFragment = RedEnvelopesFragment(this@RoomActivity) + redEnvelopesFragment!!.setIsCollectedRoom(mRoomUserBean!!.is_collect == 1) + redEnvelopesFragment!!.setFromToComment(false) + redEnvelopesFragment!!.setRedPacket(qxRedPacketManager!!.getAllRedPackets().get(0)) + redEnvelopesFragment!!.show() + } + return@setOnClickListener + } + + redListDialog = RedListDialog(this) + redListDialog!!.setOnRedPacketClickListener(object : RedListDialog.OnRedPacketClickListener { + + override fun onRedPacketClick(redPacketInfos: RedPacketInfo?, position: Int) { + redPacketInfo = redPacketInfos + if (redPacketInfos!=null && redPacketInfos.is_qiang==1){ + ARouter.getInstance().build(ARouteConstants.ROOM_RED_RESULT).withString("redpacketId", redPacketInfos.getRedpacket_id()).navigation(); + }else { + redEnvelopesFragment = RedEnvelopesFragment(this@RoomActivity) + redEnvelopesFragment!!.setIsCollectedRoom(mRoomUserBean!!.is_collect == 1) + redEnvelopesFragment!!.setFromToComment(false) + redEnvelopesFragment!!.setRedPacket(redPacketInfos) + redEnvelopesFragment!!.show() + redListDialog!!.dismiss() + } + } + }) + redListDialog!!.show(); + } + } + + private fun onGiftGiveProgressClcik() { + if (giftGiveEvent == null || giftGiveEvent!!.roonGiftModel == null) { + return + } + + if (giftGiveEvent!!.auction_id != null && !giftGiveEvent!!.auction_id.isEmpty()) { + RetrofitClient.getInstance().roomAuctionJoin( + giftGiveEvent!!.getAuction_id(), + giftGiveEvent!!.getUserId(), + giftGiveEvent!!.getRoonGiftModel().gift_id, + giftGiveEvent!!.getNum(), + "1", + object : BaseObserver() { + override fun onSubscribe(d: Disposable) { +// showGiftGiveProgress(); + } + + override fun onNext(auctionListBean: AuctionListBean) { + if (auctionListBean == null) { + // 处理空响应 + Log.e("RoomActivity", "AuctionListBean is null") + hideGiftGiveProgress() + return + } + showGiftGiveProgress() + } + + override fun onError(e: Throwable) { + super.onError(e) + val msg = e.message + if (!TextUtils.isEmpty(msg) && msg!!.contains("当前余额不足")) { + ToastUtils.show("当前余额不足,请充值") + ThreadUtils.runOnUiThreadDelayed({ + val fragment = RechargeDialogFragment.show( + roomId, null, + supportFragmentManager,"","" + ) + if (fragment != null) { + addActiveDialogFragment(fragment) // 添加到管理列表 + } + }, 1400) + } + hideGiftGiveProgress() + } + }) + } else { + RetrofitClient.getInstance().roomGift( + giftGiveEvent!!.getRoom_id(), + giftGiveEvent!!.getRoonGiftModel().gift_id, + giftGiveEvent!!.getNum(), + giftGiveEvent!!.getUserId(), + "1", + giftGiveEvent!!.getPit(), + giftGiveEvent!!.heart_id, + object : BaseObserver() { + override fun onSubscribe(d: Disposable) { +// showGiftGiveProgress(); +// LogUtils.e("xj", "onSubscribe"); + } + + override fun onNext(s: String) { + showGiftGiveProgress() + } + + override fun onError(e: Throwable) { + super.onError(e) + val msg = e.message + if (!TextUtils.isEmpty(msg) && msg!!.contains("当前余额不足")) { + ToastUtils.show("当前余额不足,请充值") + ThreadUtils.runOnUiThreadDelayed({ + val fragment = RechargeDialogFragment.show( + roomId, null, + supportFragmentManager,"","" + ) + if (fragment != null) { + addActiveDialogFragment(fragment) // 添加到管理列表 + } + }, 1400) + } + hideGiftGiveProgress() + } + }) + } + } + + private var giftGiveEvent: RoomGiftGiveEvent? = null + + @Subscribe(threadMode = ThreadMode.MAIN) + fun roomGiveGiftEvent(event: RoomGiftGiveEvent?) { + if (isFinishing || event == null || event.roonGiftModel == null) { + return + } + giftGiveEvent = event + showGiftGiveProgress() + } + + private var giftProgress = 0 + private var giftCountTimer: CountDownTimer? = null + + private fun startGiftProgressTime() { + giftProgress = 0 + if (giftCountTimer != null) { + giftCountTimer!!.cancel() + } + LogUtils.e("xj2", "onSubscribe") + giftCountTimer = object : CountDownTimer((1000 * 10).toLong(), 50) { + override fun onTick(millisUntilFinished: Long) { + if (!isFinishing) { + circularProgress!!.progress = 1000 - (millisUntilFinished / 10).toInt() + } + } + + override fun onFinish() { + circularProgress!!.progress = 1000 + hideGiftGiveProgress() + } + } + giftCountTimer?.start() + } + + private fun showGiftGiveProgress() { + ImageUtils.loadImageView( + giftGiveEvent!!.roonGiftModel.base_image, + mBinding!!.giftShowProgressImg + ) + circularProgress!!.progress = 1000 // 显示进度条,2025年7月19日11:23:37将这个从下面的方法提起到这里, + startGiftProgressTime() + mBinding!!.giftShowLayout.visibility = View.VISIBLE + } + + private fun hideGiftGiveProgress() { + mBinding!!.giftShowLayout.visibility = View.GONE + if (giftCountTimer != null) { + giftCountTimer!!.cancel() + giftCountTimer = null + } + } + + private fun toggleFullScreen() { + if (isFullScreen) { + exitFullScreen() + } else { +// enterFullScreen(); + + // 修改为横屏展示模式而不是全屏模式 + + enterLandscapeMode() + } + } + + + private fun enterLandscapeMode() { + isFullScreen = true + + // 设置横屏 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + + if (floatingMagnetView != null) { + // 修改Floa组件的布局参数,使其在横屏时占据更大区域 + val layoutParams = floatingMagnetView!!.layoutParams + if (layoutParams is ConstraintLayout.LayoutParams) { + val params = layoutParams + params.width = ConstraintLayout.LayoutParams.MATCH_CONSTRAINT + params.height = ConstraintLayout.LayoutParams.MATCH_CONSTRAINT +// params.horizontalBias = 0.5f +// params.verticalBias = 0.5f + floatingMagnetView!!.layoutParams = params + } else { + // 如果不是ConstraintLayout.LayoutParams,创建新的 + val params = ConstraintLayout.LayoutParams( + ConstraintLayout.LayoutParams.MATCH_CONSTRAINT, + ConstraintLayout.LayoutParams.MATCH_CONSTRAINT + ) + params.topToTop = ConstraintLayout.LayoutParams.PARENT_ID + params.bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID + params.startToStart = ConstraintLayout.LayoutParams.PARENT_ID + params.endToEnd = ConstraintLayout.LayoutParams.PARENT_ID + floatingMagnetView!!.layoutParams = params + } + + // 可以调整内部fl_screenshare的布局参数 + val flScreenshare = floatingMagnetView!!.findViewById(R.id.fl_screenshare) + val screenParams = flScreenshare.layoutParams + if (screenParams !is FrameLayout.LayoutParams) { + // 如果不是FrameLayout.LayoutParams,创建新的 + val newScreenParams = FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT + ) + flScreenshare.layoutParams = newScreenParams + } else { + val newScreenParams = screenParams + newScreenParams.width = FrameLayout.LayoutParams.MATCH_PARENT + newScreenParams.height = FrameLayout.LayoutParams.MATCH_PARENT + flScreenshare.layoutParams = newScreenParams + } + + // 显示退出按钮 + ivQuan!!.visibility = View.VISIBLE + } + } + + private fun enterFullScreen() { + isFullScreen = true + + + // 隐藏系统UI + val decorView = window.decorView + decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_FULLSCREEN + or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) + + // 设置横屏 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + // 找到 fl_screenshare 并移到全屏容器中 + val fl_screenshare = findViewById(R.id.fl_screenshare) + if (fl_screenshare != null) { +// // 先从当前父容器中移除 +// ViewParent parent = fl_screenshare.getParent(); +// if (parent != null && parent instanceof ViewGroup) { +// ((ViewGroup) parent).removeView(fl_screenshare); +// } +// +// // 添加到全屏容器 +// fullScreenContainer.addView(fl_screenshare); + + safelyMoveViewToParent(fl_screenshare, floatingMagnetView) + // 显示全屏容器 + fullScreenContainer!!.visibility = View.VISIBLE + floatingMagnetView!!.visibility = View.GONE + ivExitFullscreen!!.visibility = View.VISIBLE // 显示退出按钮 + } + } + + private fun exitFullScreen() { + isFullScreen = false + + // 设置回竖屏 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + + if (floatingMagnetView != null) { + // 恢复原始尺寸 + val params = ConstraintLayout.LayoutParams( + resources.getDimensionPixelSize(com.xscm.moduleutil.R.dimen.dp_240), + resources.getDimensionPixelSize(com.xscm.moduleutil.R.dimen.dp_135) + ) + params.topToTop = ConstraintLayout.LayoutParams.PARENT_ID + params.bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID + params.startToStart = ConstraintLayout.LayoutParams.PARENT_ID + params.endToEnd = ConstraintLayout.LayoutParams.PARENT_ID + floatingMagnetView!!.layoutParams = params + + // 恢复内部fl_screenshare的布局参数 + val flScreenshare = floatingMagnetView!!.findViewById(R.id.fl_screenshare) + val screenParams = FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT + ) + flScreenshare.layoutParams = screenParams + } + + // 隐藏退出按钮 + ivExitFullscreen!!.visibility = View.GONE + } + + override fun initData() { + if (!EasyPermissions.hasPermissions(this, *permissions)) { + EasyPermissions.requestPermissions( + this, "请开启录音使用权限", + 1, *permissions + ) + } + + mBinding!!.roomTop.btnFollow.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.roomTop.btnNotice.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.roomTop.btnRanking.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.roomTop.btnCloseLive.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.roomTop.tvNum.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.roomTop.rl.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.ivSoundEffects.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.ivWheatFeeding.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.clFirstCharge.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.roomTop.userRecyclerView.layoutManager = LinearLayoutManager( + this, LinearLayoutManager.HORIZONTAL, false + ) + likeUserAdapter = LikeUserAdapter() + mBinding!!.roomTop.userRecyclerView.adapter = likeUserAdapter + likeUserAdapter!!.onItemClickListener = + BaseQuickAdapter.OnItemClickListener { adapter, view, position -> + // RoomOnlineDialogFragment.show(roomId, "", mRoomUserBean, mRoomInfoResp, getSupportFragmentManager()); + val fragment = RoomOnlineDialogFragment.show( + roomId, "", mRoomUserBean, mRoomInfoResp, + supportFragmentManager + ) + if (fragment != null) { + addActiveDialogFragment(fragment) // 添加到管理列表 + } + } + + + // PublicScreenEaseChatFragment fragment = PublicScreenEaseChatFragment.newInstance(); +// getSupportFragmentManager().beginTransaction().replace(R.id.ease_container, fragment).commitAllowingStateLoss(); + mBinding!!.ivChat.setOnClickListener { view: View -> + this.onClick( + view + ) + } + + mBinding!!.ivEmoji.setOnClickListener { view: View -> + this.onClick( + view + ) + } + + mBinding!!.llInput.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.rlMisc.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.rlGift.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.rlMic.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.rlSett.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.rlVoive.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.rlMore.setOnClickListener { view: View -> + this.onClick( + view + ) + } + mBinding!!.rlMessage.setOnClickListener { view: View -> + this.onClick( + view + ) + } + + // SpUtil.saveMyRoomId(roomId); +// MvpPre.getRoomIn(roomId, password); +// MvpPre.getRoomOnline(roomId, "1", "10"); + mBinding!!.inputMenu1.performClick() + + V2TIMManager.getConversationManager() + .getTotalUnreadMessageCount(object : V2TIMValueCallback { + override fun onSuccess(aLong: Long) { + if (aLong == 0L) { + mBinding!!.ivMessageDot.visibility = View.GONE + mBinding!!.ivMessageDot.text = "0" + } else { + mBinding!!.ivMessageDot.visibility = View.VISIBLE + } + mBinding!!.ivMessageDot.text = aLong.toString() + } + + override fun onError(code: Int, desc: String) { + } + }) + + mBinding!!.roomTop.root.isClickable = false + mBinding!!.roomTop.root.setOnClickListener { + // ToastUtils.showShort("点击了房间,事件穿透"); + } + +// mBinding!!.clXsb.setOnClickListener { +// val fragment = HourlyChartDialog.newInstance() +// fragment.show(supportFragmentManager,"HourlyChartDialog") +// if (fragment != null) { +// addActiveDialogFragment(fragment) // 添加到管理列表 +// } +// } + } + + + private fun initPublicScreenFragment() { + // 检查是否已经存在 Fragment 实例(例如在配置更改后) + publicScreenFragment = supportFragmentManager + .findFragmentById(R.id.ease_container) as PublicScreenEaseChatFragment? + + // 如果不存在,则创建新的实例 + if (publicScreenFragment == null) { + publicScreenFragment = PublicScreenEaseChatFragment.newInstance(roomId) + supportFragmentManager.beginTransaction() + .replace(R.id.ease_container, publicScreenFragment!!) + .commitAllowingStateLoss() + } + } + + // 在类成员变量中添加 + private val roomSwitchHandler = Handler(Looper.getMainLooper()) + private var roomSwitchRunnable: Runnable? = null + private var pendingRoomId: String? = null + private var lastSwitchedRoomId = "" + + fun roomInfoEvent(messageEvent: RoomMessageEvent?) { + if (messageEvent == null) return + if (roomFragment == null) { + roomFragment = RoomFragment.newInstance() + supportFragmentManager + .beginTransaction() + .replace(R.id.vp_room_pager, roomFragment!!) + .commitAllowingStateLoss() + } + + val msgType = messageEvent.msgType + val text = messageEvent.text + + if (msgType == 1005) { + LogUtils.e("@@@@" + "EventBusnujm2" + "playQueue.size()====" + messageEvent.text.giftInfo) + val playQueue = Arrays.asList( + *messageEvent.text.giftInfo.play_image.split(",".toRegex()) + .dropLastWhile { it.isEmpty() }.toTypedArray() + ) + QXGiftPlayerManager.getInstance(this).displayFullEffectView1(playQueue) + if (messageEvent!!.text.giftInfo!=null) { + var giftBean = messageEvent.text.giftInfo + giftBean.nickname= messageEvent.text.fromUserInfo.nickname + giftBean.userAvatar=messageEvent.text.fromUserInfo.avatar + giftBean.senderName=messageEvent.text.toUserInfo.nickname + giftBean.senderAvatarUrl=messageEvent.text.toUserInfo.avatar + giftBean.number=messageEvent.text.gift_num.toInt() + giftManager.receiveGift(giftBean) + } + hand1005(messageEvent, text) + } else if (msgType == 123) { + EventBus.getDefault().post(RoomSettingEvent()) + } else if (msgType == 1014) { + handleMsgType1014(messageEvent, text) + } else if (msgType == 1013) { + handleMsgType1013(messageEvent, text) + } else if (msgType == 1012) { + handleMsgType1012() + } else if (msgType == 124) { + handleMsgType124(messageEvent, text) + } else if (msgType == 1003) { + handleMsgType1003(messageEvent, text) + } else if (msgType == 1004) { + handleMsgType1004(messageEvent, text) + } else if (msgType == 1022) { + handleMsgType1022(messageEvent, text) + } else if (msgType == 1023) { + handleMsgType1023(messageEvent, text) + } else if (msgType == 1024) { + handleMsgType1024(messageEvent, text) + } else if (msgType == 1025) { + roomFragment!!.handleAuctionMessageEvent(messageEvent) + } else if (msgType == 1026) { + roomFragment!!.handleAuctionMessageEvent(messageEvent) + } else if (msgType == 1027) { + roomFragment!!.handleAuctionMessageEvent(messageEvent) + } else if (msgType == 1020) { + handleMsgType1020(messageEvent, text) + } else if (msgType == 1011) { + handleMsgType1011(messageEvent, text) + } else if (msgType == 1001) { + handleMsgType1001() + } else if (msgType == 1002) { + handleMsgType1002() + } else if (msgType == 1029) { + handleMsgType1029(messageEvent, text) + } else if (msgType == 1021) { + handleMsgType1021(messageEvent, text) + } else if (msgType == 1036) { + handleMsgType1036(messageEvent, text) + } else if (msgType == 1049) { + handleMsgType1049(messageEvent, text) + } else if (msgType == 1050) { + handleMsgType1050(messageEvent, text) + } else if (msgType == 1051) { + handleMsgType1051(messageEvent, text) + } else if (msgType == 1052) { + roomFragment!!.upCabinFragment(text.time_day) + } else if (msgType == 1053) { + handleMsgType1053(messageEvent, text) + } else if (msgType == 1054) { + handleMsgType1054(messageEvent, text) + } else if (msgType == 1055) { + handleMsgType1055(messageEvent) + } else if (msgType == 1035) { + handleMsgType1035(messageEvent, text) + } else if (msgType == 1030 || msgType == 1031 || msgType == 1032 || msgType == 1033 || msgType == 1015 || msgType == 1037) { + roomFragment!!.SingSongEvent(messageEvent) + if (msgType == 1032 || msgType == 1033) { + setRoleType(3, -11) + } + } else if (msgType == 125) { + handleMsgType125(messageEvent, text) + } else if (msgType == 1006) { + handleMsgType1006() + } else if (msgType == 1007) { + handleMsgType1007() + } else if (msgType == 1017) { + handleMsgType1017() + } else if (msgType == 1018) { + handleMsgType1018() + } else if (msgType == 126) { + handleMsgType126(messageEvent, text) + } else if (msgType == 1034) { + handleMsgType1034(messageEvent, text) + } else if (msgType == 1016) { + handleMsgType1016(messageEvent, text) + } else if (msgType == 1039) { + handleMsgType1039(messageEvent, text) + } else if (msgType == 1028) { + roomFragment!!.handleMsgType1028(messageEvent) + } else if (msgType == 1058) { + var userId = messageEvent!!.text!!.user_id!! + LogUtils.e("messageEvent!!.text.type" + messageEvent!!.text.type) + CommonAppContext.getInstance().onlineMap.set( + userId?.toString() ?: "", + messageEvent!!.text.type + ) + if (mRoomInfoResp != null && mRoomInfoResp!!.room_info != null) { + if (mRoomInfoResp!!.room_info.type_id == "1" || mRoomInfoResp!!.room_info.type_id == "3" || + mRoomInfoResp!!.room_info.type_id == "4" || mRoomInfoResp!!.room_info.type_id == "8" + ) { + if (mRoomInfoResp!!.room_info.label_id == "1") { +// roomFragment!!.SingSongEvent(messageEvent) + } else { + roomFragment!!.KtvFragmentEvent(messageEvent) + } + } else if (mRoomInfoResp!!.room_info.type_id == "2") { + roomFragment!!.handleAuctionMessageEvent(messageEvent) + } else if (mRoomInfoResp!!.room_info.type_id == "7") { + roomFragment!!.friendshipRoomFragmentEvent(messageEvent) + } + } + + CommonAppContext.getInstance().getOnlineMap() + } else if (msgType == 1059) { // 1059清除个人魅力 1058在离线 + if (mRoomInfoResp != null && mRoomInfoResp!!.room_info != null) { + if (mRoomInfoResp!!.room_info.type_id == "1" || mRoomInfoResp!!.room_info.type_id == "3" || + mRoomInfoResp!!.room_info.type_id == "4" || mRoomInfoResp!!.room_info.type_id == "8" + ) { + if (mRoomInfoResp!!.room_info.label_id == "1") { + roomFragment!!.SingSongEvent(messageEvent) + } else { + roomFragment!!.KtvFragmentEvent(messageEvent) + } + } else if (mRoomInfoResp!!.room_info.type_id == "2") { + roomFragment!!.handleAuctionMessageEvent(messageEvent) + } else if (mRoomInfoResp!!.room_info.type_id == "7") { + roomFragment!!.friendshipRoomFragmentEvent(messageEvent) + } + } + } else if (msgType == 1056) { // 1056 抽奖结果 + val dialog = supportFragmentManager + .findFragmentByTag("GiftLotteryDialog") as GiftLotteryDialog? + if (dialog != null && dialog.isVisible) { + dialog.UpView(messageEvent.text.xlh_data) + } else { + EventBus.getDefault().post(messageEvent.text.xlh_data) + } + + if (messageEvent.text.xlh_data != null) { + if (messageEvent.text.xlh_data.status == 1) { + mBinding!!.xlhRk.visibility = View.VISIBLE + xlhDjs(messageEvent.text.xlh_data.end_time) + } else { + mBinding!!.xlhRk.visibility = View.INVISIBLE + releaseCountDownTimer1() + } + } + } else if (msgType == 1057) { + val existingFragment = + supportFragmentManager.findFragmentByTag("TourClubDialogFragment") as TourClubDialogFragment? + if (existingFragment != null && existingFragment.isVisible) { + existingFragment.onMusicPlay(messageEvent) + } else { + LogUtils.e("TourClubDialogFragment", "巡乐会界面未打开") + EventBus.getDefault().post(messageEvent) + } + xlhDjs(messageEvent.text.end_time) + + } else if (msgType == 1060) { + qxRedPacketManager!!.addRedPacket(messageEvent.text.redpacketInfo) + }else if (msgType == 1061){ + qxRedPacketManager!!.removeRedPacket(messageEvent.text.redpacket_id) + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onMessageEvent(messageEvent: MqttXlhEnd) { + val xlhBean: XLHBean = GsonUtils.fromJson(messageEvent.message, XLHBean::class.java) + if(xlhBean.from_type==100){ + if (xlhBean.xlh_data != null) { + if (xlhBean.xlh_data.status == 1) { + mBinding!!.xlhRk.visibility = View.VISIBLE + xlhDjs(xlhBean.xlh_data.end_time) + } else { + mBinding!!.xlhRk.visibility = View.INVISIBLE + releaseCountDownTimer1() + } + } + }else if(xlhBean.from_type==103){ + val existingFragment = + supportFragmentManager.findFragmentByTag("TourClubDialogFragment") as TourClubDialogFragment? + if (existingFragment != null && existingFragment.isVisible) { + existingFragment.onMessageReceived(messageEvent) + } else { + LogUtils.e("TourClubDialogFragment", "巡乐会界面未打开") +// EventBus.getDefault().post(messageEvent) + } + xlhDjs(xlhBean.end_time) + }else if(xlhBean.from_type==104){ + + } + } + + private var endTime: Long = 0 + + private fun xlhDjs(endTimeStr: String?) { + // 获取结束时间并启动倒计时 + if (endTimeStr != null && !endTimeStr.isEmpty()) { + try { + // 假设 end_time 是时间戳字符串 + endTime = endTimeStr.toLong() + countDownTime(endTime) + } catch (e: NumberFormatException) { + // 如果不是时间戳,可能是日期字符串,需要相应解析 + // 例如:2025-08-26 19:10:47 + // 可以使用 SimpleDateFormat 解析 + e.printStackTrace() + } + } + } + + fun countDownTime(time: Long) { + try { + if (time <= 0) { + setTime(0) + + releaseCountDownTimer1() + return + } + releaseCountDownTimer1() + // 获取当前时间的毫秒值 + val currentTime = System.currentTimeMillis() / 1000L + // 计算倒计时的总秒数 + val countDownTime = (time - currentTime) + Logger.d("@@@", "countDownTime = $countDownTime") + if (countDownTime <= 0) { + setTime(0) + releaseCountDownTimer1() + return + } + mCountDownTimer2 = object : CountDownTimer(countDownTime * 1000L, 1000L) { + override fun onTick(millisUntilFinished: Long) { + val time1 = (millisUntilFinished / 1000).toInt() + setTime(time1) + // mBinding.tvDjs.setText(time1 + ""); + if (time1 == 0) { + mBinding!!.xlhRk.visibility = View.INVISIBLE + } + } + + override fun onFinish() { + setTime(0) + } + } + mCountDownTimer2?.start() + } catch (e: Exception) { + Logger.e("countDownTime", e) + } + } + + private fun formatTime(totalSeconds: Int): String { + val minutes = (totalSeconds % 3600) / 60 + val seconds = totalSeconds % 60 + + return String.format("%02d:%02d", minutes, seconds) + } + + @SuppressLint("DefaultLocale") + fun setTime(seconds: Int) { + if (seconds == 0) { + mBinding!!.xlhRk.visibility = View.INVISIBLE + return + } + val formattedTime = formatTime(seconds) + mBinding!!.tvDjs.text = "倒计时$formattedTime" + } + + // TODO: 2025/3/19 释放倒计时器 + private fun releaseCountDownTimer1() { + if (mCountDownTimer2 != null) { + mCountDownTimer2!!.cancel() + mCountDownTimer2 = null + } + } + + private val pitMap: MutableMap = HashMap() + + fun handleMsgType1039(messageEvent: RoomMessageEvent, text: T?) { + if (mRoomInfoResp == null || mRoomInfoResp!!.room_info == null) { + return + } + + val pitList = mRoomInfoResp!!.room_info.pit_list + if (pitList != null && !pitList.isEmpty()) { +// pitMap.clear() // 避免数据累积 +// for (roomPitBean in pitList) { +// pitMap[roomPitBean.pit_number] = roomPitBean +// } + + if (text == null) { + return + } + + val fromPitNumber = text.from_pit_number + val toPitNumber = text.to_pit_number + + if (!TextUtils.isEmpty(fromPitNumber) && !TextUtils.isEmpty(toPitNumber)) { + performSwitchMic(fromPitNumber, toPitNumber, messageEvent) + } + // 执行换麦逻辑 + } + } + + private fun performSwitchMic( + fromPitNumber: String, + toPitNumber: String, + messageEvent: RoomMessageEvent + ) { + mRoomInfoResp!!.user_info.pit_number = Integer.parseInt(toPitNumber) + + +// if (messageEvent.text.user_id .equals(SpUtil.getUserId().toString()) && "9" == toPitNumber) { +// if (customMusicFloatingView != null) { +// customMusicFloatingView!!.destroy() +// AgoraManager.getInstance(this@RoomActivity).desMusic() +// isMusic = false +// } +// mBinding!!.roomTop.rl.visibility = View.GONE +// ivSoundEffects(false) +// } + + if ("9" == toPitNumber && messageEvent.text.user_id.equals(SpUtil.getUserId().toString())) { + mBinding!!.roomTop.rl.visibility = View.VISIBLE + ivSoundEffects(true) + } else { + if (customMusicFloatingView != null) { + customMusicFloatingView!!.destroy() + AgoraManager.getInstance(this@RoomActivity).desMusic() + isMusic = false + } + mBinding!!.roomTop.rl.visibility = View.GONE + ivSoundEffects(false) + } +// if (TextUtils.isEmpty(fromPitNumber) || TextUtils.isEmpty(toPitNumber)) { +// return +// } +//// +// if (mRoomInfoResp == null || mRoomInfoResp!!.room_info == null) { +// LogUtils.e("Room info is null") +// return +// } +//// +// val pitList = mRoomInfoResp!!.room_info.pit_list +// if (pitList == null || pitList.isEmpty()) { +// LogUtils.e("pit_list is null or empty") +// return +// } +//// +// var fromBean: RoomPitBean? = null +// var toBean: RoomPitBean? = null +// val pitListCopy: MutableList = ArrayList() +// +// for (bean in pitList) { +// if (bean == null) continue +// if (fromPitNumber == bean.pit_number) { +// fromBean = bean +// pitListCopy.add(bean) +// } else if (toPitNumber == bean.pit_number) { +// toBean = bean +// pitListCopy.add(bean) +// } +// } +// +// if (fromBean == null || toBean == null) { +// LogUtils.e("Cannot find pit number: from=$fromPitNumber, to=$toPitNumber") +// return +// } +// +// // 交换 pit_number +// val temp = fromBean.pit_number +// fromBean.pit_number = toBean.pit_number +// toBean.pit_number = temp +// +// // 构造新的 pitList +// val newPitList: MutableList = ArrayList() +// for (bean in pitList) { +// if (!pitListCopy.contains(bean)) { +// newPitList.add(bean) +// } +// } +// newPitList.add(fromBean) +// newPitList.add(toBean) +//// 排序 - 更简洁的 Kotlin 写法 +// newPitList.sortWith(compareBy { +// try { +// it.pit_number.toInt() +// } catch (e: NumberFormatException) { +// it.pit_number +// } +// }) +// +// mRoomInfoResp!!.room_info.pit_list = newPitList +// +// // 更新当前用户 pit_number +// if (mRoomInfoResp!!.user_info != null) { +// val currentUserId = SpUtil.getUserId().toString() +// val fromUserId = fromBean.user_id +// val toUserId = toBean.user_id +// +// if (fromUserId != null && fromUserId == currentUserId) { +// try { +// mRoomInfoResp!!.user_info.pit_number = fromBean.pit_number.toInt() +// } catch (e: NumberFormatException) { +// LogUtils.e("Invalid pit number: " + toBean.pit_number) +// } +// } else if (toUserId != null && toUserId == currentUserId) { +// try { +// mRoomInfoResp!!.user_info.pit_number = fromBean.pit_number.toInt() +// } catch (e: NumberFormatException) { +// LogUtils.e("Invalid pit number: " + toBean.pit_number) +// } +// } +// } + + dispatchRoomEvent(messageEvent) + } + + private fun dispatchRoomEvent(messageEvent: RoomMessageEvent) { + if (mRoomInfoResp == null || mRoomInfoResp!!.room_info == null) return + roomFragment!!.upRoomInfoData(mRoomInfoResp) + val typeId = mRoomInfoResp!!.room_info.type_id + if ("2" == typeId) { + + roomFragment!!.handleAuctionMessageEvent(messageEvent) + } else if ("3" == typeId || "4" == typeId || "1" == typeId || "8" == typeId) { + val labelId = mRoomInfoResp!!.room_info.label_id + if ("2" == labelId) { + roomFragment!!.KtvFragmentEvent(messageEvent) + } else if ("1" == labelId) { + roomFragment!!.SingSongEvent(messageEvent) + } + } else if ("7" == typeId) { + roomFragment!!.friendshipRoomFragmentEvent(messageEvent) + } + if (mRoomInfoResp!!.user_info.pit_number == 9) { + mBinding!!.roomTop.rl.visibility = View.VISIBLE + ivSoundEffects(true) + } + } + + private fun hand1005(messageEvent: RoomMessageEvent, text: T?) { + if (text == null || mRoomInfoResp == null || mRoomInfoResp!!.room_info == null) return + + val giftInfo = text.giftInfo + val toUserInfo = text.toUserInfo + // if (giftInfo == null || toUserInfo == null) return; + val pitList = mRoomInfoResp!!.room_info.pit_list ?: return + + + // roomFragment.updateSeatViewExchangedWithPitArray(mRoomInfoResp); + val typeId = mRoomInfoResp!!.room_info.type_id + if ("2" == typeId) { + roomFragment!!.handleAuctionMessageEvent(messageEvent) + return + } else if ("1" == typeId || "4" == typeId || "3" == typeId || "8" == typeId) { + val labelId = mRoomInfoResp!!.room_info.label_id + if ("2" == labelId) { + roomFragment!!.KtvFragmentEvent(messageEvent) + return + } else if ("1" == labelId) { + roomFragment!!.SingSongEvent(messageEvent) + return + } + } else if ("7" == typeId) { //交友房 + roomFragment!!.friendshipRoomFragmentEvent(messageEvent) + return + } + } + + private fun handleMsgType1014(messageEvent: RoomMessageEvent, text: T?) { + if (text == null) return + + val roomSettingEvent = RoomSettingEvent() + roomSettingEvent.roomId = messageEvent.roomId + roomSettingEvent.room_up_pit_type = text.room_up_pit_type + roomSettingEvent.type = messageEvent.msgType + + if (mRoomBean != null) { + mRoomBean!!.room_up_pit_type = text.room_up_pit_type.toString() + "" + EventBus.getDefault().post(mRoomBean) + } + + EventBus.getDefault().post(roomSettingEvent) + } + + private fun handleMsgType1013(messageEvent: RoomMessageEvent, text: T?) { + if (text == null || mRoomUserBean == null) return + + val userId2 = SpUtil.getUserId() + + if (text.action == 1 && mRoomUserBean!!.user_id == userId2.toString() + "" && mRoomUserBean!!.pit_number == 9) { + queren(text.fromUserInfo.nickname) + } else if (text.action == 4 && text.fromUserInfo.user_id == userId2) { + queren1(text.fromUserInfo.nickname) + } else { + roomFragment?.KtvFragmentEvent(messageEvent) + } + } + + private fun handleMsgType1012() { + if (customMusicFloatingView != null) { + customMusicFloatingView!!.destroy() + } + AgoraManager.getInstance(this@RoomActivity).desMusic() + + // stub.setVisibility(View.GONE); + if ((mRoomInfoResp!!.room_info.type_id == "1" || mRoomInfoResp!!.room_info.type_id == "4" || + mRoomInfoResp!!.room_info.type_id == "3" || mRoomInfoResp!!.room_info.type_id == "8") && + mRoomInfoResp!!.room_info.label_id == "2" + ) { + for (roomPitBean in mRoomInfoResp!!.song_pit_list) { + AgoraManager.getInstance(this@RoomActivity).ClientRole(false) + ivWheatFeeding(com.xscm.moduleutil.R.mipmap.room_wheat_feeding) + mBinding!!.rlMic.visibility = View.GONE + } + if (mRoomInfoResp!!.song_user_info != null && mRoomInfoResp!!.song_user_info.user_id != null) { + if (mRoomInfoResp!!.song_user_info.user_id == SpUtil.getUserId().toString() + "") { + AgoraManager.getInstance(this@RoomActivity).ClientRole(false) + ivWheatFeeding(com.xscm.moduleutil.R.mipmap.room_wheat_feeding) + mBinding!!.rlMic.visibility = View.GONE + } + } + } + CommonAppContext.getInstance().onlineMap.clear() + MvpPre!!.postRoomInfo(roomId) + } + + private fun handleMsgType124(messageEvent: RoomMessageEvent, text: T?) { + if (text == null) return + + try { + val parsedText = GsonUtils.fromJson( + text.text, + text::class.java + ) + val musicPlayBean = MusicPlayBean() + musicPlayBean.position = parsedText.position + EventBus.getDefault().post(musicPlayBean) + } catch (e: Exception) { + // Handle exception + } + } + + private fun handleMsgType1003(messageEvent: RoomMessageEvent, text: T?) { + if (text == null || mRoomInfoResp == null || mRoomInfoResp!!.room_info == null) return + if (roomFragment == null) { + roomFragment = RoomFragment.newInstance() + supportFragmentManager + .beginTransaction() + .replace(R.id.vp_room_pager, roomFragment!!) + .commitAllowingStateLoss() + } + + val fromUserInfo = text.fromUserInfo ?: return + + val pitNumber = text.pit_number + val userId = fromUserInfo.user_id + val currentUserId = SpUtil.getUserId() + + if ("9" == pitNumber && userId == currentUserId) { + mBinding!!.roomTop.rl.visibility = View.VISIBLE + ivSoundEffects(true) + } + + if (userId == currentUserId) { + aBoolean = false + ivWheatFeeding(com.xscm.moduleutil.R.mipmap.room_wheat_feeding_up) + setBoolean(aBoolean) + if (mRoomInfoResp!!.user_info != null) { + mRoomInfoResp!!.user_info.pit_number = + pitNumber?.toInt() ?: -1 + } + setRoleType(3, pitNumber!!.toInt()) + switchMic(2) + } + + + val typeId = mRoomInfoResp!!.room_info.type_id + if ("2" == typeId) { + if ("9" == pitNumber) { + mRoomInfoResp!!.room_info.pit_list[0] = getPitBean(messageEvent) + if (mRoomInfoResp!!.user_info != null) { + mRoomInfoResp!!.user_info.pit_number = pitNumber.toInt() + } + } + roomFragment!!.upRoomInfoData(mRoomInfoResp) + roomFragment!!.handleAuctionMessageEvent(messageEvent) + } else if ("3" == typeId || "4" == typeId || "1" == typeId || "8" == typeId) { + val labelId = mRoomInfoResp!!.room_info.label_id + if ("2" == labelId) { + roomFragment!!.KtvFragmentEvent(messageEvent) + } else if ("1" == labelId) { + mRoomInfoResp!!.room_info.pit_list.set(pitNumber.toInt() - 1, getPitBean(messageEvent)) + roomFragment!!.upRoomInfoData(mRoomInfoResp) + roomFragment!!.SingSongEvent(messageEvent) + } + } else if ("7" == typeId) { + mBinding!!.rlMore.visibility = View.GONE + mBinding!!.rlMisc.visibility = View.GONE + + roomFragment!!.friendshipRoomFragmentEvent(messageEvent) + } else { + roomFragment!!.updateSeatViewExchangedWithPitArray(mRoomInfoResp) + } + + // if (pitNumber.equals("9") && mRoomInfoResp.getUser_info().getUser_id().equals(SpUtil.getUserId()+"")) { +// ivSoundEffects(true); +// } else { +// ivSoundEffects(false); +// } + } + + private fun handleMsgType1004(messageEvent: RoomMessageEvent, text: T?) { + if (text == null || mRoomInfoResp == null || mRoomInfoResp!!.room_info == null) return + + val fromUserInfo = text.fromUserInfo ?: return + + val pitNumber = text.pit_number + val userId = fromUserInfo.user_id + val currentUserId = SpUtil.getUserId() + + if (userId == currentUserId) { + aBoolean = true + ivWheatFeeding(com.xscm.moduleutil.R.mipmap.room_wheat_feeding) + setBoolean(aBoolean) + if (mRoomInfoResp!!.user_info != null) { + mRoomInfoResp!!.user_info.pit_number = 0 + } + setRoleType(0, 0) + switchMic(2) + } + + if (pitNumber == "9") { + ivSoundEffects(false) + } + + if (userId == currentUserId && "9" == pitNumber) { + if (customMusicFloatingView != null) { + customMusicFloatingView!!.destroy() + AgoraManager.getInstance(this@RoomActivity).desMusic() + isMusic = false + } + mBinding!!.roomTop.rl.visibility = View.GONE + ivSoundEffects(false) + } + + val typeId = mRoomInfoResp!!.room_info.type_id + if ("2" == typeId) { + if ("9" == pitNumber) { + if (userId == currentUserId) { + mRoomInfoResp!!.room_info.pit_list[0] = getPitBean2(messageEvent, "9") + if (mRoomInfoResp!!.user_info != null) { + mRoomInfoResp!!.user_info.pit_number = 0 + } + } + } else if ("888" == pitNumber) { + mRoomInfoResp!!.room_auction = null + if (userId == currentUserId) { + setRoleType(0, 0) + switchMic(2) + } + } + roomFragment!!.upRoomInfoData(mRoomInfoResp) + roomFragment!!.handleAuctionMessageEvent(messageEvent) + } else if ("3" == typeId || "4" == typeId || "1" == typeId || "8" == typeId) { + val labelId = mRoomInfoResp!!.room_info.label_id + if ("2" == labelId) { + roomFragment!!.KtvFragmentEvent(messageEvent) + } else if ("1" == labelId) { + mRoomInfoResp!!.room_info.pit_list.set(pitNumber.toInt() - 1, getPitBean2(messageEvent, pitNumber)) + roomFragment!!.upRoomInfoData(mRoomInfoResp) + roomFragment!!.SingSongEvent(messageEvent) + if (mRoomInfoResp!!.user_info.user_id == SpUtil.getUserId().toString() + "") { + ivSoundEffects(false) + } + } + } else { + roomFragment!!.friendshipRoomFragmentEvent(messageEvent) + } + } + + private fun handleMsgType1022(messageEvent: RoomMessageEvent, text: T?) { + if (text == null || mRoomInfoResp == null || mRoomInfoResp!!.room_info == null) return + + val pitNumber = text.pit_number + val userId = text.fromUserInfo.user_id + val currentUserId = SpUtil.getUserId() + + if (text.type == 1) { + if ("888" == pitNumber) { + var type = -1 + if ("2" == mRoomInfoResp!!.room_info.type_id) { + type = if ("1" == mRoomInfoResp!!.room_info.label_id) 1 else 2 + } + if (userId == currentUserId) { + setRoleType(3, 888) + switchMic(2) + } + } + } else if (text.type == 2) { + if ("9" == pitNumber) { + setRoleType(0, 0) + switchMic(2) + } else if ("888" == pitNumber) { + mRoomInfoResp!!.room_auction = RoomAuction() + if (userId == currentUserId) { + setRoleType(0, 0) + switchMic(2) + } + } + } + + roomFragment!!.upRoomInfoData(mRoomInfoResp) + roomFragment!!.handleAuctionMessageEvent(messageEvent) + } + + private fun handleMsgType1023(messageEvent: RoomMessageEvent, text: T?) { + if (text == null || mRoomInfoResp == null || mRoomInfoResp!!.room_auction == null) return + + mRoomInfoResp!!.room_auction.auction_user = text.auction_user + SpUtil.setAuctionId(text.auction_user.auction_id) + roomFragment!!.upRoomInfoData(mRoomInfoResp) + roomFragment!!.handleAuctionMessageEvent(messageEvent) + // roomFragment.updateSeatViewExchangedWithPitArray(mRoomInfoResp); + } + + private fun handleMsgType1024(messageEvent: RoomMessageEvent, text: T?) { + if (text == null || mRoomInfoResp == null || mRoomInfoResp!!.room_auction == null) return + if (mRoomInfoResp!!.room_auction.auction_list != null) { + mRoomInfoResp!!.room_auction.auction_list.clear() + } + if (mRoomInfoResp!!.room_auction.auction_list != null && text.auction_list != null) { + mRoomInfoResp!!.room_auction.auction_list.addAll(text.auction_list) + } else { + mRoomInfoResp!!.room_auction.auction_list = ArrayList() + // mRoomInfoResp.getRoom_auction().getAuction_list().addAll(text.getAuction_list()); + } + roomFragment!!.upRoomInfoData(mRoomInfoResp) + roomFragment!!.handleAuctionMessageEvent(messageEvent) + // roomFragment.updateSeatViewExchangedWithPitArray(mRoomInfoResp); + } + + private fun handleMsgType1020(messageEvent: RoomMessageEvent, text: T?) { + if (text == null) return + + mRoomBean = text.roomInfo + EventBus.getDefault().post(mRoomBean) + changeBackgroundColor(mRoomBean?.getRoom_background()) + } + + private fun handleMsgType1011(messageEvent: RoomMessageEvent, text: T?) { + if (text == null || text.fromUserInfo == null) return + + if (text.fromUserInfo.user_id == SpUtil.getUserId()) { + LogUtils.e("退出房间") + MvpPre!!.quitRoom(roomId, SpUtil.getUserId().toString() + "") + } + } + + private fun handleMsgType1001() { + number++ + mBinding!!.roomTop.tvNum.text = number.toString() + "" + } + + private fun handleMsgType1002() { + number-- + if (number < 0) { + number = 0 + } + mBinding!!.roomTop.tvNum.text = number.toString() + "" + } + + private fun handleMsgType1029(messageEvent: RoomMessageEvent, text: T?) { + if (text == null || mRoomInfoResp == null || mRoomInfoResp!!.user_info == null) return + + if (mRoomInfoResp!!.user_info.pit_number == 9 && mRoomInfoResp!!.user_info.user_id == SpUtil.getUserId() + .toString() + "" + ) { + querenPk(text.text, text.pkId) + } + } + + private fun handleMsgType1021(messageEvent: RoomMessageEvent, text: T) { + if (mRoomInfoResp == null || mRoomInfoResp!!.room_info == null) return + + val typeId = mRoomInfoResp!!.room_info.type_id + if ("2" == typeId) { + roomFragment!!.handleAuctionMessageEvent(messageEvent) + } else if ("1" == typeId || "4" == typeId || "3" == typeId || "8" == typeId) { + val labelId = mRoomInfoResp!!.room_info.label_id + if ("2" == labelId) { + roomFragment!!.KtvFragmentEvent(messageEvent) + } else { + updateCharmForAllPitBeans("") + roomFragment!!.upRoomInfoData(mRoomInfoResp) + roomFragment!!.SingSongEvent(messageEvent) + } + } else { + updateCharmForAllPitBeans("") + roomFragment!!.upFriendList(mRoomInfoResp!!.room_info.pit_list) + } + } + + private fun updateCharmForAllPitBeans(charm: String) { + if (mRoomInfoResp == null || mRoomInfoResp!!.room_info == null) return + + val pitList = mRoomInfoResp!!.room_info.pit_list ?: return + + for (roomPitBean in pitList) { + roomPitBean.charm = charm + try { + pitList[roomPitBean.pit_number.toInt() - 1] = roomPitBean + } catch (e: NumberFormatException) { + // Handle exception + } + } + } + + private fun handleMsgType1036(messageEvent: RoomMessageEvent, text: T?) { + if (text == null) return + + if (text.room_id == roomId) { + val onlineNumber = text.online_number.toString() + "" + if (mBinding!!.roomTop.tvNum.text.toString() != onlineNumber) { + mBinding!!.roomTop.tvNum.text = onlineNumber + } + } + } + + private fun handleMsgType1049(messageEvent: RoomMessageEvent, text: T?) { + if (text == null) return + + val endTime = if (text.end_time != null) text.end_time.toLong() else 0 + if (text.step != 3) { + roomFragment!!.updateFriendshipState(text.step, text.friend_id, endTime, null) + } else { + roomFragment!!.updateFriendshipState(text.step, text.friend_id, 0, text.friend_user) + } + } + + private fun handleMsgType1050(messageEvent: RoomMessageEvent, text: T?) { + if (text == null) return + + roomFragment!!.friendTimeDelayWithTime(text.end_time.toLong()) + } + + private fun handleMsgType1051(messageEvent: RoomMessageEvent, text: T?) { + if (text == null) return + + if (text.user1_id == null || text.user2_id == null) { + return + } + if (roomFragment != null) { + roomFragment!!.clearDialog() + } + val friend_user = getFriendUserBean(messageEvent) + FriendsDialogFragment.show(friend_user, supportFragmentManager) + + + if (text.user1_id == SpUtil.getUserId() + .toString() + "" || text.user2_id == SpUtil.getUserId().toString() + "" + ) { + if (roomSwitchRunnable != null) { + roomSwitchHandler.removeCallbacks(roomSwitchRunnable!!) + } + + pendingRoomId = text.room_id + if (pendingRoomId == null) { + return + } + LogUtils.e("需要加入的房间id:pendingRoomId: $pendingRoomId") + roomSwitchRunnable = Runnable { + if (!isFinishing && !isDestroyed) { + if (pendingRoomId != lastSwitchedRoomId) { + MvpPre!!.quitRoom2(messageEvent.roomId, SpUtil.getUserId().toString() + "") + quit() + MessageListenerSingleton.quitGroup(messageEvent.roomId) + MessageListenerSingleton.getInstance().joinGroup(pendingRoomId) + MvpPre!!.getRoomIn(pendingRoomId, "") + lastSwitchedRoomId = pendingRoomId!! + AgoraManager.getInstance(OkDownloadProvider.context).lastRoomId = + messageEvent.roomId +// RoomManager.getInstance().fetchRoomDataAndEnter(this,pendingRoomId, "") + } + } + pendingRoomId = null + } + + roomSwitchHandler.postDelayed(roomSwitchRunnable!!, 3000) + } + } + + //退出房间 + fun quitRoomAll(roomId: String?) { + MvpPre!!.quitRoom(roomId, SpUtil.getUserId().toString() + "") + } + + private fun handleMsgType1053(messageEvent: RoomMessageEvent, text: T?) { + if (text == null || text.list == null || text.list.isEmpty()) return + val pitArr: MutableList = ArrayList() + for (j in text.list.indices) { + val roomPitBean = getRoomPitBean(messageEvent, j) + pitArr.add(roomPitBean) + } + + roomFragment!!.friendSeatDidChanged(pitArr) + pitArr.clear() + } + + private fun handleMsgType1054(messageEvent: RoomMessageEvent, text: T?) { + if (text == null || text.list == null) return + + val heartList = text.list.stream() + .map { item: UserInfo -> + val heartList1 = HeartList() + heartList1.heartId = item.heartId + heartList1.heartNum = item.heartNum + heartList1 + } + .collect(Collectors.toList()) + + roomFragment!!.friendHeartNumberDidChanged(heartList) + } + + private fun handleMsgType1055(messageEvent: RoomMessageEvent) { + if (!isFinishing && !isDestroyed) { + MvpPre!!.quitRoom2(messageEvent.roomId, SpUtil.getUserId().toString() + "") + quit() + jiaR() + } + } + + private fun handleMsgType1035(messageEvent: RoomMessageEvent, text: T?) { + if (text == null || mRoomInfoResp == null || mRoomInfoResp!!.room_info == null) return + + val fromUserInfo = text.fromUserInfo ?: return + + val typeId = mRoomInfoResp!!.room_info.type_id + if ("2" == typeId) { + roomFragment!!.handleAuctionMessageEvent(messageEvent) + } else if ("1" == typeId || "3" == typeId || "4" == typeId || "8" == typeId) { + val labelId = mRoomInfoResp!!.room_info.label_id + if ("2" == labelId) { + roomFragment!!.KtvFragmentEvent(messageEvent) + } else { +// updatePitBeanForUser(fromUserInfo); + roomFragment!!.upRoomInfoData(updatePitBeanForUser(fromUserInfo)) + roomFragment!!.SingSongEvent(messageEvent) + } + } else { + roomFragment!!.upRoomInfoData(updatePitBeanForUser(fromUserInfo)) + roomFragment!!.friendshipRoomFragmentEvent(messageEvent) + } + } + + private fun updatePitBeanForUser(fromUserInfo: UserInfo): RoomInfoResp? { + if (mRoomInfoResp == null || mRoomInfoResp!!.room_info == null) return mRoomInfoResp + + val pitList = mRoomInfoResp!!.room_info.pit_list ?: return mRoomInfoResp + + for (pitBean in pitList) { + if (pitBean.user_id == fromUserInfo.user_id.toString() + "") { + pitBean.charm = fromUserInfo.charm + pitBean.avatar = fromUserInfo.avatar + pitBean.nickname = fromUserInfo.nickname + pitBean.sex = fromUserInfo.sex.toString() + "" + pitBean.dress = fromUserInfo.dress + } + } + return mRoomInfoResp + } + + private fun handleMsgType125(messageEvent: RoomMessageEvent, text: T?) { + if (text == null) return + + try { + val parsedText = GsonUtils.fromJson( + text.text, + text::class.java + ) + if (parsedText.is_mute == 1) { + AgoraManager.getInstance(this).ClientRole(false) + AgoraManager.getInstance(this).muteLocalAudioStreamEx(false, SpUtil.getUserId()) + } else { + AgoraManager.getInstance(this).ClientRole(true) + AgoraManager.getInstance(this).muteLocalAudioStreamEx(true, SpUtil.getUserId()) + } + } catch (e: Exception) { + // Handle exception + } + } + + private fun handleMsgType1007() { + if (mRoomInfoResp != null && mRoomInfoResp!!.user_info != null) { + mRoomInfoResp!!.user_info.is_host = 1 + roomFragment!!.upRoomInfoData(mRoomInfoResp) + // roomFragment.updateSeatViewExchangedWithPitArray(mRoomInfoResp); + } + } + + private fun handleMsgType1006() { + if (mRoomInfoResp != null && mRoomInfoResp!!.user_info != null) { + mRoomInfoResp!!.user_info.is_management = 1 + roomFragment!!.upRoomInfoData(mRoomInfoResp) + } + } + + private fun handleMsgType1018() { + if (mRoomInfoResp != null && mRoomInfoResp!!.user_info != null) { + mRoomInfoResp!!.user_info.is_host = 0 + roomFragment!!.upRoomInfoData(mRoomInfoResp) + // roomFragment.updateSeatViewExchangedWithPitArray(mRoomInfoResp); + } + } + + private fun handleMsgType1017() { + if (mRoomInfoResp != null && mRoomInfoResp!!.user_info != null) { + mRoomInfoResp!!.user_info.is_management = 0 + roomFragment!!.upRoomInfoData(mRoomInfoResp) + } + } + + private fun handleMsgType126(messageEvent: RoomMessageEvent, text: T?) { + if (text == null) return + + AgoraManager.getInstance(this) + .setLocalAudioEnabled(false, text.fromUserInfo.user_id.toString() + "") + } + + private fun handleMsgType1034(messageEvent: RoomMessageEvent, text: T?) { + if (text == null) return + + val count = text.count + if (count == 0) { + tvFirst(SpannableStringBuilder("0人排队")) + return + } + + val countText = count.toString() + val fullText = countText + "人排队" + + val spannableStringBuilder = SpannableStringBuilder(fullText) + spannableStringBuilder.setSpan( + ForegroundColorSpan( + ContextCompat.getColor( + this, + com.xscm.moduleutil.R.color.color_C7BF62 + ) + ), + 0, + countText.length, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + tvFirst(spannableStringBuilder) + } + + private fun handleMsgType1016(messageEvent: RoomMessageEvent, text: T?) { + if (text == null || mRoomInfoResp == null || mRoomInfoResp!!.user_info == null) return + + if (text.fromUserInfo.user_id == SpUtil.getUserId()) { + if (text.is_mute_pit == 1) { + switchMic(2) + } + mRoomInfoResp!!.user_info.is_mute_pit = text.is_mute_pit.toString() + mRoomInfoResp!!.user_info.is_mute = text.is_mute.toString() + } + } + + // TODO: 2025/6/30 上麦,麦位变化 + private fun getPitBean(messageEvent: RoomMessageEvent): RoomPitBean { + val pitBean = RoomPitBean() + pitBean.pit_number = messageEvent.text.pit_number + pitBean.user_id = messageEvent.text.fromUserInfo.user_id.toString() + "" + pitBean.avatar = messageEvent.text.fromUserInfo.avatar + pitBean.nickname = messageEvent.text.fromUserInfo.nickname + pitBean.sex = messageEvent.text.fromUserInfo.sex.toString() + "" + pitBean.charm = messageEvent.text.fromUserInfo.charm + + return pitBean + } + + // TODO: 2025/6/30 下麦麦位变化 + private fun getPitBean2(messageEvent: RoomMessageEvent?, number: String): RoomPitBean { + val pitBean = RoomPitBean() + pitBean.pit_number = if (messageEvent != null) messageEvent.text.pit_number else number + pitBean.user_id = "" + pitBean.avatar = "" + pitBean.nickname = "" + pitBean.sex = "" + pitBean.charm = "" + pitBean.is_pm = 1 + return pitBean + } + + // TODO: 2025/8/29 排麦位上麦 + private fun getPitBean3(messageEvent: RoomMessageEvent): AuctionUserBean { + val roomAuction = AuctionUserBean() + roomAuction.user_id = messageEvent.text.fromUserInfo.user_id.toString() + "" + roomAuction.avatar = messageEvent.text.fromUserInfo.avatar + roomAuction.nickname = messageEvent.text.fromUserInfo.nickname + roomAuction.sex = messageEvent.text.fromUserInfo.sex.toString() + "" + roomAuction.charm = messageEvent.text.fromUserInfo.charm + + return roomAuction + } + + fun mus() { + if (mRoomInfoResp!!.user_info.is_mute == "1") { + ToastUtils.show("您已经被禁言") + } else { + switchMic(1) + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onMessageEvent(messageEvent: UnreadCountEvent) { + if (messageEvent.aLong == 0L) { + mBinding!!.ivMessageDot.visibility = View.GONE + } else { + mBinding!!.ivMessageDot.visibility = View.VISIBLE + mBinding!!.ivMessageDot.text = messageEvent.aLong.toString() + } + } + + private fun querenPk(text: String, pk_id: String) { + // 创建并显示确认对话框 + val dialog = ConfirmDialog( + this, + "温馨提示", + text, + "确认", + "拒绝", + { v: View? -> + // 点击“确认”按钮时执行删除操作 + MvpPre!!.acceptPk(pk_id, "1") + }, + { v: View? -> + MvpPre!!.acceptPk(pk_id, "2") + }, true, 10 + ) + dialog.show() + addActiveDialog(dialog) + } + + /** + * 修改背景图 + * + * @param bjId + */ + fun changeBackgroundColor(bjId: String?) { + // 假设你的Activity有一个根布局,例如 ConstraintLayout + ImageUtils.loadImageWithCache(this, bjId, mBinding!!.ivBg) + } + + fun changeBackground(bjId: Int) { + mBinding!!.ivBg.setImageDrawable(resources.getDrawable(bjId)) + } + + fun setvisibTop(`is`: Boolean) { + mBinding!!.roomTop.root.visibility = + if (`is`) View.VISIBLE else View.GONE + } + + fun setDiany(`is`: Boolean) { +// mBinding.flaoat.setVisibility(is? VISIBLE : GONE); + } + + fun setOnlineNumber(number: Int) { + mBinding!!.roomTop.tvNum.text = number.toString() + "" + } + + fun setUserInfo() { + mRoomInfoResp!!.user_info.is_collect = 1 + mBinding!!.roomTop.btnFollow.background = + resources.getDrawable(com.xscm.moduleutil.R.mipmap.yishouc) + mBinding!!.roomTop.btnFollow.text = "" + } + + /** + * 特效设置 + */ + @Subscribe(threadMode = ThreadMode.MAIN) + fun setEffectSwitch(event: EffectEvent) { + if (event.isEffectOn) { //特效开启 + QXGiftPlayerManager.getInstance(this).openOrCloseEffectViewWith(true) + mBinding!!.svgaGift.visibility = View.VISIBLE + } else { +// mBinding.svgaGift.closeEffect(); +// mBinding.svgaGift.closeEffect(); + QXGiftPlayerManager.getInstance(this).openOrCloseEffectViewWith(false) + mBinding!!.svgaGift.visibility = View.GONE + } + } + + /** + * 坐骑进场特效 + * + * @param roomJoinMountModel + */ + @Subscribe(threadMode = ThreadMode.MAIN) + fun roomJoinMount(roomJoinMountModel: RoomJoinMountModel) { + if (roomId != roomJoinMountModel.room_id) { + return + } + if (roomJoinMountModel.show_type != 1) { + val gift = GiftBean() + gift.gift_id = "" + gift.play_image = roomJoinMountModel.ride_url + QXGiftPlayerManager.getInstance(this).displayFullEffectView(roomJoinMountModel.ride_url) + // mBinding.svgaZuoji.setSource(roomJoinMountModel.getRide_url(), 2); + } + } + + private var isSwith = false + private var voive = false //声音开关 + private var canSend = true + private var aBoolean = true //上下麦按钮 + private var mCountDownTimer: CountDownTimer? = null + private var mCountDownTimer2: CountDownTimer? = null + + private fun onClick(view: View) { + val id = view.id + if (id == R.id.btn_follow) { + MvpPre!!.userGuanz(mRoomInfoResp!!.room_info.room_id, "2") + } else if (id == R.id.btn_notice) { +// RoomTipsView.show(this,view,"公告","公告内容"); + val roomNoticeDialogFragment = RoomNoticeDialogFragment(this) + roomNoticeDialogFragment.setTitle("公告") + roomNoticeDialogFragment.setContent(mRoomBean!!.room_intro) + roomNoticeDialogFragment.show() + addActiveDialog(roomNoticeDialogFragment) + } else if (id == R.id.btn_ranking) { //排行榜 +// RoomChartsFragment.newInstance(roomId).show(getSupportFragmentManager(), "RoomChartsFragment"); + val fragment = RoomChartsFragment.newInstance(roomId, mRoomInfoResp) + fragment.show(supportFragmentManager, "RoomChartsFragment") + addActiveDialogFragment(fragment) + } else if (id == R.id.btn_close_live) { //退出房间 + showExitRoomDialog() + } else if (id == R.id.tv_num) { +// RoomOnlineDialogFragment.show(roomId, "", mRoomUserBean, mRoomInfoResp, getSupportFragmentManager()); + val fragment = RoomOnlineDialogFragment.show( + roomId, "", mRoomUserBean, mRoomInfoResp, + supportFragmentManager + ) + if (fragment != null) { + addActiveDialogFragment(fragment) // 添加到管理列表 + } + } else if (id == R.id.rl) { + MvpPre!!.clearUserCharm(roomId, "") + } else if (id == R.id.ll_input) { + mBinding!!.llInput.visibility = View.GONE + mBinding!!.inputMenu1.dismiss() + }else if (id==R.id.iv_emoji){ + val emotionPickerDialog = EmotionPickerDialog(this) + emotionPickerDialog.setOnEmotionSelectedListener { emotion -> + // 处理选中的表情 + if (publicScreenFragment!=null){ + publicScreenFragment!!.sendChatEmoji(emotion) + } + } + emotionPickerDialog.show() + } + else if (id == R.id.iv_chat) { + if (mRoomInfoResp!!.user_info.is_mute == "1") { + ToastUtils.show("您已经被禁言") + } else { + // mBinding.llInput.setVisibility(View.VISIBLE); +// mBinding.inputMenu1.bringToFront(); // 强制将该 View 置于最上层 +// mBinding.inputMenu1.show(); + + dialogDismiss(1) + } + } else if (id == R.id.rl_mic) { + if (mRoomInfoResp!!.user_info.is_mute_pit != null && mRoomInfoResp!!.user_info.is_mute_pit == "1") { + ToastUtils.show("您被禁麦了") + } else { + if (isSwith) { + switchMic(1) + } else { + switchMic(2) + } + } + } else if (id == R.id.rl_sett) { //房间设置 +// RoomSettingFragment.show(mRoomInfoResp, getSupportFragmentManager()); + if (mRoomInfoResp == null) { + com.blankj.utilcode.util.ToastUtils.showShort("请稍后再试") + return + } + val fragment = RoomSettingFragment.show( + mRoomInfoResp, + supportFragmentManager + ) + if (fragment != null) { + addActiveDialogFragment(fragment) // 添加到管理列表 + } + } else if (id == R.id.rl_voive) { + if (voive) { + mBinding!!.imVoive.setImageResource(com.xscm.moduleutil.R.mipmap.room_voice_g) + voive = false + } else { + mBinding!!.imVoive.setImageResource(com.xscm.moduleutil.R.mipmap.room_voice_kg) + voive = true + } + AgoraManager.getInstance(this).muteSpeaker(!voive) + } else if (id == R.id.rl_more) { //点击PK +// RoomPkDialogFragment.newInstance(roomId, SpUtil.getUserId() + "", mRoomInfoResp.getRoom_info().getIs_pk()).show(getSupportFragmentManager(), "RoomPkDialogFragment"); + val fragment = RoomPkDialogFragment.newInstance( + roomId, + SpUtil.getUserId().toString() + "", + mRoomInfoResp!!.room_info.is_pk + ) + fragment.show(supportFragmentManager, "RoomPkDialogFragment") + addActiveDialogFragment(fragment) // 添加到管理列表 + } else if (id == R.id.rl_message) { +// RoomMessageDialogFragment.show(getSupportFragmentManager()); + val fragment = RoomMessageDialogFragment.show( + supportFragmentManager + ) + if (fragment != null) { + addActiveDialogFragment(fragment) // 添加到管理列表 + } + } else if (id == R.id.rl_misc) { //设置点歌 + if (mRoomInfoResp!!.room_info.label_id == "1") { + queren() + } else { +// RequestDialogFragment.show(roomId, mRoomInfoResp, 1, getSupportFragmentManager()); + val fragment = RequestDialogFragment.show( + roomId, mRoomInfoResp, 1, + supportFragmentManager + ) + if (fragment != null) { + addActiveDialogFragment(fragment) // 添加到管理列表 + } + } + } else if (id == R.id.rl_gift) { //礼物 +// RoomGiftDialogFragment.show(mRoomInfoResp, null, roomId, 0, "", getSupportFragmentManager()); + val fragment = RoomGiftDialogFragment.show( + mRoomInfoResp, null, roomId, 0, "", + supportFragmentManager + ) + if (fragment != null) { + addActiveDialogFragment(fragment) // 添加到管理列表 + } + } else if (id == R.id.iv_sound_effects) { +// SoundEffectsDialogFragment.show(roomId, getSupportFragmentManager()); + val fragment = SoundEffectsDialogFragment.show( + roomId, + supportFragmentManager + ) + if (fragment != null) { + addActiveDialogFragment(fragment) // 添加到管理列表 + } + } else if (id == R.id.cl_first_charge) { +// showWheatFeedingDialog(roomId, (mRoomInfoResp.getUser_info().getIs_room_owner() == 1 || mRoomInfoResp.getUser_info().getIs_host() == 1 || mRoomInfoResp.getUser_info().getIs_management() == 1) ? 1 : 2); + roomFragment!!.showWheatFeedingDialog( + roomId, + if ((mRoomInfoResp!!.user_info.is_room_owner == 1 || mRoomInfoResp!!.user_info.is_host == 1 || mRoomInfoResp!!.user_info.is_management == 1)) 1 else 2 + ) + } else if (id == R.id.iv_wheat_feeding) { //点击上麦操作 + if (mRoomInfoResp!!.room_info.room_up_pit_type == "1") { +// showWheatFeedingDialog(roomId, mRoomInfoResp.getUser_info().getPit_number() == 9 ? 1 : 2); + if (aBoolean) { + MvpPre!!.applyPit(roomId, "") + // aBoolean = false; + } else { + MvpPre!!.downPit(roomId, "") + // aBoolean = true; + } + } else { + if (aBoolean) { +// mBinding.ivWheatFeeding.setImageResource(com.xscm.moduleutil.R.mipmap.room_wheat_feeding_up); + MvpPre!!.applyPit(roomId, "") + aBoolean = false + } else { +// mBinding.ivWheatFeeding.setImageResource(com.xscm.moduleutil.R.mipmap.room_wheat_feeding); + MvpPre!!.downPit(roomId, "") + aBoolean = true + } + } + } + } + + // TODO: 2025/9/18 type==1:退出房间,进入到首页 2:退出当前页,不导航到首页,是从首页点击关闭悬浮退出的 + fun performExitRoom(type: Int) { + // 清理最小化状态 + clearMinimizeState() + isMinimized = false + + // 执行退出房间逻辑 + CommonAppContext.getInstance().isPlaying = false + CommonAppContext.getInstance().isShow = false + QXGiftPlayerManager.getInstance(this).destroyEffectSvga() + // 停止屏幕捕获和其他资源 +// AgoraManager.getInstance(this).stopScreenCapture(); +// AgoraManager.getInstance(this).leaveRoom(); +// AgoraManager.getInstance(this).stopMusicPlayer(); + AgoraManager.getInstance(this).cleanup() + + MyRoomSingleton.getInstance().onExitRoom() + MessageListenerSingleton.quitGroup(roomId) + // 清理ViewModel中的数据 +// if (sharedViewModel != null) { +// sharedViewModel.clearAllData(); +// } + RoomManager.getInstance().exitRoom(roomId) + // 清理资源 + cleanupResources() + if (type == 1) { + // 导航到首页 + navigateToMainPage() + } else if (type == 2) { + // 返回上一个页面 + finish() + } + + finish() + } + + private val isAppInForeground: Boolean + // 添加前后台状态检测 + get() { + if (mRoomInfoResp == null) { + return true + } + if (mRoomInfoResp!!.room_info.label_id != "6") { + val activityManager = + getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + val appProcesses = + activityManager.runningAppProcesses ?: return false + + val packageName = packageName + for (appProcess in appProcesses) { + if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND + && appProcess.processName == packageName + ) { + return true + } + } + } else { + return true + } + return false + } + + private fun navigateToMainPage() { + ARouter.getInstance() + .build(ARouteConstants.ME) + .navigation() + + // 添加转场动画 + overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out) + } + + private fun quitUpRoom() { + // 清理最小化状态 + clearMinimizeState() + isMinimized = false + + // 执行退出房间逻辑 + CommonAppContext.getInstance().isPlaying = false + CommonAppContext.getInstance().isShow = false + CommonAppContext.getInstance().playId = null + QXGiftPlayerManager.getInstance(this).destroyEffectSvga() + // 停止屏幕捕获和其他资源 +// AgoraManager.getInstance(this).stopScreenCapture(); + AgoraManager.getInstance(this).leaveRoom() + // AgoraManager.getInstance(this).stopMusicPlayer(); + AgoraManager.getInstance(this).cleanup() + + MyRoomSingleton.getInstance().onExitRoom() + MessageListenerSingleton.quitGroup(roomId) + cleanupResources() + } + + private fun minimizeToBackground() { + isMinimized = true + // 保存最小化状态和房间ID + saveMinimizeState() + // 设置应用状态 + CommonAppContext.getInstance().isShow = false + // 通知状态管理器RoomActivity已最小化 + if (appStateListener != null) { + appStateListener!!.isAppInBackground = true + } + QXGiftPlayerManager.getInstance(applicationContext).destroyEffectSvga() + + ARouter.getInstance() + .build(ARouteConstants.ME) + .navigation() + + // ARouter.getInstance().build(ARouteConstants.ME) +// .addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP) +// .navigation(); + + // 使用Intent启动主Activity,通过ARouter路径 + // 这样可以避免模块间的直接依赖 +// try { +// val intent = Intent() +// intent.setClassName(packageName, "com.xscm.modulemain.activity.MainActivity") +// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP) +// startActivity(intent) +// } catch (e: Exception) { +// // 如果直接指定类名失败,则使用默认的Launcher Activity +// val startMain = Intent(Intent.ACTION_MAIN) +// startMain.addCategory(Intent.CATEGORY_HOME) +// startMain.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) +// startActivity(startMain) +// } + + // 隐藏Activity而不是销毁它 +// moveTaskToBack(true); + // 使用 moveTaskToBack 将应用最小化 +// moveTaskToBack(true); + } + + private fun saveMinimizeState() { + val prefs = getSharedPreferences("room_minimize_state", Context.MODE_PRIVATE) + val editor = prefs.edit() + editor.putString(PREF_MINIMIZED_ROOM, roomId) + editor.putLong(PREF_MINIMIZED_TIME, System.currentTimeMillis()) + editor.putBoolean("is_minimized", true) + editor.apply() + } + + private fun clearMinimizeState() { + val prefs = getSharedPreferences("room_minimize_state", Context.MODE_PRIVATE) + val editor = prefs.edit() + editor.remove(PREF_MINIMIZED_ROOM) + editor.remove(PREF_MINIMIZED_TIME) + editor.putBoolean("is_minimized", false) + editor.apply() + } + + private fun wasMinimized(): Boolean { + val prefs = getSharedPreferences("room_minimize_state", Context.MODE_PRIVATE) + return prefs.getBoolean("is_minimized", false) + } + + private fun queren() { + // 创建并显示确认对话框 + val dialog = ConfirmDialog( + this, + "提示", + "您将要发起点歌申请?", + "确认", + "取消", + { v: View? -> + // 点击“确认”按钮时执行删除操作 + MvpPre!!.applySong(roomId) + }, + { v: View? -> }, false, 0 + ) + dialog.show() + addActiveDialog(dialog) + } + + /** + * 设置是否打开麦克风 + * + * @param type + */ + // @Override + fun switchMic(type: Int) { + if (type == 1) { + mBinding!!.ivMic.setImageResource(com.xscm.moduleutil.R.mipmap.room_microphone) + AgoraManager.getInstance(this) + .setLocalAudioEnabled(true, SpUtil.getUserId().toString() + "") + isSwith = false + AgoraManager.getInstance(this).muteLocalAudioStream(false) + AgoraManager.getInstance(this).ClientRole(true) + CommonAppContext.getInstance().isMai = true + } else { + mBinding!!.ivMic.setImageResource(com.xscm.moduleutil.R.mipmap.room_microphone_off) + AgoraManager.getInstance(this) + .setLocalAudioEnabled(false, SpUtil.getUserId().toString() + "") + isSwith = true + isMute(1) + CommonAppContext.getInstance().isMai = false + } + } + + /** 进入小黑屋将所有的底部隐藏 */ + fun setviewyc(voive: Boolean) { + mBinding!!.rlMore.visibility = + if (voive) View.GONE else View.GONE + mBinding!!.rlMisc.visibility = + if (voive) View.GONE else View.GONE + mBinding!!.rlMic.visibility = + if (voive) View.VISIBLE else View.GONE + mBinding!!.rlSett.visibility = + if (voive) View.VISIBLE else View.GONE + mBinding!!.rlVoive.visibility = + if (voive) View.VISIBLE else View.GONE + mBinding!!.rlGift.visibility = + if (voive) View.VISIBLE else View.GONE + mBinding!!.ivSoundEffects.visibility = + if (voive) View.VISIBLE else View.GONE + mBinding!!.ivWheatFeeding.visibility = + if (voive) View.VISIBLE else View.GONE + mBinding!!.clFirstCharge.visibility = + if (voive) View.VISIBLE else View.GONE + } + + /** 这里是当进入电影放房的时候,如果是排麦模式,并且不是电影放的时候,就隐藏排麦视图 */ + fun clFirstCharge(voive: Boolean) { + mBinding!!.clFirstCharge.visibility = + if (voive) View.VISIBLE else View.GONE + } + + fun ivWheatFeeding(id: Int) { + mBinding!!.ivWheatFeeding.setImageResource(id) + } + + fun setBoolean(voive: Boolean) { + this.aBoolean = voive + } + + fun ivSoundEffects(voive: Boolean) { + mBinding!!.ivSoundEffects.visibility = + if (voive) View.VISIBLE else View.GONE + } + + fun tvFirst(s: SpannableStringBuilder?) { + mBinding!!.tvFirst.text = s + } + + fun setrlMic(voive: Boolean) { + mBinding!!.rlMic.visibility = + if (voive) View.VISIBLE else View.GONE + } + + fun rlMore(voive: Boolean) { + mBinding!!.rlMore.visibility = if (voive) View.GONE else View.GONE + } + + fun ivMic(inIvMic: Int) { + mBinding!!.ivMic.setImageResource(inIvMic) + } + + fun setRoleType(roleType: Int, pit_number: Int) { + val rl_voice = mBinding!!.rlVoive // 注意:原拼写错误已修正 + val rl_mic = mBinding!!.rlMic + val rl_more = mBinding!!.rlMore + val rl_misc = mBinding!!.rlMisc + + // 默认隐藏所有按钮 + rl_voice.visibility = View.GONE + rl_more.visibility = View.GONE + rl_misc.visibility = View.GONE + rl_mic.visibility = View.GONE + + // 空指针保护 + if (mRoomInfoResp == null || mRoomInfoResp!!.room_info == null || mRoomInfoResp!!.user_info == null) { + return + } + + val typeId = mRoomInfoResp!!.room_info.type_id + val labelId = mRoomInfoResp!!.room_info.label_id + val userPitNumber = mRoomInfoResp!!.user_info.pit_number + + // 特殊房间类型处理(优先级最高) + if ("6" == typeId) { + mBinding!!.rlMessage.visibility = View.GONE + return // 全部隐藏,无需继续处理 + } + + + // 根据角色类型显示按钮 + when (roleType) { + 1, 2, 3 -> { + rl_voice.visibility = View.VISIBLE + rl_mic.visibility = + if (pit_number != 0) View.VISIBLE else View.GONE + rl_more.visibility = + if (pit_number == 9) View.GONE else View.GONE + rl_misc.visibility = View.VISIBLE + } + + 0 -> { + rl_voice.visibility = View.VISIBLE + rl_mic.visibility = + if (pit_number != 0) View.VISIBLE else View.GONE + rl_misc.visibility = View.VISIBLE + } + + 5 -> { + rl_voice.visibility = View.VISIBLE + rl_more.visibility = View.GONE + rl_misc.visibility = View.VISIBLE + } + + else -> {} + } + if (roleType != 5) { + rl_misc.visibility = View.VISIBLE + if (userPitNumber == 9) { + rl_more.visibility = View.GONE + } + } + + + // label_id 和 type_id 联合判断 + if (mutableListOf("1", "3", "4", "8").contains(typeId) && "2" == labelId) { + rl_more.visibility = View.GONE + } + + // mic 显示逻辑 + if (userPitNumber > 0) { + rl_mic.visibility = View.VISIBLE + switchMic(2) + } else { + if (pit_number == 888) { + rl_mic.visibility = View.VISIBLE + switchMic(2) + } else if (pit_number == -1) { + rl_mic.visibility = View.VISIBLE // 原代码此处缺少 View. 前缀,已补全 + switchMic(1) + } else { + rl_mic.visibility = View.GONE + switchMic(2) + } + } + + if ("7" == typeId || "2" == typeId) { + rl_more.visibility = View.GONE + rl_misc.visibility = View.GONE + } + } + + fun isMute(is_mute: Int) { + val text = text() + text.is_mute = is_mute + val s = GsonUtils.toJson(text) + val t = T() + t.fromUserInfo = SpUtil.getUserInfo() + t.text = s + val roomMessageEvent = RoomMessageEvent(126, mRoomInfoResp!!.room_info.room_id, t) + val json = GsonUtils.toJson(roomMessageEvent) + // 转换为 byte[] + val binaryData = json.toByteArray(StandardCharsets.UTF_8) + // 创建自定义消息 + MessageListenerSingleton.getInstance().sendCustomRoomMessage( + roomId + "", + binaryData + ) + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun roomInfoEvent(messageEvent: RoomWheatEvent) { + if (messageEvent.roomId == roomId) { + if (messageEvent.isOccupied) { + mBinding!!.ivWheatFeeding.setImageResource(com.xscm.moduleutil.R.mipmap.room_wheat_feeding_up) + aBoolean = false + } else { + mBinding!!.ivWheatFeeding.setImageResource(com.xscm.moduleutil.R.mipmap.room_wheat_feeding) + aBoolean = true + } + } + } + + @SuppressLint("MissingInflatedId") + fun dialogDismiss(type:Int) { + // // 使用 AlertDialog.Builder + + val builder = AlertDialog.Builder(this) + val inflater = layoutInflater + val dialogView = + inflater.inflate(com.xscm.moduleutil.R.layout.room_message_input_menu, null) + builder.setView(dialogView) + val etContent = dialogView.findViewById(com.xscm.moduleutil.R.id.et_content) + val tvSend = dialogView.findViewById